I am currently working on a Chip-8 interpreter for Mac OS X. As part of my preparation for this project I wanted to analyse the original Chip-8 interpreter created for the COSMAC VIP computer. To do this work I needed to get intimate with the processor at the heart of that machine, the RCA 1802.
This post details my findings.
The RCA CDP1802 is quite a lovely beast as microprocessors go. It was developed by a Joseph Weisbecker back in the early 1970s, initially as a two-chip system. In 1976 both circuits were combined on a single dual inline package. It’s a testament to the ingenious and versatile design of the 1802 that forty years on it is still used in many different applications. It’s even been into space, as it was used in many systems in the Galileo space probe and onboard other spacecraft.
Although it is an 8-bit system, and the physical address bus is only 8-bits wide, the 1802 uses a multiplexer to create a 16-bit address, giving a maximum addressable memory of 64K. When putting an address onto the address bus, the multiplexer puts the high order byte first then the low order byte. Two timing control signals, TPA and TPB, let memory and other connected systems know which part of the address is currently on the address bus. So effectively this forms a paging mechanism where the memory is divided into 256 pages of 256 bytes per page. The high order byte of the address indicates the page and the low order byte indicates the location within the page.
In terms of timing in general, most 1802 instructions require two machine cycles, each of which requires 8 clock cycles. The first machine cycle fetches the instruction and the second executes it. Long branch instructions (i.e. those that use a full 16 bit address) require three machine cycles, one for fetching and two for execution. For this reason the 1802 has instructions for both short branches within a memory page and long branches between memory pages.
Another thing that is unusual about the 1802 architecture is that there is no dedicated program counter. Instead the 1802 has 16 16-bit registers, labelled R0 to RF. These are split into two 8 bit pairs labelled RX.0 and RX.1 for the low and high byte respectively. Any of these register pairs can be designated as the program counter. The current program counter is indicated by a special 4-bit register, P, which is set using a SEP instruction. So, rather than using CALL and RETurn instructions, the way to call a subroutine is to set the register holding the address of the subroutine as the program counter. At the end of the subroutine, execution can be continued from after the calling instruction by designating the original register as the program counter. See the diagram below for an example.
Any of the registers can also be used as an address pointer for register indirect memory addressing. Again there is a special 4-bit register, X, that indicates the register currently being used for this. The X register is set with an SEX instruction (no sniggering at the back please). The X register is used by instructions such as LDXA, which reads from a memory location then advances the pointer, and STXD which works in the same way for writing to memory but decrements the pointer. So, for example, consider the following code:
(Assume R1 is set to a source address, R2 is set to a destination address, and R3 is set to the number of bytes to copy)
This will copy the number of bytes in R3.0 starting from the address in R1 to the memory starting from the address in R2.
The use of the X and P registers gives rise to another 1802 oddity, which is instructions that sometimes appear to have an immediate operand and sometimes don’t!
Here’s an actual example from the VIP’s operating system. There are a series of instructions, OUT 1 to OUT 7. These are single byte instructions, 0x61 to 0x67. Their function is to set the 1802’s three I/O control lines to a specific state (indicated by the number). This will activate whatever I/O device is connected to respond to that configuration of the I/O lines. They also put the contents of the memory location pointed to by the register indicated by X onto the data bus to be read by that I/O device. Finally, they increment the register pointed to by X, so it points to the next address. This makes it easier to use a series of OUT instructions to send sequential data to the I/O device.
Early on in the operating system, you will see this instruction: OUT 4, 0x00. This is odd. Suddenly the 1 byte OUT instruction has an operand and appears to work in a direct addressing mode! This is something that initially confused me and may well confuse others who are unfamiliar with the 1802.
Here’s how it works. When this instruction is executed by the operating system, R2 has been designated as the register for indirect addressing by a SEX 2 instruction, but it has also been designated as the program counter by a SEP 2 instruction. This set up causes the following sequence to occur:
- The OUT 4 instruction is fetched
- The program counter (R2) is incremented
- The OUT 4 instruction is decoded
- The memory at the address in R2 is read. Because R2 was incremented back in step 2 it now points to the byte after the OUT 4 instruction, which happens to be the ‘operand’ 0x00
- After the memory is read, the OUT 4 instruction increments the indirect addressing register (R2)
- The next instruction is fetched. Because R2 was incremented back in step 5, this is the byte that followed the ‘operand’ 0x00.
This sort of weirdness is typical of the 1802’s ingenious design.
To help me with my analysis I made a table listing all the opcodes, with their mnemonics and descriptions. It is included twice, first sorted numerically by opcode and then sorted alphabetically by mnemonic. If you would like a copy, select the link below to download it as a PDF.