Msx Assembly 101: 04 Stack
Stack in cartridges
According to MSX Technical Handbook, a cartridge software should initialize
stack pointer before using the stack. The common practice is to put 0xF380
into sp
register (see
this)
and remember that stack grows downwards.
It means that any cartridge program, which uses the stack, should near its
beginning do something like ld sp, 0f380h
.
Stack in CP/M programs
When a CP/M program starts execution, sp
points to the stack of 16 bytes.
Since any subroutine call puts a return address on the stack, you can do no
more than 7 nested calls if you do not use stack and do not call BDOS
routines (2 bytes are already consumed by the CP/M return address, used when
your program does final ret
). Due to this, it is a good practice to use own
stack space in CP/M program. Moreover, CP/M expects that the program preserves
stack pointer. It all means that the following should be done at the start of a
program:
sp
must be preservedsp
should be initialized to point to some own space
and in the end sp
should be restored.
In assembly it means the following:
At the start
ld [SavedStack], sp
ld sp, Stack
The memory for saving the old sp
value (2 bytes) and for the new stack area
(whatever) should be reserved. The following reserves 32 bytes for the program
stack:
SavedStack:
ds 2
ds 31
Stack:
ds 1
Remember that stack grows downwards, so the corresponding label points to the last reserved byte in stack area.
At the end, sp
should be restored: ld sp, SavedStack
.
Putting it all together
We will modify our framework which can compile both cartridge software and CP/M program from the same source introduced in YAZE post to add stack handling to it. Now the program should look like this:
.INCLUDE "format.asm"
IFDEF CARTRIDGE
.PAGE 1
.ROM
.BIOS
ENDIF
IFDEF CPM
.MSXDOS
ENDIF
; this adds macro, initializing the stack pointer
Start: MACRO
IFDEF CARTRIDGE
ld sp, 0f380h
ENDIF
IFDEF CPM
ld [SavedStack], sp
ld sp, Stack
ENDIF
ENDM
Stop: MACRO
IFDEF CARTRIDGE
@@end:
jr @@end
ENDIF
; if we are compiling CP/M program, it restores the stack pointer to the
; original value and reserves the space after program end to store `sp`,
; and also area for the new stack
IFDEF CPM
ld sp, [SavedStack]
ret
SavedStack:
ds 2
ds 31
Stack:
ds 1
ENDIF
ENDM
Start
; program body
Stop