CHIP-8 Instruction Set

CHIP-8's instruction set is pretty straightforward. I'm going to categorize them by their first nibble, since that seems to be as good a way as any. If you look at the Wikipedia reference, you'll see 3 placeholder letters being used.

Register placeholders X and Y are used in place of register numbers - when you see X or Y in number, for instance 8XY0, X and Y are replaced with a one of 16 register numbers 0-F.

Immediate Values N is used wherever the number is interpreted as immediate, that is used as is. 2 Ns (NN) is for a byte of data, and 3 Ns (NNN) signifies an address.

0xxx ops, special

There are 3 ops starting with zero. One clears the screen, and one is return from subroutine. The 3rd will execute a subroutine in an RCA 1802 - since we aren't emulating the 1802 processor we won't do that instruction. I didn't see a CHIP-8 programs use that.

Here's the Assembly syntax I'll use:

   Op     Nemonic    
   00E0   CLS    
   00EE   RTS    

1xxx, 2xxx, Bxxx ops, jumps and calls

The 1xxx opcodes are absolute jumps. The opcode 12A8 equates to JUMP $2A8

2NNN will jump to a subroutine by:

  1. pushing the address if the next instruction on a stack

  2. setting the PC to the address contained in the instruction

22A8 would yeild CALL $2A8

Each subroutine has to end with a 00EE instruction (RTS). CHIP-8 assumes that the programs can call up to 16 nested subroutines - it is not defined what happens if you call more than 16.

The BNNN opcode performs an indexed jump. B290 would jump to the absolute address $290 plus the value contined in V0. So if V0 contained #$08, the program would jump to $298. B290 will show in my disassembly as JUMP $290(V0).

3xxx, 4xxx, 5xxx, 9xxx ops, compare and skip

These instructions will compare 2 values and skip the next instruction if the test passes. I'm going to assign assembly nemonic "SKIP" to the instruction, so exmples are:

   OP     NEMONIC    
   3A00   SKIP.EQ   VA, #$00    
   4800   SKIP.NE   V8, #$00    
   5A70   SKIP.EQ   VA, V7    
   93B0   SKIP.NE   V3, VB    

These let programs do conditional execution. A sequence like this would clear the screen unless V5 contained zero:

   ---- -----------    
   021A SKIP.NE  V5, #$00    
   021C JUMP     $220    
   021E CLS    
   0220 MOV      V5, #$00    

8xxx, register ops and condition codes

There are 9 instructions in the 8xxx group that use 2 registers. VX will be modified by VY. You can see in the Wikipedia table that some of the operations will modify VF based on the result of the math. This is CHIP-8's version of condition codes.

For the assembly syntax, I'm going to use a dot '.' after the instruction to indicate that the instruction will modify VF. Here are the sample assembly:

   83A0     MOV     V3, VA    
   83A1     OR      V3, VA    
   83A2     AND     V3, VA    
   83A3     XOR     V3, VA    
   83B4     ADD.    V3, VB    
   83B5     SUB.    V3, VB    
   83x6     SHR.    V3    
   83B7     SUBB.   V3, VB    
   83xE     SHL.    V3    

The SUBB instruction is "backward subtract", where VX=VY-VX.

All the rest

The rest of the instructions are hard to categorize so we'll cover them during the emulator implementation. They mostly have to do with drawing sprites, timers, and keyboard interaction. I'll just present my assembler syntax for them:

   Op      Syntax    
   DXYN    SPRITE       VX, VY, #$N    
   EX9E    SKIP.KEY     VX    
   EXA1    SKIP.NOKEY   VX    
   FX07    MOV          VX, DELAY    
   FX0A    WAITKEY      VX    
   FX15    MOV          DELAY, VX    
   FX18    MOV          SOUND, VX    
   FX1E    ADD          I, VX    
   FX29    SPRITECHAR   VX    
   FX33    MOVBCD       VX    
   FX55    MOVM         (I), V0-VX    
   FX65    MOVM         V0-VX, (I)    

This should be plenty of information to finish the disassembler and get us started on the emulator.

View my CHIP-8 Disassembler source

← Prev: chip-8-disassembler   Next: chip-8-emulator →