The stack
The stack is a special type of "table" which is located inside the SNES RAM. Imagine the stack as a stack of plates. You can only add (push) or remove (pull/pop) a plate from the top. You can visualize it as something like this:
The empty "boxes" in above example are basically the values inside the stack, and they can hold any value. The collection of boxes are closed off from all sides, except from the top.
Technically speaking, because the stack is an area inside the RAM, you can access any value you want, using special stack-relative addressing modes rather than using only push and pull opcodes. For the purposes of this chapter, we'll assume the stack indeed is a perfect stack of plates.
Push
"Pushing" is the act of adding a value on top of the stack. Here's an example:
As you can see, the value $32 is added on top of the stack. The stack now has five values instead of four.
Pull/Pop
"Pulling" (or "popping") is the act of reading a value from the top of the stack. Here's an example:
As you can see, the value $32 is retrieved from the top of the stack.
All pulling instructions affect the Negative and the Zero processor flags.
Push A, X, Y
There are opcodes to push the current value inside the A, X or Y registers onto the stack:
Opcode | Full name | Explanation |
PHA | Push A onto stack | Pushes the current value of A onto the stack |
PHX | Push X onto stack | Pushes the current value of X onto the stack |
PHY | Push Y onto stack | Pushes the current value of Y onto the stack |
Pull A, X, Y
There are also opcodes to pull the current value from the stack into the A, X or Y registers:
Opcode | Full name | Explanation |
PLA | Pull into A | Pulls a value from the stack into the A register |
PLX | Pull into X | Pulls a value from the stack into the X register |
PLY | Pull into Y | Pulls a value from the stack into the Y register |
Example
Imagine the following scenario: The X register has to stay at the value $19, no matter what, but you really have to use X for something else. How would one do that? You use PHX to preserve the value in X in the stack, before you use an instruction which modifies the contents of X:
The A, X and Y registers do not have a separate stack. There is only one stack, specified by the "stack pointer register". For detailed explanations about the stack pointer register, see: Stack pointer register
16-bit mode stack operations
All the previous explanations and behaviours apply to 16-bit stack operations as well. It's just that you're pushing and pulling 16-bit values, not 8-bit values.
This also means that if you push two 8-bit values onto the stack, you can pull a single 16-bit value later.
Other push and pull operations
There are also other push and pull commands, which are not affected by 8-bit or 16-bit mode A, X and Y:
Opcode | Full name | Explanation | Value size |
PHB | Push data bank register | Pushes the data bank register's current value onto the stack | 8-bit |
PLB | Pull data bank register | Pulls a value from the stack into the data bank register | 8-bit |
PHD | Push direct page register | Pushes the direct page register's current value onto the stack | 16-bit |
PLD | Pull direct page register | Pulls a value from the stack into the direct page register | 16-bit |
PHP | Push processor flags | Pushes the processor flags register's current value onto the stack | 8-bit |
PLP | Pull processor flags | Pulls a value from the stack into the processor flag register | 8-bit |
PHK | Push program bank | Pushes the bank value of the currently executed opcode (which is PHK) onto the stack | 8-bit |
PEA $XXXX | Push effective address | Pushes the specified 16-bit value onto the stack. Don't let the name of the opcode mislead you. This doesn't read out any address | 16-bit |
PEI ($XX) | Push effective indirect address | Pushes the value at the given direct page address onto the stack. The direct page register can affect the given address | 16-bit |
PER label | Push program counter relative | A rather complicated push. In short: it pushes the absolute address of the given label onto the stack. What happens during assembly is that the assembler calculates the relative distance between PER and the given label. This relative distance is a signed 16-bit value and is used as the parameter for PER. The opcode finally assembles into | 16-bit |
Last updated