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:
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.
By Chip-8 on the COSMAC VIP: Index | Laurence Scotford August 4, 2013 - 6:34 am
[…] The following posts analyse different parts of the interpreter. These are useful if you want to ensure that your implementations of Chip-8 instructions follow the behaviour of the original interpreter: Chip-8 on the COSMAC VIP: Initialisation Chip-8 on the COSMAC VIP: The Call Routine (Fetch and Decode) Chip-8 on the COSMAC VIP: Machine Code Integration Chip-8 on the COSMAC VIP: Branch and Call Instructions Chip-8 on the COSMAC VIP: Skip Instructions Chip-8 on the COSMAC VIP: Loading and Saving Variables […]
By Chip-8 on the COSMAC VIP: Arithmetic and Logic Instructions | Laurence Scotford August 10, 2013 - 8:10 am
[…] There’s a short routine here to copy VY into VX. This was analysed in a previous post […]
By Chip-8 on the COSMAC VIP: Drawing Sprites | Laurence Scotford August 24, 2013 - 7:07 am
[…] to the memory location of the first row of pixels in the sprite. You can set I with either the AMMM instruction, which simply sets I to the address 0x0MMM, or with the FX29 instruction, which I will analyse in a […]
By Chip-8 on the COSMAC VIP: Keyboard Input | Laurence Scotford October 8, 2013 - 9:23 pm
[…] The final instruction, FX0A,is intended for situations in which you want to wait for a key press, turn-based games for example. This instruction is part of the FXXX instruction group, so it is subject to an additional stage of decoding. I discuss this in an earlier post. […]
By Chip-8 on the COSMAC VIP: Indexing the Memory | Laurence Scotford October 10, 2013 - 5:52 am
[…] an earlier post I showed how I could be loaded with any 12-bit address using the AMMM instruction group, and how it […]
By Chip 8 on the COSMAC VIP: Instruction Index | Laurence Scotford October 19, 2013 - 11:30 am
[…] Loading and Saving Variables […]
By Chip-8 on the COSMAC VIP: Binary Coded Decimal | Laurence Scotford October 19, 2013 - 11:35 am
[…] will have to add the small overhead for the second stage decoding of these instructions. See this earlier post for […]
By Chip-8 on the COSMAC VIP: Sound | Laurence Scotford June 7, 2015 - 8:27 am
[…] As this is part of the FXXX instruction group it is subject to a small secondary stage of decoding which is discussed in an earlier post. […]
By Chip-8 on the COSMAC VIP: The General Purpose Timer | Laurence Scotford June 7, 2015 - 8:28 am
[…] These instructions are both part of the FXXX instruction group, so they are subject to an additional stage of decoding. I discuss this in an earlier post. […]
By Chip-8 on the COSMAC VIP: The Character Set | Laurence Scotford October 25, 2015 - 10:14 am
[…] the small overhead for the second stage decoding of these instructions needs to be added. See this earlier post for […]