From f6e339105abacb963c114a30bcb4ed668a60325e Mon Sep 17 00:00:00 2001 From: Austin Morlan Date: Wed, 11 Sep 2019 16:20:30 -0700 Subject: [PATCH] Input --- CMakeLists.txt | 1 + Source/Input.cpp | 40 +++++++++++++++++++ Source/Input.hpp | 32 ++++++++++++++++ Source/NES.cpp | 31 ++++++++++++++- Source/NES.hpp | 2 + Source/Platform.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++- Source/Platform.hpp | 3 +- 7 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 Source/Input.cpp create mode 100644 Source/Input.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ab432ba..f9f50e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ target_sources( Source/CPU/CPU.cpp Source/CPU/AddressModes.cpp Source/CPU/Instructions.cpp + Source/Input.cpp Source/NES.cpp Source/Platform.cpp Source/PPU/PPU.cpp diff --git a/Source/Input.cpp b/Source/Input.cpp new file mode 100644 index 0000000..b561a71 --- /dev/null +++ b/Source/Input.cpp @@ -0,0 +1,40 @@ +#include "Input.hpp" + + +void Input::Strobe(uint8_t* but) +{ + if (strobe) + { + for (int i = 0; i < 8; ++i) + { + buttons[i] = but[i]; + } + } +} + +uint8_t Input::Poll() +{ + uint8_t buttonState; + + // Strobe set - return state of A button + if (strobe) + { + buttonState = buttons[Buttons::A]; + } + + // All 8 bits read - return 1u + else if (buttonIndex > Buttons::Right) + { + buttonState = 1u; + } + + // Return next bit + else + { + buttonState = buttons[buttonIndex]; + + ++buttonIndex; + } + + return buttonState; +} diff --git a/Source/Input.hpp b/Source/Input.hpp new file mode 100644 index 0000000..cd20f99 --- /dev/null +++ b/Source/Input.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + + +enum Buttons +{ + A = 0, + B = 1, + Select = 2, + Start = 3, + Up = 4, + Down = 5, + Left = 6, + Right = 7 +}; + + +class Input +{ +public: + void Strobe(uint8_t* but); + uint8_t Poll(); + +private: + friend class NES; + + bool strobe{}; + uint8_t buttonIndex{}; + uint8_t buttons[8]{}; +}; diff --git a/Source/NES.cpp b/Source/NES.cpp index 155eeb5..744dd6e 100644 --- a/Source/NES.cpp +++ b/Source/NES.cpp @@ -44,7 +44,8 @@ NES::NES() : cpu(std::make_unique()), ppu(std::make_unique()), cartridge(std::make_unique()), - platform(std::make_unique("NES", WINDOW_WIDTH, WINDOW_HEIGHT, VIDEO_WIDTH, VIDEO_HEIGHT)) + platform(std::make_unique("NES", WINDOW_WIDTH, WINDOW_HEIGHT, VIDEO_WIDTH, VIDEO_HEIGHT)), + input(std::make_unique()) { ppu->nes = this; @@ -123,10 +124,14 @@ void NES::InsertCartridge(char const* filename) void NES::Run() { - while (!platform->ProcessInput()) + uint8_t buttons[8]{}; + + while (!platform->ProcessInput(buttons)) { cpu->Cycle(); + input->Strobe(buttons); + uint8_t cpuCyclesTaken = (cpu->cycles - cpu->prevCycles) * 3u; ppu->Cycle(cpuCyclesTaken); @@ -166,6 +171,7 @@ void NES::Write(BusSource source, uint16_t address, uint8_t value) { uint16_t index = address & 0x1Fu; + // PPU OAM if (index == 0x14u) { uint8_t addrMsb = value; @@ -177,6 +183,20 @@ void NES::Write(BusSource source, uint16_t address, uint8_t value) ppu->oam[ppu->oamAddr + addrLsb] = Read(BusSource::CPU, addr); } } + + // Controller + else if (index == 0x16u) + { + if (value & 0x1u) + { + input->strobe = true; + } + else + { + input->strobe = false; + input->buttonIndex = 0u; + } + } } // Expansion I/O @@ -253,6 +273,13 @@ uint8_t NES::Read(BusSource source, uint16_t address) // APU and IO else if (address < 0x4020u) { + uint16_t index = address & 0x1Fu; + + // Controller + if (index == 0x16u) + { + byte = input->Poll(); + } } // Expansion I/O diff --git a/Source/NES.hpp b/Source/NES.hpp index 3924826..a4a6f7f 100644 --- a/Source/NES.hpp +++ b/Source/NES.hpp @@ -2,6 +2,7 @@ #include "Cartridge.hpp" #include "CPU/CPU.hpp" +#include "Input.hpp" #include "Platform.hpp" #include "PPU/PPU.hpp" #include @@ -45,6 +46,7 @@ public: std::unique_ptr ppu; std::unique_ptr cartridge; std::unique_ptr platform; + std::unique_ptr input; bool nmi{}; Color palette[64]; diff --git a/Source/Platform.cpp b/Source/Platform.cpp index 2ca9506..1edd7d4 100644 --- a/Source/Platform.cpp +++ b/Source/Platform.cpp @@ -1,4 +1,5 @@ #include "Platform.hpp" +#include "Input.hpp" #include @@ -30,7 +31,7 @@ void Platform::Update(void const* buffer, int pitch) SDL_RenderPresent(renderer); } -bool Platform::ProcessInput() +bool Platform::ProcessInput(uint8_t* buttons) { bool quit = false; @@ -55,6 +56,95 @@ bool Platform::ProcessInput() quit = true; break; } + case SDLK_UP: + { + {buttons[Buttons::Up] = 1u;} + break; + } + case SDLK_DOWN: + { + {buttons[Buttons::Down] = 1u;} + break; + } + case SDLK_LEFT: + { + {buttons[Buttons::Left] = 1u;} + break; + } + case SDLK_RIGHT: + { + {buttons[Buttons::Right] = 1u;} + break; + } + case SDLK_LSHIFT: + { + buttons[Buttons::Select] = 1u; + break; + } + case SDLK_RETURN: + { + {buttons[Buttons::Start] = 1u;} + break; + } + case SDLK_z: + { + {buttons[Buttons::A] = 1u;} + break; + } + case SDLK_x: + { + {buttons[Buttons::B] = 1u;} + break; + } + } + + break; + } + + case SDL_KEYUP: + { + switch (event.key.keysym.sym) + { + case SDLK_UP: + { + {buttons[Buttons::Up] = 0u;} + break; + } + case SDLK_DOWN: + { + {buttons[Buttons::Down] = 0u;} + break; + } + case SDLK_LEFT: + { + {buttons[Buttons::Left] = 0u;} + break; + } + case SDLK_RIGHT: + { + {buttons[Buttons::Right] = 0u;} + break; + } + case SDLK_LSHIFT: + { + {buttons[Buttons::Select] = 0u;} + break; + } + case SDLK_RETURN: + { + {buttons[Buttons::Start] = 0u;} + break; + } + case SDLK_z: + { + {buttons[Buttons::A] = 0u;} + break; + } + case SDLK_x: + { + {buttons[Buttons::B] = 0u;} + break; + } } break; @@ -62,5 +152,6 @@ bool Platform::ProcessInput() } } + return quit; } diff --git a/Source/Platform.hpp b/Source/Platform.hpp index 768a2d7..e94945c 100644 --- a/Source/Platform.hpp +++ b/Source/Platform.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include "Input.hpp" class SDL_Window; @@ -14,7 +15,7 @@ public: Platform(char const* title, int windowWidth, int windowHeight, int textureWidth, int textureHeight); ~Platform(); void Update(void const* buffer, int pitch); - bool ProcessInput(); + bool ProcessInput(uint8_t* buttons); SDL_Window* window{}; SDL_Renderer* renderer{};