CHIP 8 Interpreter Disassembly
CHIP 8 Interpreter Disassembly
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 the VX pointer
to this page
0008 A2 PLO 2
000B B1 PHI 1
000E A1 PLO 1
0010 B4 PHI 4
0013 A4 PLO 4
0016 B5 PHI 5
0019 A5 PLO 5
001B 96 FETCH_DEC GHI 6 The Chip 8 Fetch and Decode routine starts
ODE_LOOP: here
Get the high order byte of the VX pointer ...
001C B7 PHI 7 ... and copy this to the high order byte of the
VY pointer
0023 F6 SHR
0024 F6 SHR
0025 F6 SHR
002C FA 0F ANI 0x0F Mask the first byte of the Chip-8 instruction
to leave only the least significant digit
0033 F6 SHR
0034 F6 SHR
0035 F6 SHR
003F 0C LDN C Get the low order byte of the address from
the lookup table
0040 A3 CALL_SUBRO PLO 3 And use this to set the low order byte of the
UTINE: interpreter programme counter (R3)
0045 FA 0F ANI 0x0F Use a mask to remove the first digit of the
instruction (leaving the high order byte of
the address to be called)
0047 B3 PHI 3 Use this to set the high order byte of the
interpreter programme counter (R3), as this
is also used as the programme counter for
machine code routines called with this
instruction
0051 01 01 01 01 01 01 01 01 DB 0x01, 0x01, 0x01, 0x01, 0x01, A lookup table holding the high order bytes
01 01 01 01 00 01 01 0x01, 0x01, 0x01, 0x01, 0x01, of the addresses of the subroutines for
0x01, 0x01, 0x00, 0x01, 0x01 Chip-8 instruction groups 1 through F
0061 7C 75 83 88 95 B4 87 DB 0x7C, 0x75, 0x83, 0x88, 0x95, Table holding the low bytes for the
BC 91 EB A4 D9 70 99 0xB4, 0x87, 0xBC, 0x91, 0xEB, subroutines selected by the first digit of
05 0xA4, 0xD9, 0x70, 0x99, 0x05 Chip-8 instructions. So the completed
addresses for each digit are:
0x1: 0x017C
0x2: 0x0175
0x3: 0x0183
0x4: 0x018B
0x5: 0x0195
0x6: 0x01B4
0x7: 0x01B7
0x8: 0x01BC
0x9: 0x0191
0xA: 0x01EB
0xB: 0x01A4
0xC: 0x01D9
0xD: 0x0070
0xE: 0x0199
0xF: 0x0105
0075 FA 3F ANI 0x3F Mask with 0x3F to save least significant six
bits (max value of X position is 63, which
requires only six bits)
0078 F6 SHR
0079 F6 SHR
007D FA 1F ANI 0x1F Mask with 0x1F to save the five least
significant bits (max value of Y position is
31, which requires only five bits)
0080 FE SHL
0081 FE SHL
0087 FA 0F ANI 0x0F Mask off the least significant hex digit. This
contains the number of bytes (rows) in the
sprite pattern
008B F8 D0 LDI 0xD0 0xD0 is the low order byte of the address of
the area of RAM set aside as a Chip-8 work
area. This will be used to assemble a two-
byte wide copy of the sprite with the sprite
data shifted to the correct offset for the
position at which the sprite will be displayed
0091 32 F3 BZ RESET_I_PTR Branch to the next stage if they are all done
0096 9E GHI E Get the bit offset for the first bit of sprite
data (this was saved in RE.1 earlier)
009C F6 SHR Shift right by 1 bit. his will move a zero into
the most significant bit, shift everything else
along and move the least significant bit into
the carry flag
009F 76 SHRC Shift with carry to the right by one bit. This
will move the discarded bit from the first
byte into the most significant bit position
and shift everything else along
00AE F8 D0 LDI 0xD0 0xD0 is the low order byte of the address of
the area of RAM set aside as a Chip-8 work
area. This is where the offset sprite has
been assembled
00BE 46 DISPLAY_LEF LDA 6 Get the lefthand byte of sprite data and
T_BYTE: advance the pointer
00D7 3B B3 BNF SPRITE_DISPLAY_LOOP Only display the next row if it is not off the
bottom of the screen. This will be indicated
because adding 0x08 to the display RAM
address will cross a page boundary and
generate a carry condition
00D9 F8 FF SAVE_COLLI LDI 0xFF 0xFF is the low order byte of the address of
SION_FLAG: variable F, where the collision flag will be
stored
00E2 F8 FF LDI 0xFF ... so that RF now points to the final byte in
the display page
0100 00 00 00 00 00 DB 0x00, 0x00, 0x00, 0x00, 0x00 Filler at start of next page
010A F8 81 FX0A: LDI 0x81 Instruction FX0A -> wait for a key press and
store it in VX
0x81 is the high-order byte of the address
of a routine in the COSMAC VIP ROM that
reads the keyboard
011B 64 0A 01 BCD_DENOM DB 0x64, 0x0A, 0x01 Three constants with the decimal values of
INATORS: 100, 10 and 1, used by the BCD instruction
FX33
0121 AA PLO A Put result back into low order byte of I (RA.
0)
0129 F8 81 FX29: LDI 0x81 Instruction FX29 -> Point I to sprite for
hexadecimal character in VX
Both the look up table and the sprite data
are located in the ROM in page 0x81
0131 AA PLO A I now points to the start of the data for the
correct sprite
0138 F8 1B LDI BCD_DENOMINATORS Get the low order byte of the address of the
BCD denominator constants
0142 3B 4B BNF NEXT_DIGIT: If the result is negative then the current digit
is at the correct value, so move on to the
next one
014B 4E NEXT_DIGIT: LDA E Get current BCD constant and point to next
one
014D 3B 3C BNF BCD_LOOP If it's not set (i.e. the constant we just using
was not 0x01) then loop back and do the
next digit
0152 2A DEC A
0156 86 GLO 6 Get the low order byte of the VX pointer ...
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
0161 3A 5B BNZ STORE_VARS_LOOP Return to top of loop if there are still more
variables to store
0166 86 GLO 6 Get the low order byte of the VX pointer ...
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
Compiled by Laurence Scotford 2013 ! ! ! ! Page 26 of 40! !
Address Code Labels Assembler Comments
0171 3A 6B BNZ LOAD_VARS_LOOP Return to top of loop if there are still more
variables to load
017C 45 1MMM: LDA 5 This is the entry point for the handler for
group 1MMM instructions: Branch to
instruction at address 0x0MMM
Get the low-order byte of the current
instruction
0181 B5 PHI 5 Load this into the high order byte of the
Chip-8 programme counter (this now points
to the first instruction of the subroutine/
sequence to be branched to)
0183 45 3XNN: LDA 5 This is the entry point for the 3XNN
instruction group (Skip if VX = NN)
On entry the Chip-8 programme counter
(R5) will be pointing to the second byte of
the instruction, which contains the value to
be compared. This is loaded into the
accumulator before the programme counter
is advanced to point to the next Chip-8
instruction
0184 E6 TEST_FOR_E SEX 6 The VX pointer (R6) will now be used for
QUALITY: register indirect addressing operations
018B 45 4XNN: LDA 5 This is the entry point for the 4XNN
instruction group (Skip if VX ≠ NN)
On entry the Chip-8 programme counter
(R5) will be pointing to the second byte of
the instruction, which contains the value NN
to be compared. This is loaded into the
accumulator before the programme counter
is advanced to point to the next Chip-8
instruction
018C E6 TEST_FOR_I SEX 6 The VX pointer (R6) will now be used for
NEQUALITY: register indirect addressing operations
0191 45 9XY0: LDA 5 This is the entry point for the 9XY0
instruction group (Skip if VX ≠ VY)
The LDA 5 instruction used here simply
moves the programme counter on to the
next instruction, since the value stored in D
is not used. It's not clear why the
programmer chose to use an LDA rather
than an INC instruction here
0195 45 5XY0: LDA 5 This is the entry point for the 5XY0
instruction group (Skip if VX = VY)
Moves the programme counter on to the
next instruction. See comment for the
instruction at 0x0191
0199 E6 EX9E/EXA1: SEX 6 This is the entry point for instruction groups
EX9E (Skip if VX = current key press) and
EXA1 (Skip if VX ≠ current key press)
The VX pointer (R6) will now be used for
register indirect addressing
01AC FA 0F ANI 0x0F We just need to use a mask to set the most
significant digit to 0x0
01B2 B5 STORE_HIGH PHI 5 Load the high order byte of the address into
_ORDER_BY the Chip-8 programme counter
TE:
01BD FA 0F ANI 0x0F Mask the byte to save just the second hex
digit
01C8 73 STXD Push this onto the stack and decrement the
stack pointer
01D6 7E SHLC Move the carry flag into the least significant
bit of the accumulator
01E2 76 SHRC Shift the result one bit to the right. This will
effectively divide the full result of the
addition by 2 as it takes into account the
carry bit generated by the addition