This is a little tutorial about how to implement Standard Call on SNES ASM.
Standard Call is a safety way to implements functions with parameters and local variables using the stack.
The process is:
1) Push each parameter on the stack.
2) Call Routine.
3) Have a way to access to any parameter or local variables easy.
4) Substract n bytes to stack (n = number of bytes uses on local variables).
5) Execute Routine.
6) Add n bytes to Stack (n = number of bytes used on local variables)
7) One register must have the return value.
8) Return from Routine.
9) Add m bytes to stack pointer (m = number of bytes used on parameters)
How it works:
considere that this is the stack:
After push all parameters this is the stack:
After call routine:
After substract n bytes for local variables.
After add n bytes before return.
After Return
After add m bytes after return.
To implement this on snes follow these steps:
1) Push Parameters (i recommend first 8 bits parameters and then 16 bits parameters).
Note: m = (2 * Number of 16bits parameters) + Number of 8bits parameters
2) Call Routine
Note: k = 2 if the routine is JSR and 3 if it is JSL.
3) Do a define that must be $01+n, in my case i will use 2 local variables 1 of 16 bits and other of 8 bits then n = (2 * Number of 16 bits local variables) + Number of 8 bits local variables = 3
4) Do a define for each parameter. Parameters are on !BasePointer+k and are saved in backward order.
5) Do a define for each local variable. Parameters are on !BasePointer.
6) On the routine starts substracting n bytes of Stack Pointer.
7) Before return add n bytes. Remember that register Y o X must have the the return value.
Note: You can access to each variable or parameters using register A for their operations, example: LDA !Par0 or STA !Par2
8) After call routine, add m bytes.
You can do macros to do all this easier, example:
------------------------------------------------------
Youtube
Twitter
SMWControlLibX GitHub
My Discord Server
Snestorage where you can download my resources
Standard Call is a safety way to implements functions with parameters and local variables using the stack.
The process is:
1) Push each parameter on the stack.
2) Call Routine.
3) Have a way to access to any parameter or local variables easy.
4) Substract n bytes to stack (n = number of bytes uses on local variables).
5) Execute Routine.
6) Add n bytes to Stack (n = number of bytes used on local variables)
7) One register must have the return value.
8) Return from Routine.
9) Add m bytes to stack pointer (m = number of bytes used on parameters)
How it works:
considere that this is the stack:
Code
| Stack Top (on snes $01,s).
After push all parameters this is the stack:
Code
| m bytes for Parameters | Stack Top (on snes $01,s).
After call routine:
Code
| m bytes for Parameters | k bytes for return address | Stack Top (on snes $01,s).
After substract n bytes for local variables.
Code
| m bytes for Parameters | k bytes for return address | n bytes for local variables | Stack Top (on snes $01,s).
After add n bytes before return.
Code
| m bytes for Parameters | k bytes for return address | Stack Top (on snes $01,s).
After Return
Code
| m bytes for Parameters | Stack Top (on snes $01,s).
After add m bytes after return.
Code
| Stack Top (on snes $01,s).
To implement this on snes follow these steps:
1) Push Parameters (i recommend first 8 bits parameters and then 16 bits parameters).
Code
LDA !Parameter8bits0 PHA LDA !Parameter8bits1 PHA REP #$20 LDA !Parameter16bits2 PHA LDA !Parameter16bits3 PHA SEP #$20
Note: m = (2 * Number of 16bits parameters) + Number of 8bits parameters
2) Call Routine
Code
JSR Routine
Note: k = 2 if the routine is JSR and 3 if it is JSL.
3) Do a define that must be $01+n, in my case i will use 2 local variables 1 of 16 bits and other of 8 bits then n = (2 * Number of 16 bits local variables) + Number of 8 bits local variables = 3
Code
!BasePointer = $04
4) Do a define for each parameter. Parameters are on !BasePointer+k and are saved in backward order.
Code
!Par3 = !BasePointer+2,s !Par2 = !BasePointer+4,s !Par1 = !BasePointer+6,s !Par0 = !BasePointer+7,s
5) Do a define for each local variable. Parameters are on !BasePointer.
Code
!LocalVar0 = !BasePointer,s ;Local var 0 is of 8 bits !LocalVar1 = !BasePointer-1,s ;Local var 1 is of 16 bits
6) On the routine starts substracting n bytes of Stack Pointer.
Code
Routine: TSC CLC ADC #$03 TCS ;Here Starts the routine RTS
7) Before return add n bytes. Remember that register Y o X must have the the return value.
Code
Routine: TSC SEC SBC #$03 TCS ;Here Starts the routine TSC CLC ADC #$03 TCS RTS
Note: You can access to each variable or parameters using register A for their operations, example: LDA !Par0 or STA !Par2
8) After call routine, add m bytes.
Code
JSR Routine TSC CLC ADC #$06 TCS
You can do macros to do all this easier, example:
Code
macro AddStack(val) TSC CLC ADC #<val> TCS endmacro macro SubStack(val) TSC SEC SBC #<val> TCS endmacro macro PushPar(par) LDA <par> PHA endmacro macro RTIN(n) %AddStack(<n>) RTI endmacro macro RTSN(n) %AddStack(<n>) RTS endmacro macro RTLN(n) %AddStack(<n>) RTL endmacro macro StartFunction(name, n) <name>: %SubStack(<n>) endmacro macro CallFunction(name, m) JSR <name> %AddStack(<m>) endmacro macro CallRoutine(par0, par1, par2, par3) %PushPar(<par0>) %PushPar(<par1>) REP #$20 %PushPar(<par2>) %PushPar(<par3>) SEP #$20 %CallFunction(Routine, $06) endmacro !BasePointer = $01+3 !Par3 = !BasePointer+2,s !Par2 = !BasePointer+4,s !Par1 = !BasePointer+6,s !Par0 = !BasePointer+7,s !LocalVar0 = !BasePointer,s ;Local var 0 is of 8 bits !LocalVar1 = !BasePointer-1,s ;Local var 1 is of 16 bits %StartFunction("Routine", $03) ;Here Starts your routine %RTSN($03) Main: %CallRoutine(#$10, $1234, $000000, $0F) RTS
------------------------------------------------------
Youtube
SMWControlLibX GitHub
My Discord Server
Snestorage where you can download my resources