Language…
22 users online: Adsila, alerzi520,  Anorakun, Batata Douce, conicthecat, drake-68,  Erik,  Fernap, Foxy_9000_, Green, Green Jerry, GRIMMKIN, Hot Sauce, KaidenThelens, Knight of Time, Koopster, Lady_Amethyst, LOLRyan2006 the Goombud, PermaBan, Sokobansolver, Squiffygrape, TCgamerboy2002 - Guests: 200 - Bots: 101
Users: 68,885 (2,338 active)
Latest user: alerzi520

Standard Call on SNES ASM

AdvancedASM Coding

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:

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
Twitter
SMWControlLibX GitHub
My Discord Server
Snestorage where you can download my resources

AdvancedASM Coding