From bba46296b1324fd97e8526e84b3e3087cb0828ac Mon Sep 17 00:00:00 2001 From: Pablo Rodriguez Date: Sat, 15 Mar 2025 01:58:27 -0400 Subject: [PATCH] implemented keypad --- CMakeLists.txt | 2 +- Interpreter.cpp | 26 +++++++++++++++++++++++++- KeypadSDL.cpp | 36 ++++++++++++++++++++++++++++++++++++ KeypadSDL.hpp | 12 ++++++++++++ Peripherals.hpp | 7 ++++--- main.cpp | 13 +++++-------- 6 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 KeypadSDL.cpp create mode 100644 KeypadSDL.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 39ff7f8..ac6e774 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,5 +5,5 @@ SET(CMAKE_BUILD_TYPE Debug) add_subdirectory(submodules/sdl2) SET(CMAKE_EXPORT_COMPILE_COMMANDS ON) -add_executable(chocochip8 main.cpp Interpreter.cpp DisplaySDL.cpp BuzzerSDL.cpp CountdownTimerSDL.cpp) +add_executable(chocochip8 main.cpp Interpreter.cpp DisplaySDL.cpp BuzzerSDL.cpp CountdownTimerSDL.cpp KeypadSDL.cpp) target_link_libraries(chocochip8 SDL2::SDL2-static) diff --git a/Interpreter.cpp b/Interpreter.cpp index 248ccdd..eaa7173 100644 --- a/Interpreter.cpp +++ b/Interpreter.cpp @@ -139,13 +139,37 @@ void Interpreter::tick() { case 0xD000: // DXYN - draw executeDraw(mvReg[iRegDst], mvReg[iRegSrc], opcode); break; - case 0xE000: // EX9E, EXA1 - keypad access + case 0xE000: // keypad access + switch(inst & 0xF0FF) { + case 0xE09E: // EX9E - skip if key pressed + if(mrKeypad.isKeyPressed(mvReg[iRegDst])) { + mvSpecialReg[SR_PC] += 2; + } + break; + case 0xE0A1: // EXA1 - skip if key not pressed + if(!mrKeypad.isKeyPressed(mvReg[iRegDst])) { + mvSpecialReg[SR_PC] += 2; + } + break; + default: + throw std::invalid_argument("not implemented"); + break; + } break; case 0xF000: // several unique instructions switch(inst & 0xF0FF) { case 0xF007: // FX07 - read timer register mvReg[iRegDst] = mrDelayTimer.get(); break; + case 0xF00A: // FX0A - wait for a keypress + mvSpecialReg[SR_PC] -= 2; + for(int i = KEY_0; i < KEY_0 + KEY_COUNT; i++) { + if(mrKeypad.isKeyPressed(i)) { + mvSpecialReg[SR_PC] += 2; + break; + } + } + break; case 0xF015: // FX15 - set timer register mrDelayTimer.set(mvReg[iRegDst]); break; diff --git a/KeypadSDL.cpp b/KeypadSDL.cpp new file mode 100644 index 0000000..9353880 --- /dev/null +++ b/KeypadSDL.cpp @@ -0,0 +1,36 @@ +#include "KeypadSDL.hpp" + +bool KeypadSDL::isKeyPressed(int key) const { + return mvKeyDown.at(key); +} + +void KeypadSDL::processEvent(SDL_Event &e) { + auto keymap = [](int sdlKeyCode) -> int { + switch(sdlKeyCode) { + case SDLK_1: return chocochip8::KEY_1; + case SDLK_2: return chocochip8::KEY_2; + case SDLK_3: return chocochip8::KEY_3; + case SDLK_4: return chocochip8::KEY_C; + case SDLK_q: return chocochip8::KEY_4; + case SDLK_w: return chocochip8::KEY_5; + case SDLK_e: return chocochip8::KEY_6; + case SDLK_r: return chocochip8::KEY_D; + case SDLK_a: return chocochip8::KEY_7; + case SDLK_s: return chocochip8::KEY_8; + case SDLK_d: return chocochip8::KEY_9; + case SDLK_f: return chocochip8::KEY_E; + case SDLK_z: return chocochip8::KEY_A; + case SDLK_x: return chocochip8::KEY_0; + case SDLK_c: return chocochip8::KEY_B; + case SDLK_v: return chocochip8::KEY_F; + default : return -1; + } + }; + + if(e.type == SDL_KEYUP || e.type == SDL_KEYDOWN) { + int k = keymap(e.key.keysym.sym); + if(k != -1) { + mvKeyDown[k] = (e.type == SDL_KEYDOWN); + } + } +} diff --git a/KeypadSDL.hpp b/KeypadSDL.hpp new file mode 100644 index 0000000..37ec9e0 --- /dev/null +++ b/KeypadSDL.hpp @@ -0,0 +1,12 @@ +#include "Peripherals.hpp" + +#include +#include + +class KeypadSDL : public chocochip8::Keypad { +public: + bool isKeyPressed(int key) const override; + void processEvent(SDL_Event &e); +private: + std::array mvKeyDown; +}; diff --git a/Peripherals.hpp b/Peripherals.hpp index 657e1d6..2d04ba6 100644 --- a/Peripherals.hpp +++ b/Peripherals.hpp @@ -8,11 +8,12 @@ namespace chocochip8 { constexpr size_t gcHeight = 64; using Scanline = std::bitset; - enum class Key { + enum { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_A, KEY_B, - KEY_C, KEY_D, KEY_E, KEY_F + KEY_C, KEY_D, KEY_E, KEY_F, + KEY_COUNT }; class Display { @@ -32,7 +33,7 @@ namespace chocochip8 { class Keypad { public: virtual ~Keypad() = default; - virtual bool isKeyPressed(Key key) = 0; + virtual bool isKeyPressed(int key) const = 0; }; class CountdownTimer { diff --git a/main.cpp b/main.cpp index 760fc9c..ca11992 100644 --- a/main.cpp +++ b/main.cpp @@ -8,9 +8,8 @@ #include "BuzzerSDL.hpp" #include "CountdownTimerSDL.hpp" #include "DisplaySDL.hpp" +#include "KeypadSDL.hpp" #include "Interpreter.hpp" -#include "Peripherals.hpp" -#include "SDL2/SDL_events.h" int main(int argc, char* argv[]) { if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { @@ -18,17 +17,13 @@ int main(int argc, char* argv[]) { return 1; } - class TestKeypad : public chocochip8::Keypad { - bool isKeyPressed(chocochip8::Key) override { return false; } - }; - BuzzerSDL buzzer(440); int N = 4; DisplaySDL display(128*N, 64*N); - TestKeypad keypad; + KeypadSDL keypad; CountdownTimerSDL delayTimer(60); CountdownTimerSDL soundTimer(60); - CountdownTimerSDL displayTimer(20); + CountdownTimerSDL displayTimer(60); chocochip8::Interpreter chip8(display, buzzer, keypad, delayTimer, soundTimer); auto rom = std::vector(); @@ -46,6 +41,8 @@ int main(int argc, char* argv[]) { while(SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) { done = true; + } else { + keypad.processEvent(event); } } chip8.tick();