This post is part of a series on the Chip-8 interpreter. In this post I will look at how the Chip-8 interpreter is launched and initialised on the COSMAC VIP. If you are unfamiliar with the RCA CDP1802 processor, you might want to read this earlier post first. In a previous post I talked about how the VIP’s ROM is executed. The ROM basically provides four functions:
- The user can enter bytes to be written to memory from a selected address
- The user can inspect the memory at a selected address to see what is stored there
- The user can save a block of memory to tape from a selected address
- The user can restore a block of memory from tape to a selected address
That’s it! To access these functions, the user must hold the C key down as they flip the RUN switch on the VIP. If they flip RUN without holding the C key the ROM will do just three things. First it will enable the RAM, then it will find the top of available RAM to determine how much memory the system has, then it will execute the programme stored in RAM at 0x0000.
So it is expected that the user has entered and verified the Chip-8 interpreter using functions 1 and 2, saved it for further use with function 3 and then used function 4 each time they want to run the interpreter.
Whenever any programme is first run on the VIP, the registers are configured as follows:
- X is 0, so R0 will be used for indirect register addressing operations.
- P is also 0, so R0 is the program counter.
- R0 points to the start of RAM (0x0000).
- R1 points to the last byte of on-card RAM (note that this might not be the last byte of all the RAM, if an external RAM module has been installed).
- The remaining registers will be in an undefined state.
Another important thing to note is that the VIP’s display will be off at this point, so no screen refresh interrupts will be generated.
Chip-8 uses the general purpose 16-bit registers in different roles as follows:
|R0||DMA pointer for screen refresh|
|R1||Program counter for interrupt routine|
|R3||Interpreter subroutine/machine code subroutine program counter|
|R4||CALL (fetch and decode) subroutine program counter|
|R5||Chip-8 program counter|
|R6||VX pointer (this points to the chip-8 variable used as the first parameter in an instruction)|
|R7||VY pointer (this points to the chip-8 variable used as the second parameter in an instruction)|
|R8||Timers (R8.0 is the tone timer and R8.1 is the general purpose timer)|
|RB||Display page pointer|
|RC||Used for temporary storage only|
|RD||Used for temporary storage only|
|RE||Used for temporary storage only|
|RF||Used for temporary storage only|
I’ll explain these in more detail as they become relevant. One initial thing to note though, is that the roles chosen for each register are not arbitrary. Whenever DMA is used, as it is by the display controller in the COSMAC VIP, R0 is always used as the pointer to the memory to be accessed. Also whenever interrupts are enabled, as they will be when the display is switched on, R1 should always be set as the program counter for the interrupt routine and should initially be pointing to the first byte of that routine. Here’s a flowchart showing how the interpreter sets these up.
Here’s the code for this section of the interpreter.
|Address (hex)||Code (hex)||Labels||Assembly||Comments|
|0000||91||GHI 1||When a program is initially run R1 points to the end of the last available page of on-card RAM.|
|0001||BB||PHI B||Sets RB to highest memory page (this is the display page)|
|0002||FF 01||SMI 0x01||Point to previous page in RAM|
|0004||B2||PHI 2||Set the high order byte of the stack pointer to this page|
|0005||B6||PHI 6||Set the high order byte of the VX pointer to this page|
|0006||F8 CF||LDI 0xCF||Initialise low order byte of stack pointer|
|0009||F8 81||LDI 0x81||These next four instructions set the Program Counter for the interrupt routine in R1 to 0x8146|
|000C||F8 46||LDI 0x46|
|000F||90||GHI 0||Set R4 to 0x001B in preparation for assignment as Program Counter for the call routine|
|0011||F8 1B||LDI 0x1B|
|0014||F8 01||LDI 0x01||Set R5 to 0x01FC. This register will act as the Chip 8 Program Counter.|
|0017||F8 FC||LDI 0xFC|
|001A||D4||SEP 4||R4 is now the interpreter program counter. This has no effect on the sequence at this point because R4 points to 001B which is the next instruction pointed to by the old PC in R0.|
This sequence is run just once, when the interpreter first starts. The whole thing takes 40 machine cycles. One machine cycle on the CDP1802 requires 8 clock cycles. So, on the COSMAC VIP, which has a clock speed of 1.7609Mhz, one machine cycle takes 4.54 micro seconds. This equates to an execution time of 181.6 micro seconds for this routine.
For a programmer of a contemporary interpreter, the initialise sequence is unlikely to follow this pattern, although the basic tasks, such as initialising the stack pointer, will still need to be carried out.
In the next post in this series, I’ll look at the Chip-8 call, or fetch and decode, sequence in detail.