diff --git a/src/machine/cpu.odin b/src/machine/cpu.odin index 498c836..aabfab7 100644 --- a/src/machine/cpu.odin +++ b/src/machine/cpu.odin @@ -31,19 +31,87 @@ cycle :: proc(s: ^System) { switch opcode { case 0x00E0: op_cls(s) } - case 0x1: op_jp_add(s) - case 0xD: log.info("D instruction a draw call!") + case 0x1: op_jp_add(s, opcode) + case 0x6: op_ld(s, opcode) + case 0x7: op_add(s, opcode) + case 0xA: op_set(s, opcode) + case 0xD: op_draw(s, opcode) } } +debug_opcode :: proc(opcode: u16) { + log.debugf("opcode: 0x%04X", opcode) +} + // Instruction procs // ----------------------------------- // CLS: Clear the display op_cls :: proc(s: ^System) { - log.info("found clear screen instruction, zero out display buffer") + // log.info("found clear screen instruction, zero out display buffer") + + // Odin lets you zero a fixed array with just: {} is the zero value, + // so it clears the entire buffer in one shot. + s.display = {} } // JP addr: Jump to location nnn -op_jp_add :: proc(s: ^System) { - log.info("found jump instruction, set pc to nnn") +op_jp_add :: proc(s: ^System, opcode: u16) { + addr := (opcode & 0x0FFF) + s.pc = addr +} + +// LD: Load value kk into x register +op_ld :: proc(s: ^System, opcode: u16) { + register := (opcode & 0x0F00) >> 8 + value := (opcode & 0x00FF) + + s.v[register] = u8(value) +} + +// ADD: Adds the value kk to the value of register Vx, then stores the result in Vx. +op_add :: proc(s: ^System, opcode: u16) { + register := (opcode & 0x0F00) >> 8 + value := (opcode & 0x00FF) + s.v[register] += u8(value) +} + +// SET: The value of register I is set to nnn. +op_set :: proc(s: ^System, opcode: u16) { + index_addr := (opcode & 0x0FFF) + s.i = index_addr +} + +// DRAW: Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision. +op_draw :: proc(s: ^System, opcode: u16) { + x_register := (opcode & 0x0F00) >> 8 + y_register := (opcode & 0x00F0) >> 4 + + // Handle wrapping + x_coord := (s.v[x_register] & 0x03F) + y_coord := (s.v[y_register] & 0x1F) + + s.v[0xF] = 0 + + n_bytes := (opcode & 0x000F) + + for row in 0..> u8(col) + + if sprite_row & mask != 0 { + // this bit is set Xor the pixel + y_pos := ((y_coord + u8(row)) % 32) + x_pos := ((x_coord + u8(col)) % 64) + + pixel := &s.display[y_pos][x_pos] + if pixel^ == 1 { + s.v[0xF] = 1 + } + pixel^ = pixel^ ~ 1 + } + } + } }