diff --git a/src/dchip8.cpp b/src/dchip8.cpp index 0ed1b9f..09f3bf8 100644 --- a/src/dchip8.cpp +++ b/src/dchip8.cpp @@ -15,6 +15,11 @@ enum Chip8State chip8state_off, }; +typedef struct Chip8Controller +{ + bool key[0x10]; +} Chip8Controller; + typedef struct Chip8CPU { const u16 INIT_ADDRESS = 0x200; @@ -66,7 +71,9 @@ typedef struct Chip8CPU u8 stackPointer; u16 stack[16]; - u8 keyToStoreToRegisterIndex; + // Metadata + u8 storeKeyToRegisterIndex; + f32 elapsedTime; enum Chip8State state; } Chip8CPU; @@ -267,6 +274,45 @@ FILE_SCOPE void dchip8_init_display(PlatformRenderBuffer renderBuffer) } } +FILE_SCOPE Chip8Controller dchip8_controller_map_input(PlatformInput input) +{ + // NOTE: Chip8 Hex Controller to Keyboard Mapping + // Keypad Keyboard + // +-+-+-+-+ +-+-+-+-+ + // |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| + // +-+-+-+-+ +-+-+-+-+ + + Chip8Controller result = {}; + + result.key[0x01] = input.key_1.isDown; + result.key[0x02] = input.key_2.isDown; + result.key[0x03] = input.key_3.isDown; + result.key[0x0C] = input.key_4.isDown; + + result.key[0x04] = input.key_q.isDown; + result.key[0x05] = input.key_w.isDown; + result.key[0x06] = input.key_e.isDown; + result.key[0x0D] = input.key_r.isDown; + + result.key[0x07] = input.key_a.isDown; + result.key[0x08] = input.key_s.isDown; + result.key[0x09] = input.key_d.isDown; + result.key[0x0E] = input.key_f.isDown; + + result.key[0x0A] = input.key_z.isDown; + result.key[0x00] = input.key_x.isDown; + result.key[0x0B] = input.key_c.isDown; + result.key[0x0F] = input.key_v.isDown; + + return result; +} + void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input, PlatformMemory memory) { @@ -275,7 +321,8 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input, DQNT_ASSERT(renderBuffer.bytesPerPixel == 4); DQNT_ASSERT(memory.permanentMemSize == 4096); - u8 *mainMem = (u8 *)memory.permanentMem; + u8 *mainMem = (u8 *)memory.permanentMem; + Chip8Controller controller = dchip8_controller_map_input(input); if (cpu.state == chip8state_init) { dchip8_init_cpu(&cpu); @@ -283,7 +330,6 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input, dchip8_init_display(renderBuffer); } -#if 1 if (cpu.state == chip8state_load_file) { PlatformFile file = {}; @@ -305,31 +351,27 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input, platform_close_file(&file); } } -#endif if (cpu.state == chip8state_await_input) { - const u32 OFFSET_TO_CHIP_CONTROLS = key_7; - for (i32 i = OFFSET_TO_CHIP_CONTROLS; i < DQNT_ARRAY_COUNT(input.key); - i++) + for (i32 keyVal = 0; keyVal < DQNT_ARRAY_COUNT(controller.key); keyVal++) { - KeyState checkKey = input.key[i]; - if (checkKey.isDown) + if (controller.key[keyVal]) { - u8 regIndex = cpu.keyToStoreToRegisterIndex; - u8 keyVal = (u8)i - OFFSET_TO_CHIP_CONTROLS; - DQNT_ASSERT(keyVal >= 0 && keyVal <= 0x0F); + u8 regIndex = cpu.storeKeyToRegisterIndex; + DQNT_ASSERT(keyVal >= 0 && keyVal < 0x0F); - cpu.registerArray[regIndex] = keyVal; + cpu.registerArray[regIndex] = (u8)keyVal; cpu.state = chip8state_running; + break; } } } if (cpu.state == chip8state_running) { - u8 opHighByte = mainMem[cpu.programCounter++]; - u8 opLowByte = mainMem[cpu.programCounter++]; + u8 opHighByte = mainMem[cpu.programCounter++]; + u8 opLowByte = mainMem[cpu.programCounter++]; u8 opFirstNibble = (opHighByte & 0xF0); switch (opFirstNibble) @@ -655,26 +697,21 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input, DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray)); u8 vx = cpu.registerArray[regNum]; DQNT_ASSERT(vx >= 0 && vx <= 0x0F); + DQNT_ASSERT(vx < DQNT_ARRAY_COUNT(controller.key)); - const u32 KEY_OFFSET_TO_START_CONTROLS = key_7; - DQNT_ASSERT((KEY_OFFSET_TO_START_CONTROLS + vx) < - DQNT_ARRAY_COUNT(input.key)); - - KeyState checkKey = - input.key[KEY_OFFSET_TO_START_CONTROLS + vx]; bool skipNextInstruction = false; // SKP Vx - Ex9E - Skip next instruction if key with the value // of Vx is pressed if (opLowByte == 0x9E) { - skipNextInstruction = checkKey.isDown; + skipNextInstruction = controller.key[vx]; } // SKNP Vx - ExA1 - Skip next instruction if key with the value // of Vx is not pressed else { DQNT_ASSERT(opLowByte == 0xA1); - skipNextInstruction = !checkKey.isDown; + skipNextInstruction = !controller.key[vx]; } if (skipNextInstruction) cpu.programCounter += 2; @@ -696,8 +733,8 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input, // the key in Vx else if (opLowByte == 0x0A) { - cpu.state = chip8state_await_input; - cpu.keyToStoreToRegisterIndex = regNum; + cpu.state = chip8state_await_input; + cpu.storeKeyToRegisterIndex = regNum; } // LD DT, Vx - Fx15 - Set delay timer = Vx else if (opLowByte == 0x15) @@ -770,10 +807,27 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input, break; }; - if (cpu.delayTimer > 0) cpu.delayTimer--; + // IMPORTANT: Timers need to be decremented at a rate of 60hz. Since we + // can run the interpreter faster than that, make sure we decrement + // timers at the fixed rate. + if (cpu.delayTimer > 0 || cpu.soundTimer > 0) + { + cpu.elapsedTime += input.deltaForFrame; + f32 TIMER_DECREMENT_INTERVAL = 1 / 60.0f; - // TODO(doyle): This needs to play a buzzing sound whilst timer > 0 - if (cpu.soundTimer > 0) cpu.soundTimer--; + if (cpu.elapsedTime >= TIMER_DECREMENT_INTERVAL) + { + cpu.elapsedTime = 0; + if (cpu.delayTimer > 0) cpu.delayTimer--; + // TODO(doyle): This needs to play a buzzing sound whilst timer + // > 0 + if (cpu.soundTimer > 0) cpu.soundTimer--; + } + } + else + { + cpu.elapsedTime = 0; + } } } diff --git a/src/dchip8_platform.h b/src/dchip8_platform.h index 4b6df8d..abe5ea1 100644 --- a/src/dchip8_platform.h +++ b/src/dchip8_platform.h @@ -21,25 +21,25 @@ enum Key key_right, key_escape, - key_7, - key_8, - key_9, - key_0, + key_1, + key_2, + key_3, + key_4, - key_U, - key_I, - key_O, - key_P, + key_q, + key_w, + key_e, + key_r, - key_J, - key_K, - key_L, - key_colon, + key_a, + key_s, + key_d, + key_f, - key_M, - key_comma, - key_dot, - key_forward_slash, + key_z, + key_x, + key_c, + key_v, key_count, }; @@ -64,25 +64,25 @@ typedef struct PlatformInput KeyState right; KeyState escape; - KeyState key_7; - KeyState key_8; - KeyState key_9; - KeyState key_0; + KeyState key_1; + KeyState key_2; + KeyState key_3; + KeyState key_4; - KeyState key_U; - KeyState key_I; - KeyState key_O; - KeyState key_P; + KeyState key_q; + KeyState key_w; + KeyState key_e; + KeyState key_r; - KeyState key_J; - KeyState key_K; - KeyState key_L; - KeyState key_colon; + KeyState key_a; + KeyState key_s; + KeyState key_d; + KeyState key_f; - KeyState key_M; - KeyState key_comma; - KeyState key_dot; - KeyState key_forward_slash; + KeyState key_z; + KeyState key_x; + KeyState key_c; + KeyState key_v; }; }; } PlatformInput; diff --git a/src/win32_dchip8.cpp b/src/win32_dchip8.cpp index 1f78468..e90a6d2 100644 --- a/src/win32_dchip8.cpp +++ b/src/win32_dchip8.cpp @@ -117,7 +117,7 @@ inline FILE_SCOPE LARGE_INTEGER win32_query_perf_counter_time() FILE_SCOPE inline void win32_parse_key_msg(KeyState *key, MSG msg) { - WPARAM lParam = msg.lParam; + LPARAM lParam = msg.lParam; bool keyIsDown = ((lParam >> 30) & 1); bool keyTransitioned = ((lParam >> 31) & 1); @@ -144,25 +144,25 @@ FILE_SCOPE void win32_process_messages(HWND window, PlatformInput *input) case VK_LEFT: win32_parse_key_msg(&input->left, msg); break; case VK_RIGHT: win32_parse_key_msg(&input->right, msg); break; - case '7': win32_parse_key_msg(&input->key_7, msg); break; - case '8': win32_parse_key_msg(&input->key_8, msg); break; - case '9': win32_parse_key_msg(&input->key_9, msg); break; - case '0': win32_parse_key_msg(&input->key_0, msg); break; + case '1': win32_parse_key_msg(&input->key_1, msg); break; + case '2': win32_parse_key_msg(&input->key_2, msg); break; + case '3': win32_parse_key_msg(&input->key_3, msg); break; + case '4': win32_parse_key_msg(&input->key_4, msg); break; - case 'U': win32_parse_key_msg(&input->key_U, msg); break; - case 'I': win32_parse_key_msg(&input->key_I, msg); break; - case 'O': win32_parse_key_msg(&input->key_O, msg); break; - case 'P': win32_parse_key_msg(&input->key_P, msg); break; + case 'Q': win32_parse_key_msg(&input->key_q, msg); break; + case 'W': win32_parse_key_msg(&input->key_w, msg); break; + case 'E': win32_parse_key_msg(&input->key_e, msg); break; + case 'R': win32_parse_key_msg(&input->key_r, msg); break; - case 'J': win32_parse_key_msg(&input->key_J, msg); break; - case 'K': win32_parse_key_msg(&input->key_K, msg); break; - case 'L': win32_parse_key_msg(&input->key_L, msg); break; - case ';': win32_parse_key_msg(&input->key_colon, msg); break; + case 'A': win32_parse_key_msg(&input->key_a, msg); break; + case 'S': win32_parse_key_msg(&input->key_s, msg); break; + case 'D': win32_parse_key_msg(&input->key_d, msg); break; + case 'F': win32_parse_key_msg(&input->key_f, msg); break; - case 'M': win32_parse_key_msg(&input->key_M, msg); break; - case ',': win32_parse_key_msg(&input->key_comma, msg); break; - case '.': win32_parse_key_msg(&input->key_dot, msg); break; - case '/': win32_parse_key_msg(&input->key_forward_slash, msg); break; + case 'Z': win32_parse_key_msg(&input->key_z, msg); break; + case 'X': win32_parse_key_msg(&input->key_x, msg); break; + case 'C': win32_parse_key_msg(&input->key_c, msg); break; + case 'V': win32_parse_key_msg(&input->key_v, msg); break; case VK_ESCAPE: { @@ -279,7 +279,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, platformMemory.permanentMemSize = DQNT_ARRAY_COUNT(stackMemory); QueryPerformanceFrequency(&globalQueryPerformanceFrequency); - const f32 TARGET_FRAMES_PER_S = 180.0f; + const f32 TARGET_FRAMES_PER_S = 540.0f; f32 targetSecondsPerFrame = 1 / TARGET_FRAMES_PER_S; f32 frameTimeInS = 0.0f; globalRunning = true;