Skip to content

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:

Labels
Address (hex)

Code (hex)
Assembly

Comments

6XNN:
01B4

45
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:

Labels
Address (hex)

Code (hex)
Assembly

Comments

8XY0:
01BC

45
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

56
STR 6

Copy this into VX.

01C3

D4
SEP 4

Return to the fetch and decode routine.

DECODE_ AL_ INSTR:
01C4

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:

Labels
Address (hex)

Code (hex)
Assembly

Comments

AMMM:
01EB

45
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:

Labels
Address (hex)

Code (hex)
Assembly

Comments

DECODE_ FXXX_ INSTRUCTIONS:
0105

45
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 describing the operation of Chip-8 interpreter for group FX55 and group FX65 instructions.
Flowchart describing the operation of Chip-8 interpreter for group FX55 and group FX65 instructions

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.

Labels
Address (hex)

Code (hex)
Assembly

Comments

FX55:
0155

22
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).

STORE_ VARS_ LOOP:
015B

07
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:

Labels
Address (hex)

Code (hex)
Assembly

Comments

FX65:
0165

22
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).

LOAD_ VARS_ LOOP:
016B

0A
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.

Published inProgrammingRetro Computing

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *