diff --git a/src/machine/cpu.odin b/src/machine/cpu.odin index a024317..5fea854 100644 --- a/src/machine/cpu.odin +++ b/src/machine/cpu.odin @@ -5,6 +5,7 @@ import "core:math/rand" import "base:intrinsics" // CPU.odin -> instructions, fetch, decode, execute, run loop +// ---------------------------------------------------------- cycle :: proc(s: ^System) { // Fetch @@ -273,20 +274,20 @@ op_ld_dt :: proc(s: ^System, vx_idx: u16) { // Fx0A - LD Vx, K op_get_key :: proc(s: ^System, vx_idx: u16) { - for val, kp_idx in s.keypad { - if val == true { - s.v[vx_idx] = u8(kp_idx) + if s.current_key != -1 { + key := s.current_key - // return here so it does not decrement + released := check_if_key_released(key) + if released { + s.v[vx_idx] = u8(key) + s.current_key = -1 return } } - // if loop does not return decrement go into loop s.pc -= 2 } - // Fx15 - LD DT, Vx op_set_dt :: proc(s: ^System, vx_idx: u16) { // set delay timer to value of x register @@ -333,3 +334,4 @@ op_mem_get :: proc(s: ^System, vx_idx: u16) { s.v[loop_idx] = s.memory[s.i + loop_idx] } } + diff --git a/src/machine/input.odin b/src/machine/input.odin index e21cec9..bb91802 100644 --- a/src/machine/input.odin +++ b/src/machine/input.odin @@ -1,3 +1,89 @@ package machine -// keypad mapping, input state update +import rl "vendor:raylib" + +// @IDEA: Maybe add controller support? + +// Input handling for CHIP-8 keypad (0x0-0xF) mapped to a standard keyboard. +// CHIP-8 uses a polling model, not hardware interrupts - we check key state each cycle. +// Standard CHIP-8 -> keyboard mapping: +// 1 2 3 C → 1 2 3 4 +// 4 5 6 D → Q W E R +// 7 8 9 E → A S D F +// A 0 B F → Z X C V + +handle_input :: proc(s: ^System) { + // Row 1 + s.keypad[0x1] = rl.IsKeyDown(.ONE) + s.keypad[0x2] = rl.IsKeyDown(.TWO) + s.keypad[0x3] = rl.IsKeyDown(.THREE) + s.keypad[0xC] = rl.IsKeyDown(.FOUR) + // Row 2 + s.keypad[0x4] = rl.IsKeyDown(.Q) + s.keypad[0x5] = rl.IsKeyDown(.W) + s.keypad[0x6] = rl.IsKeyDown(.E) + s.keypad[0xD] = rl.IsKeyDown(.R) + // Row 3 + s.keypad[0x7] = rl.IsKeyDown(.A) + s.keypad[0x8] = rl.IsKeyDown(.S) + s.keypad[0x9] = rl.IsKeyDown(.D) + s.keypad[0xE] = rl.IsKeyDown(.F) + // Row 4 + s.keypad[0xA] = rl.IsKeyDown(.Z) + s.keypad[0x0] = rl.IsKeyDown(.X) + s.keypad[0xB] = rl.IsKeyDown(.C) + s.keypad[0xF] = rl.IsKeyDown(.V) + + // Track the last pressed key as a CHIP-8 index (0x0-0xF). + // Used by Fx0A which blocks until a key is pressed AND released. + // current_key holds the index until release is confirmed, then resets to -1. + key := rl.GetKeyPressed() + + #partial switch key { + case .ONE: s.current_key = 0x1 + case .TWO: s.current_key = 0x2 + case .THREE: s.current_key = 0x3 + case .FOUR: s.current_key = 0xC + case .Q: s.current_key = 0x4 + case .W: s.current_key = 0x5 + case .E: s.current_key = 0x6 + case .R: s.current_key = 0xD + case .A: s.current_key = 0x7 + case .S: s.current_key = 0x8 + case .D: s.current_key = 0x9 + case .F: s.current_key = 0xE + case .Z: s.current_key = 0xA + case .X: s.current_key = 0x0 + case .C: s.current_key = 0xB + case .V: s.current_key = 0xF + } +} + +// Returns true only when the tracked key is released. +// Used by Fx0A to check for a press-and-release. +check_if_key_released :: proc(key: i16) -> bool { + return rl.IsKeyReleased(chip8_key_to_raylib(key)) +} + +// Maps a CHIP-8 key index (0x0-0xF) back to its Raylib equivalent. +chip8_key_to_raylib :: proc(key: i16) -> rl.KeyboardKey { + switch key { + case 0x1: return .ONE + case 0x2: return .TWO + case 0x3: return .THREE + case 0xC: return .FOUR + case 0x4: return .Q + case 0x5: return .W + case 0x6: return .E + case 0xD: return .R + case 0x7: return .A + case 0x8: return .S + case 0x9: return .D + case 0xE: return .F + case 0xA: return .Z + case 0x0: return .X + case 0xB: return .C + case 0xF: return .V + case: return .KEY_NULL + } +} diff --git a/src/machine/machine.odin b/src/machine/machine.odin index 376d87d..69a926c 100644 --- a/src/machine/machine.odin +++ b/src/machine/machine.odin @@ -19,7 +19,11 @@ System :: struct { pc: u16, // 64x32-pixel monochrome display display: [32][64]u8, + // Keypad keypad: [16]bool, + // -1 = no key pressed, 0-15 = key index + current_key: i16, + // Timers delay_timer: u8, sound_timer: u8, }