diff --git a/NES Emulator/CMakeLists.txt b/NES Emulator/CMakeLists.txt index 90ddbd8..550b3df 100644 --- a/NES Emulator/CMakeLists.txt +++ b/NES Emulator/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 3.8) -add_executable (nesemu "main.c" "bus.c" "cpu.c" "cartridge.c" "opcodes.c" "log.c" "ppu.c" "mappers/mapper000.c" "mapper.c") +add_executable (nesemu "main.c" "bus.c" "cpu.c" "cartridge.c" "opcodes.c" "log.c" "ppu.c" "mappers/mapper000.c" "mapper.c" "controller.c") target_include_directories(nesemu PUBLIC ${SDL2_INCLUDE_DIRS}) target_link_libraries(nesemu PUBLIC ${SDL2_LIBRARIES}) diff --git a/NES Emulator/bus.c b/NES Emulator/bus.c index 8bf3c9b..afe7fe3 100644 --- a/NES Emulator/bus.c +++ b/NES Emulator/bus.c @@ -74,7 +74,12 @@ Byte readBus(struct Bus* bus, Word addr) } else if (0x4000 <= addr && addr <= 0x4017) // I/O space { - val = bus->io[addr - 0x4000]; + switch (addr) + { + case 0x4016: + val = pollInput(&bus->controller); + break; + } } else if (0x4020 <= addr && addr <= 0xFFFF) // Cartridge space { @@ -102,7 +107,14 @@ void writeBus(struct Bus* bus, Word addr, Byte val) } else if (0x4000 <= addr && addr <= 0x4017) // I/O space { - bus->io[addr - 0x4000] = val; + switch (addr) + { + case 0x4016: + bus->controller.strobe = (val & 0x1); + if (val & 0x1) + fillRegister(&bus->controller); + break; + } } else if (0x4020 <= addr && addr <= 0xFFFF) // Cartridge space { diff --git a/NES Emulator/bus.h b/NES Emulator/bus.h index 219edcd..6c1ac43 100644 --- a/NES Emulator/bus.h +++ b/NES Emulator/bus.h @@ -2,12 +2,15 @@ #define _BUS_H_ #include "types.h" +#include "controller.h" + #include struct CPU; struct PPU; struct Cartridge; + // Main communication path for devices and memory in the NES struct Bus { @@ -17,6 +20,7 @@ struct Bus struct CPU* cpu; struct PPU* ppu; struct Cartridge* cartridge; + struct Controller controller; Byte masterClockTimer; diff --git a/NES Emulator/controller.c b/NES Emulator/controller.c new file mode 100644 index 0000000..57e05b2 --- /dev/null +++ b/NES Emulator/controller.c @@ -0,0 +1,30 @@ +#include "controller.h" +#include + +Byte pollInput(struct Controller* controller) +{ + if (controller->strobe) + { + fillRegister(controller); + } + + Byte ret = 0x1 - (controller->latch & 0x1); // Controller port is active low + controller->latch >>= 1; + return ret; +} + +void fillRegister(struct Controller* controller) +{ + Byte* keyboard = SDL_GetKeyboardState(NULL); + + controller->data.A = keyboard[SDL_SCANCODE_A]; + controller->data.B = keyboard[SDL_SCANCODE_S]; + controller->data.Up = keyboard[SDL_SCANCODE_UP]; + controller->data.Down = keyboard[SDL_SCANCODE_DOWN]; + controller->data.Left = keyboard[SDL_SCANCODE_LEFT]; + controller->data.Right = keyboard[SDL_SCANCODE_RIGHT]; + controller->data.Select = keyboard[SDL_SCANCODE_LSHIFT]; + controller->data.Start = keyboard[SDL_SCANCODE_RETURN]; + + controller->latch = controller->data.raw; +} diff --git a/NES Emulator/controller.h b/NES Emulator/controller.h new file mode 100644 index 0000000..513387d --- /dev/null +++ b/NES Emulator/controller.h @@ -0,0 +1,32 @@ +#ifndef _CONTROLLER_H_ +#define _CONTROLLER_H_ + +#include "types.h" + +struct Controller +{ + union + { + struct + { + Byte A : 1; + Byte B : 1; + Byte Select : 1; + Byte Start : 1; + Byte Up : 1; + Byte Down : 1; + Byte Left : 1; + Byte Right : 1; + }; + + Byte raw; + } data; + + Byte strobe; + Byte latch; +}; + +Byte pollInput(struct Controller* controller); +void fillRegister(struct Controller* controller); + +#endif // _CONTROLLER_H_ \ No newline at end of file diff --git a/NES Emulator/cpu.c b/NES Emulator/cpu.c index 4475aad..320a78f 100644 --- a/NES Emulator/cpu.c +++ b/NES Emulator/cpu.c @@ -68,7 +68,7 @@ int tickCPU(struct CPU* cpu) cpu->nmi = 0; - printf("NMI TRIGGERED FROM $%04x\n", cpu->pc.word); + // printf("NMI TRIGGERED FROM $%04x\n", cpu->pc.word); cpu->pc.lo = readBus(cpu->bus, 0xFFFA); cpu->pc.hi = readBus(cpu->bus, 0xFFFB); @@ -225,7 +225,7 @@ void prepareFetch(struct CPU* cpu) void fetch(struct CPU* cpu) { - if(cpu->currentOpcode->addr != IMP) + if(cpu->currentOpcode->addr != IMP && cpu->currentOpcode->addr != ACC) cpu->fetchedVal = readBus(cpu->bus, cpu->fetchedAddress); }