Chip-8 on the COSMAC VIP: Branch and Call Instructions

This is part of a series of posts analysing the Chip-8 interpreter on the RCA COSMAC VIP computer. These posts may be useful if you are building a Chip-8 interpreter on another platform or if you have an interest in the operation of the COSMAC VIP. For other posts in the series refer to the index or instruction index.

INSTRUCTION GROUP: 1XXX
Branches to the instruction at address 0x0XXX

INSTRUCTION GROUP: 2XXX
Calls a subroutine at address 0x0XXX

INSTRUCTION: 00EE
Returns from a subroutine

INSTRUCTION GROUP: BXXX
Branch to the address calculated by adding 0x0XXX to Chip-8 variable V0

The branch instruction group (1XXX) is probably the simplest Chip-8 instruction group in terms of its execution, so I’m not going to bother with a flowchart for this one. It simply replaces the first digit of the instruction with 0x0 to form an address, and then loads that address into the Chip-8 programme counter before returning to the fetch and decode routine.

With the call instruction group (2XXX), things are a little more complicated, but not much. The address of the next Chip-8 instruction in sequence is pushed onto the stack. From then on the sequence is the same as for a branch instruction.

Again, that doesn’t really warrant a flow chart, so here’s the code for both instruction groups:

Address (hex) Code (hex) Labels Assembly Comments
0175 15 2MMM: INC 5 Start of handler for instruction group 2MMM: Call subroutine at 0x0MMM
Increment the Chip-8 programme counter (R5) to point to the next instruction in sequence
0176 85 GLO 5 Get the low-order byte of the address
0177 22 DEC 2 Decrement the stack pointer (R2)
0178 73 STXD Push the low-order byte of the address onto the stack and decrement the stack pointer
0179 95 GHI 5 Get the high-order byte of the address
017A 52 STR 2 Push it onto the stack
017B 25 DEC 5 Reset the Chip-8 programme counter to where it was (pointing at the low-order byte of the current instruction)
017C 45 1MMM: LDA 5 This is the entry point for the handler for group 1MMM instructions: Branch to instruction at address 0x0MMM
Get the low-order byte of the current instruction
017D A5 PLO 5 Load it into the low-order byte of the Chip-8 programme counter
017E 86 GLO 6 Get the low-order byte of the VX pointer (R6). This contains the most significant digit of the address to be called/branched to
017F FA 0F ANI 0x0F We just need to mask it off to get it
0181 B5 PHI 5 Load this into the high order byte of the Chip-8 programme counter (this now points to the first instruction of the subroutine/sequence to be branched to)
0182 D4 SEP 4 Return to fetch and decode routine (First instruction fetched on return will be first instruction of subroutine/sequence that has been branched to)

Timings for these instruction groups are 12 machine cycles (54.48 microseconds) for group 1XXX instructions and 26 machine cycles (118.04 microseconds) for group 2XXX instructions.

When a called subroutine wants to return, it uses instruction 00EE. This calls the machine code routine at 0x00EE. This simply pops the saved address off the stack and loads it into the Chip-8 programme counter, then returns execution to the fetch and decode routine. Here’s the code:

Address (hex) Code (hex) Labels Assembly Comments
00EE 15 RET: LDA 2 Start of routine to return from subroutine
Pop the high-order byte of the return address off the stack and advance the stack pointer
00EF B5 PHI 5 Load the high-order byte of the return address into the Chip-8 programme counter (R5)
00F0 42 LDA 2 Pop the low-order byte of the return address off the stack
00F1 A5 PLO 5 Load the low-order byte of the return address into the Chip-8 programme counter
00F2 D4 SEP 4 Return to the fetch and decode routine. The next instruction to be fetched will be at the return address

This routine takes 10 machine cycles (45.4 microseconds).

There is another branch instruction BXXX, which adds an offset to the address before branching. The offset is whatever value is currently in V0. Here’s the flowchart for this handler:

A flowchart showing the handler for Chip-8 Branch with Offset instructions

And here’s the code:

Address (hex) Code (hex) Labels Assembly Comments
01A4 F8 F0 BMMM: LDI 0xF0 Start of handler for group BMMM instructions: branch to address 0x0MMM + V0
Create the low-order byte of the address of V0
01A6 A7 PLO 7 Load this into the VY pointer (R7). This is already loaded with the high-order byte of the address, so it now points to V0
01A7 E7 SEX 7 Set the VY pointer to be used for register indirect addressing
01A8 45 LDA 5 Get the low-order byte of the current Chip-8 instruction
01A9 F4 ADD Add the value in V0 to the low-order byte of the current Chip-8 instruction to form the low-order byte of the address to be branched to
01AA A5 PLO 5 Load this into the Chip-8 programme counter
01AB 86 GLO 6 The VX pointer has the high-order byte of the address to be branched to
01AC FA 0F ANI 0x0F We just need to use a mask to set the most significant digit to 0x0
01AE 3B B2 BNF STORE_HIGH_ORDER_BYTE If the ADD instruction at 0x01A9 did not cause a carry, then we know the addition of the offset has not crossed a page boundary, so we can skip the next instruction
01B0 FC 01 ADI 0x01 If a carry was generated, we need to add 1 so the high-order byte of the address points to the correct page
01B2 B5 STORE_ HIGH_ ORDER_ BYTE: PHI 5 Load the high order byte of the address into the Chip-8 programme counter
01B3 D4 SEP 4 Return to fetch and decode routine (Next instruction fetched will be at the address branched to)

Timing for this instruction group is 24 machine cycles (108.96 microseconds) if a page boundary is crossed or 22 machine cycles (99.88 microseconds) if a page boundary is not crossed.

A contemporary interpreter should execute all four of these instructions/instruction groups.

This entry was posted in Chip-8, Retro Computing and tagged , , , , , . Bookmark the permalink.

3 Responses to "Chip-8 on the COSMAC VIP: Branch and Call Instructions"

Leave a reply