Chip-8 on the COSMAC VIP: Loading and Saving Variables

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: 6XNN
Load VX with NN

INSTRUCTION GROUP: 8XY0
Load VX with VY

INSTRUCTION GROUP: AMMM
Load I with the address 0MMM

INSTRUCTION GROUP: FX55
Save variables V0 through VX starting at the address in I

INSTRUCTION GROUP: FX65
Load variables V0 through VX from memory starting at the address in I

These instruction groups are used for loading or saving the Chip-8 variables.

Instruction group 6XNN is very straightforward. It simply copies the second byte of the instruction into VX.

Here’s the code for this routine:

Address (hex) Code (hex) Labels Assembly Comments
01B4 45 6XNN: LDA 5 Get the value in the second byte of the instruction into the accumulator (D) and then advance the Chip-8 programme counter to the next instruction
01B5 56 STR 6 Store the value in VX
01B6 D4 SEP 4 Return to fetch and decode routine

Execution time for this instruction is 6 machine cycles (27.24 microseconds)

Instruction group 8XY0 is part of the broader 8XYN group. These are largely arithmetic and logic instructions, the exception being this sub-group, which copies the value in VY into VX. Here’s the code:

Address (hex) Code (hex) Labels Assembly Comments
01BC 45 8XYN: LDA 5 Get the value in the second byte of the instruction into the accumulator (D) and then advance the Chip-8 programme counter to the next instruction
01BD FA 0F ANI 0x0F Mask the byte to save just the second hex digit
01BF 3A C4 BNZ DECODE_ AL_ INSTR If the second digit is not zero, it’s an arithmetic and logic instruction, so branch to the decode routine for these
01C1 07 LDN 7 If we fall through to this point, it’s an 8XY0 instruction to copy VY into VX
Get the value of VY into the accumulator (D)
01C2 07 STR 6 Copy this into VX
01C3 D4 SEP 4 Return to the fetch and decode routine
01C4 DECODE_ AL_ INSTR_ The rest of the AL instruction handler continues from this point. I’ll analyse this further in a future post on that instruction group

Execution time for this instruction is 12 machine cycles (54.48 microseconds)

Register A on the CDP1802 is used as a general memory pointer by Chip-8. For the purpose of Chip-8 programmes it is designated as the variable I. Although RA can potentially point anywhere within the 64K that is addressable by the CDP1802, for Chip-8 programmes I is restricted to the first 4K (This is the maximum amount of on-card RAM for the COSMAC VIP). This variable can be set with the instruction AMMM where MMM is a 12-bit address from 0x000 to 0xFFF. To form the address, the interpreter uses the low-order byte of the instruction as it is and masks the high order byte so that the first hex digit is replaced with 0x0. So, for example, the instruction AD08 would set I to point to address 0x0D08.

Here’s the code:

Address (hex) Code (hex) Labels Assembly Comments
01EB 45 AMMM: LDA 5 Get the value in the second byte of the instruction into the accumulator (D) and then advance the Chip-8 programme counter to the next instruction
01EC AA PLO A Set this as the low-order byte of the address in I (RA)
01ED 86 GLO 6 Get low order byte of VX pointer, as this retains the second hex digit of the first instruction byte
01EF FA 0F ANI 0x0F Set the first hex digit to 0x0
01F0 BA PHI A Set this as the high-order byte of the address in I
01F1 D4 SEP 4 Return to the fetch and decode routine

Execution time for this instruction is 12 machine cycles (54.48 microseconds)

The next two instructions are part of a miscellaneous collection of FXXX instructions. These have a second decoding stage. The second byte of these instructions is actually the low-order byte of the address of their handling routines. The second stage decoding simply grabs this byte and uses it to update the interpreter’s programme counter so it continues execution from the correct point. Here’s the code for this second stage decoding:

Address (hex) Code (hex) Labels Assembly Comments
0105 45 DECODE_ FXXX_ INSTRUCTIONS: LDA 5 Get the value in the second byte of the instruction into the accumulator (D) and then advance the Chip-8 programme counter to the next instruction
0106 A3 PLO 3 Use this to set the interpreter programme counter (R3) to the address of the relevant handler. Execution will continue from there

This second stage of decoding adds an overhead of 4 machine cycles (18.16 microseconds) to group FXXX instructions.

Here’s a flowchart for both of these instruction groups:

A flowchart showing the sequence for storing or loading Chip-8 variables

Now here’s the code for the first of those instruction groups, FX55, which stores variables V0 through VX in memory starting from the address pointed to by I.

Address (hex) Code (hex) Labels Assembly Comments
0155 22 FX55: DEC 2 Decrement the stack pointer (R2), ready for a push
0156 86 GLO 6 Get the low order byte of the VX pointer …
0157 52 STR 2 … and push it onto the stack
0158 F8 F0 LDI 0xF0 0xF0 is the low-order byte of the address of the first variable (V0)
015A A7 PLO 7 Set this as the low-order byte of the VY pointer (R7)
015B 07 STORE_ VARS_ LOOP: LDN 7 Get the value of the next variable
015C 5A STR A Store it in the address pointed to by I
015D 87 GLO 7 Get the low-order byte of the address in I
015E F3 XOR XOR it with the value at the stack (the low-order byte of the VX pointer). This will result in 0 if they match – indicating that all the requested variables have been stored
015F 17 INC 7 Point VY to the next variable
0160 1A INC A Point I to the next address in memory
0161 3A 5B BNZ STORE_ VARS_ LOOP Return to top of loop if there are still more variables to store
0163 12 INC 2 Pop the low-order byte of VX off the stack
0164 D4 SEP 4 Return to the fetch and decode routine

The execution time for this instruction is 14 machine cycles (63.56 microseconds) plus 14 machine cycles for each variable stored. Total execution time will therefore range from 28 machine cycles (127.12 microseconds), if you store only V0, to 238 machine cycles (1080.52 microseconds), if you store all 16 variables.

One important thing to note about this routine is that I is not reset. At the end of the routine I will be pointing to the byte after the location of the last value stored. Another thing worth noting is that there is no validation of the address – the Chip-8 programmer must ensure that the address used here is sensible and there is sufficient space above it to store all the requested variables.

Finally, here’s the code for the complementary routine, FX65, which loads the values starting at the address in I into variables V0 through VX:

Address (hex) Code (hex) Labels Assembly Comments
0165 22 FX65: DEC 2 Decrement the stack pointer (R2), ready for a push
0166 86 GLO 6 Get the low order byte of the VX pointer …
0167 52 STR 2 … and push it onto the stack
0168 F8 F0 LDI 0xF0 0xF0 is the low-order byte of the address of the first variable (V0)
016A A7 PLO 7 Set this as the low-order byte of the VY pointer (R7)
016B 0A LOAD_ VARS_ LOOP: LDN A Get the byte at the address currently pointed to by I
016C 57 STR 7 Store it in the variable currently pointed to by VY
016D 87 GLO 7 Get the low-order byte of the address in I
016E F3 XOR XOR it with the value at the stack (the low-order byte of the VX pointer). This will result in 0 if they match – indicating that all the requested variables have been loaded
016F 17 INC 7 Point VY to the next variable
0170 1A INC A Point I to the next address in memory
0171 3A 6B BNZ LOAD_ VARS_ LOOP Return to top of loop if there are still more variables to load
0173 12 INC 2 Pop the low-order byte of VX off the stack
0174 D4 SEP 4 Return to the fetch and decode routine

The execution times for this instruction are identical to FX55. Once again note that I is left pointing to the address following the last one read into a variable.

A contemporary interpreter should implement all these instruction groups.

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

10 Responses to "Chip-8 on the COSMAC VIP: Loading and Saving Variables"

Leave a reply