Skip to content
Lesson 5 of 13

Step 1 of 5 · Reading · ~3 min

Read

Instructions

Stack & Jumps

After this lesson a ROM can leave the straight line: jump to another address, call a subroutine and come back, and pick a target from a table. Without these a CHIP-8 program is a few dozen instructions that run once. With them it is a loop, and a game is a loop.

Four ways to change PC

1NNN  JP NNN       PC = NNN
2NNN  CALL NNN     save PC on the stack, then PC = NNN
00EE  RET          PC = the most recently saved address
BNNN  JP V0, NNN   PC = NNN + V0

Addresses are 12 bits, so every new PC is masked to 0x000..0xFFF.

The stack holds return addresses and nothing else

The stack has 16 slots, and each slot holds one address. CALL pushes the current PC. Fetch already moved PC past the CALL, so the saved value is the address of the instruction after the CALL, which is exactly where RET must land. Pushing the address of the CALL itself would make every return call the subroutine again.

Trace of a call, using addresses this lesson's tests do not use:

200: 2208   CALL 208
202: 6301   V3 = 1
204: 1204   JP 204        (jump to itself: the usual way to "stop")
206: 0000
208: 7A05   VA = VA + 5
20A: 00EE   RET
step  runs   PC after  stack
1     2208   208       [202]
2     7A05   20A       [202]
3     00EE   202       []
4     6301   204       []
5     1204   204       []     (stays here forever)

A jump to its own address never advances, so a ROM that has nothing left to do ends in JP to itself. Emulators and test ROMs rely on it.

Overflow and underflow

Sixteen nested calls fit. The seventeenth does not, and RET with nothing saved has nowhere to go. Real interpreters differ on what happens, so this machine defines it: the instruction does nothing else, the machine records a fault (STACK_OVERFLOW or STACK_UNDERFLOW), and from then on RUN executes nothing. PC stays where fetch left it, just past the faulting instruction, and SHOW adds a third line FAULT= followed by the name.

BNNN: jump tables

BNNN adds V0 to the address. Put a row of two-byte JP instructions at NNN and load V0 with twice the case number; the jump lands on that case's row, which jumps on to the code. It is the CHIP-8 switch statement. (Some later interpreters use BXNN and add VX; that is a quirk for the quirks lesson.)

Common mistakes

  • Saving the CALL's own address, so RET calls the subroutine again forever.
  • Allowing a 17th nested call by checking the depth after the push instead of before.
  • Letting RET on an empty stack read a stale slot and jump somewhere random.
  • Forgetting to mask NNN + V0, so PC leaves the 4 KB address space.
  • Continuing to execute after a fault.

Your exercise

The starter already runs everything from the earlier lessons. You add 1NNN, 2NNN, BNNN and 00EE, including the two faults. Test a chain of exactly 16 calls and then a 17th: the boundary is where a stack goes wrong.

Up nextMemory InstructionsInstructions

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…