From d946cb37f24036ccdaf8c60f7c653dddedc382e4 Mon Sep 17 00:00:00 2001 From: AZero13 <83477269+AZero13@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:32:50 -0400 Subject: [PATCH] Split script to script_vm and script Move gNullScriptPtr to the script_vm file. --- ld_script.ld | 2 + src/scrcmd.c | 4 -- src/script.c | 157 +----------------------------------------------- src/script_vm.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 160 deletions(-) create mode 100644 src/script_vm.c diff --git a/ld_script.ld b/ld_script.ld index aeaf0825027a..19a30025d2b5 100644 --- a/ld_script.ld +++ b/ld_script.ld @@ -125,6 +125,7 @@ SECTIONS { src/field_message_box.o(.text); src/event_object_lock.o(.text); src/text_window.o(.text); + src/script_vm.o(.text); src/script.o(.text); src/scrcmd.o(.text); src/field_control_avatar.o(.text); @@ -509,6 +510,7 @@ SECTIONS { src/field_player_avatar.o(.rodata); src/event_object_movement.o(.rodata); src/text_window.o(.rodata); + src/script_vm.o(.rodata); src/scrcmd.o(.rodata); src/field_control_avatar.o(.rodata); src/coord_event_weather.o(.rodata); diff --git a/src/scrcmd.c b/src/scrcmd.c index 9c75a625cc62..d119a56aadb1 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -70,10 +70,6 @@ extern const u8 *gStdScripts_End[]; static void CloseBrailleWindow(void); -// This is defined in here so the optimizer can't see its value when compiling -// script.c. -void *const gNullScriptPtr = NULL; - static const u8 sScriptConditionTable[COMPARISON_OPERATORS_COUNT][3] = { // < = > diff --git a/src/script.c b/src/script.c index a953ff1e75fc..d9354123e0c9 100644 --- a/src/script.c +++ b/src/script.c @@ -8,11 +8,7 @@ #define RAM_SCRIPT_MAGIC 51 -enum { - SCRIPT_MODE_STOPPED, - SCRIPT_MODE_BYTECODE, - SCRIPT_MODE_NATIVE, -}; +extern const u8 *gRamScriptRetAddr; enum { CONTEXT_RUNNING, @@ -20,8 +16,6 @@ enum { CONTEXT_SHUTDOWN, }; -extern const u8 *gRamScriptRetAddr; - static u8 sGlobalScriptContextStatus; static struct ScriptContext sGlobalScriptContext; static struct ScriptContext sImmediateScriptContext; @@ -29,155 +23,6 @@ static bool8 sLockFieldControls; extern ScrCmdFunc gScriptCmdTable[]; extern ScrCmdFunc gScriptCmdTableEnd[]; -extern void *const gNullScriptPtr; - -void InitScriptContext(struct ScriptContext *ctx, void *cmdTable, void *cmdTableEnd) -{ - s32 i; - - ctx->mode = SCRIPT_MODE_STOPPED; - ctx->scriptPtr = NULL; - ctx->stackDepth = 0; - ctx->nativePtr = NULL; - ctx->cmdTable = cmdTable; - ctx->cmdTableEnd = cmdTableEnd; - - for (i = 0; i < (int)ARRAY_COUNT(ctx->data); i++) - ctx->data[i] = 0; - - for (i = 0; i < (int)ARRAY_COUNT(ctx->stack); i++) - ctx->stack[i] = NULL; -} - -u8 SetupBytecodeScript(struct ScriptContext *ctx, const u8 *ptr) -{ - ctx->scriptPtr = ptr; - ctx->mode = SCRIPT_MODE_BYTECODE; - return 1; -} - -void SetupNativeScript(struct ScriptContext *ctx, bool8 (*ptr)(void)) -{ - ctx->mode = SCRIPT_MODE_NATIVE; - ctx->nativePtr = ptr; -} - -void StopScript(struct ScriptContext *ctx) -{ - ctx->mode = SCRIPT_MODE_STOPPED; - ctx->scriptPtr = NULL; -} - -bool8 RunScriptCommand(struct ScriptContext *ctx) -{ - if (ctx->mode == SCRIPT_MODE_STOPPED) - return FALSE; - - switch (ctx->mode) - { - case SCRIPT_MODE_STOPPED: - return FALSE; - case SCRIPT_MODE_NATIVE: - // Try to call a function in C - // Continue to bytecode if no function or it returns TRUE - if (ctx->nativePtr) - { - if (ctx->nativePtr() == TRUE) - ctx->mode = SCRIPT_MODE_BYTECODE; - return TRUE; - } - ctx->mode = SCRIPT_MODE_BYTECODE; - // fallthrough - case SCRIPT_MODE_BYTECODE: - while (1) - { - u8 cmdCode; - ScrCmdFunc *func; - - if (!ctx->scriptPtr) - { - ctx->mode = SCRIPT_MODE_STOPPED; - return FALSE; - } - - if (ctx->scriptPtr == gNullScriptPtr) - { - while (1) - asm("svc 2"); // HALT - } - - cmdCode = *(ctx->scriptPtr); - ctx->scriptPtr++; - func = &ctx->cmdTable[cmdCode]; - - if (func >= ctx->cmdTableEnd) - { - ctx->mode = SCRIPT_MODE_STOPPED; - return FALSE; - } - - if ((*func)(ctx) == TRUE) - return TRUE; - } - } - - return TRUE; -} - -static bool8 ScriptPush(struct ScriptContext *ctx, const u8 *ptr) -{ - if (ctx->stackDepth + 1 >= (int)ARRAY_COUNT(ctx->stack)) - { - return TRUE; - } - else - { - ctx->stack[ctx->stackDepth] = ptr; - ctx->stackDepth++; - return FALSE; - } -} - -static const u8 *ScriptPop(struct ScriptContext *ctx) -{ - if (ctx->stackDepth == 0) - return NULL; - - ctx->stackDepth--; - return ctx->stack[ctx->stackDepth]; -} - -void ScriptJump(struct ScriptContext *ctx, const u8 *ptr) -{ - ctx->scriptPtr = ptr; -} - -void ScriptCall(struct ScriptContext *ctx, const u8 *ptr) -{ - ScriptPush(ctx, ctx->scriptPtr); - ctx->scriptPtr = ptr; -} - -void ScriptReturn(struct ScriptContext *ctx) -{ - ctx->scriptPtr = ScriptPop(ctx); -} - -u16 ScriptReadHalfword(struct ScriptContext *ctx) -{ - u16 value = *(ctx->scriptPtr++); - value |= *(ctx->scriptPtr++) << 8; - return value; -} - -u32 ScriptReadWord(struct ScriptContext *ctx) -{ - u32 value0 = *(ctx->scriptPtr++); - u32 value1 = *(ctx->scriptPtr++); - u32 value2 = *(ctx->scriptPtr++); - u32 value3 = *(ctx->scriptPtr++); - return (((((value3 << 8) + value2) << 8) + value1) << 8) + value0; -} void LockPlayerFieldControls(void) { diff --git a/src/script_vm.c b/src/script_vm.c new file mode 100644 index 000000000000..efb88d0d99f4 --- /dev/null +++ b/src/script_vm.c @@ -0,0 +1,156 @@ +#include "global.h" +#include "script.h" + +enum { + SCRIPT_MODE_STOPPED, + SCRIPT_MODE_BYTECODE, + SCRIPT_MODE_NATIVE, +}; + +extern ScrCmdFunc gScriptCmdTable[]; +extern ScrCmdFunc gScriptCmdTableEnd[]; + +// Has to be u32, otherwise agbcc will optimize the null check out and it won't match. +const u32 gNullScriptPtr = 0; + +void InitScriptContext(struct ScriptContext *ctx, void *cmdTable, void *cmdTableEnd) +{ + s32 i; + + ctx->mode = SCRIPT_MODE_STOPPED; + ctx->scriptPtr = NULL; + ctx->stackDepth = 0; + ctx->nativePtr = NULL; + ctx->cmdTable = cmdTable; + ctx->cmdTableEnd = cmdTableEnd; + + for (i = 0; i < (int)ARRAY_COUNT(ctx->data); i++) + ctx->data[i] = 0; + + for (i = 0; i < (int)ARRAY_COUNT(ctx->stack); i++) + ctx->stack[i] = NULL; +} + +u8 SetupBytecodeScript(struct ScriptContext *ctx, const u8 *ptr) +{ + ctx->scriptPtr = ptr; + ctx->mode = SCRIPT_MODE_BYTECODE; + return 1; +} + +void SetupNativeScript(struct ScriptContext *ctx, bool8 (*ptr)(void)) +{ + ctx->mode = SCRIPT_MODE_NATIVE; + ctx->nativePtr = ptr; +} + +void StopScript(struct ScriptContext *ctx) +{ + ctx->mode = SCRIPT_MODE_STOPPED; + ctx->scriptPtr = NULL; +} + +bool8 RunScriptCommand(struct ScriptContext *ctx) +{ + if (ctx->mode == SCRIPT_MODE_STOPPED) + return FALSE; + + switch (ctx->mode) + { + case SCRIPT_MODE_STOPPED: + return FALSE; + case SCRIPT_MODE_NATIVE: + // Try to call a function in C + // Continue to bytecode if no function or it returns TRUE + if (ctx->nativePtr) + { + if (ctx->nativePtr() == TRUE) + ctx->mode = SCRIPT_MODE_BYTECODE; + return TRUE; + } + ctx->mode = SCRIPT_MODE_BYTECODE; + // fallthrough + case SCRIPT_MODE_BYTECODE: + while (1) + { + u8 cmdCode; + if (!ctx->scriptPtr) + { + ctx->mode = SCRIPT_MODE_STOPPED; + return FALSE; + } + + // Redundant, and needed to match, though one could change gNullScriptPtr if they need a + // script debug breakpoint + if (ctx->scriptPtr == (const u8 *)gNullScriptPtr) + { + while (1) + asm("svc 2"); // HALT + } + + cmdCode = *(ctx->scriptPtr++); + + if (&ctx->cmdTable[cmdCode] >= ctx->cmdTableEnd) + { + ctx->mode = SCRIPT_MODE_STOPPED; + return FALSE; + } + + if (ctx->cmdTable[cmdCode](ctx) == 1) + return TRUE; + } + } + + return TRUE; +} + +static bool8 ScriptPush(struct ScriptContext *ctx, const u8 *ptr) +{ + if (ctx->stackDepth + 1 >= (int)ARRAY_COUNT(ctx->stack)) + return TRUE; + + ctx->stack[ctx->stackDepth] = ptr; + ctx->stackDepth++; + return FALSE; +} + +static const u8 *ScriptPop(struct ScriptContext *ctx) +{ + if (ctx->stackDepth == 0) + return NULL; + + ctx->stackDepth--; + return ctx->stack[ctx->stackDepth]; +} + +void ScriptJump(struct ScriptContext *ctx, const u8 *ptr) +{ + ctx->scriptPtr = ptr; +} + +void ScriptCall(struct ScriptContext *ctx, const u8 *ptr) +{ + ScriptPush(ctx, ctx->scriptPtr); + ctx->scriptPtr = ptr; +} + +void ScriptReturn(struct ScriptContext *ctx) +{ + ctx->scriptPtr = ScriptPop(ctx); +} + +u16 ScriptReadHalfword(struct ScriptContext *ctx) +{ + u16 value = *(ctx->scriptPtr++); + value += *(ctx->scriptPtr++) << 8; + return value; +} + +u32 ScriptReadWord(struct ScriptContext *ctx) +{ + u32 value0 = *(ctx->scriptPtr++); + u32 value1 = *(ctx->scriptPtr++); + u32 value2 = *(ctx->scriptPtr++); + u32 value3 = *(ctx->scriptPtr++); + return (((((value3 << 8) + value2) << 8) + value1) << 8) + value0; +}