Skip to content

Chip-8 on the COSMAC VIP: Machine Code Integration

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: 0MMM
Calls a machine code subroutine at the address 0x0MMM.

This instruction group allows RCA 1802 machine code to be integrated with a Chip-8 programme. I analysed the routine that calls the machine code subroutine in a previous post.

The ability of a Chip-8 programme to be mixed with machine code was undoubtedly a very powerful feature for COSMAC VIP users, however there are restrictions.

It is important that the machine code subroutine does not change registers that are reserved for use by the Chip-8 interpreter. The registers that can be safely used are RC, RD, RE and RF. The Chip-8 interpreter uses these for temporary storage only. All other registers have a specific purpose and should not be changed. Except in the explicit case of R5 mentioned below, changing the value of any of the other registers could prevent the Chip-8 interpreter from functioning correctly. See this earlier post for a table showing how the registers are used by Chip-8.

R3 will be the designated programme counter when the machine code subroutine is called. It is possible for the Chip-8 program to pass arguments to a machine code subroutine. To do this the arguments should immediately follow the instruction that calls the subroutine. The Chip-8 programme counter R5 will be pointing to the byte immediately following this instruction. After reading the arguments, the machine code subroutine should advance R5 to the next valid Chip-8 instruction before returning.

The machine code subroutine should use a D4 (SEP 4) instruction to return control to the Chip-8 interpreter.

In a previous post I mentioned that the Chip-8 interpreter adds two instructions to the start of every Chip-8 programme. Both of these are group 0 instructions that call machine code subroutines within the interpreter. The first is 0x00E0. This calls a routine that clears the display memory by setting all the bytes to 0. It’s quite a straightforward subroutine. Here’s the flowchart for it:

A flowchart describing the function of the clear screen subroutine in the COSMAC VIP ROM.
A flowchart describing the function of the clear screen subroutine in the COSMAC VIP ROM

And here’s the code:

Labels
Address (hex)

Code (hex)
Assembly

Comments

RETURN_ TO_ FETCH_ LOOP: 00DF

D4
SEP 4

Set R4 as program counter (this returns execution to the fetch and decode routine at 0042). This is actually the last instruction of the draw sprite subroutine, but it is "borrowed" by the clear screen subroutine (see instruction at 0x00E8 below).

CLS:
00E0

9B
GHI B

This is the actual entry point of the clear screen subroutine. Get the display page …

00E1

BF
PHI F

… and store it in RF.1

00E2

F8 FF
LDI 0xFF

Store 0xFF in RF.0 …

00E4

AF
PLO F

… so that RF now points to the final byte in the display page.

CLEAR_ SCREEN_ LOOP:
00E5

93
GHI 3

Get zero into the accumulator (D). R3 is the interpreter subroutine/machine code subroutine programme counter. Since this routine is in page 0, R3.1 will contain 0 and it takes just a one byte instruction to get the value from this source rather than using a two-byte immediate addressing instruction. This is another example where saving a few bytes of memory here or there was more important than code clarity!

00E6

5F
STR F

Zero the memory location currently pointed to by RF.

00E7

8F
GLO F

Get the low order byte of the current address in RF.

00E8

32 DF
BZ RETURN_ TO_ FETCH_ LOOP

If the byte that's just been zeroed is at address 0x00 in the display page then we're done, so jump to the return instruction.

00EA

2F
DEC F

Otherwise point to the previous byte in the display (bytes are zeroed starting at the final byte in the page and moving backwards through the display memory).

00EB

30 E5
BR CLEAR_ SCREEN_ LOOP

Jump back to the top of the loop.

00ED

00
DB 0x00

There's one byte of filler at the end of this subroutine

Since some Chip-8 programmes will use this machine code subroutine elsewhere in the programme as a convenient way of clearing the screen, 0x00E0 should be treated by contemporary interpreters as a clear screen instruction.

This routine takes 24 cycles (108.96 microseconds) to execute.

The second instruction added to the start of every Chip-8 programme is 0x004B. This routine switches on the COSMAC VIP’s display. This is necessary because, by default, the display is off. This is a very short routine that simply sends an input command to the display controller that causes it to turn on. From this point an interrupt will be generated 60 times a second. I”ll discuss this further in a future post on the COSMAC VIP interrupts. Here’s the code for this subroutine:

Labels
Address (hex)

Code (hex)
Assembly

Comments

SWITCH_ ON_ DISPLAY:
004B

22
DEC 2

R2 is the stack pointer. The 1802 has no push or pop operations, so this has to be done manually. The stack grows downwards in memory, so to push a value onto the stack, the stack pointer has to be decremented first.

004C

69
INP 1

This sends a control signal to the video controller to turn it on. The video controller now starts generating interrupts every 60th of a second and using DMA to read the display memory. The memory to be accessed is controlled by the interrupt handler that is pointed to be the address in R1. INP instructions will read the byte placed on the data bus. This is read into the accumulator (D) and placed onto the stack (R2). We don’t have any use for this value, so…

004D

12
INC 2

… we immediately pop it off the stack.

004E

D4
SEP 4

Return control to the interpreter’s fetch and decode routine at 0x0042.

This takes 8 machines cycles (36.32 microseconds) to execute.

As the display should remain on while the Chip-8 interpreter is running, there will be no need for this subroutine to be called again. A contemporary interpreter can safely ignore this instruction in favour of its own display handling code.

The Chip-8 interpreter makes one final machine code subroutine available to the Chip-8 programme. This is located at 0x00EE and must be called (with a 00EE instruction) whenever a Chip-8 subroutine needs to return to its caller. Since this goes hand in hand with the group 2 CALL instructions, I will analyse it in the post that looks at that instruction group.

Published inProgrammingRetro Computing

Be First to Comment

Leave a Reply

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