Skip to content

Commit

Permalink
Implement NES controller input polling
Browse files Browse the repository at this point in the history
  • Loading branch information
SirBob01 committed Oct 15, 2023
1 parent fd691ad commit 3d963f1
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 5 deletions.
75 changes: 75 additions & 0 deletions src/controller.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "./controller.h"

void create_controller(controller_t *controller) {
controller->joy[0] = 0;
controller->joy[1] = 0;

controller->shift[0] = 0;
controller->shift[1] = 0;

controller->strobe = false;
}

void destroy_controller(controller_t *controller) {}

void write_strobe_controller(controller_t *controller, unsigned char value) {
controller->strobe = value & 1;
if (controller->strobe) {
controller->shift[0] = controller->joy[0];
controller->shift[1] = controller->joy[1];
}
}

unsigned char read_joy1_controller(controller_t *controller) {
unsigned char result = controller->shift[0] & 1;
controller->shift[0] >>= 1;
controller->shift[0] |= 0x80;
return result;
}

unsigned char read_joy2_controller(controller_t *controller) {
unsigned char result = controller->shift[1] & 1;
controller->shift[1] >>= 1;
controller->shift[1] |= 0x80;
return result;
}

void set_joy1_controller(controller_t *controller,
bool a,
bool b,
bool select,
bool start,
bool up,
bool down,
bool left,
bool right) {
controller->joy[0] = 0;
controller->joy[0] |= a;
controller->joy[0] |= b << 1;
controller->joy[0] |= select << 2;
controller->joy[0] |= start << 3;
controller->joy[0] |= up << 4;
controller->joy[0] |= down << 5;
controller->joy[0] |= left << 6;
controller->joy[0] |= right << 7;
}

void set_joy2_controller(controller_t *controller,
bool a,
bool b,
bool select,
bool start,
bool up,
bool down,
bool left,
bool right) {
controller->joy[0] = 0;
controller->joy[1] |= a;
controller->joy[1] |= b << 1;
controller->joy[1] |= select << 2;
controller->joy[1] |= start << 3;
controller->joy[1] |= up << 4;
controller->joy[1] |= down << 5;
controller->joy[1] |= left << 6;
controller->joy[1] |= right << 7;
}
114 changes: 114 additions & 0 deletions src/controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#ifndef CONTROLLER_H
#define CONTROLLER_H

#include <stdbool.h>

/**
* @brief NES input controller state.
*
*/
typedef struct {
/**
* @brief Button states of the controllers.
*
*/
unsigned char joy[2];

/**
* @brief Shift registers for each controller.
*
*/
unsigned char shift[2];

/**
* @brief Flag that determines if the controller input should be polled.
*
*/
bool strobe;
} controller_t;

/**
* @brief Create a controller object.
*
* @param controller
*/
void create_controller(controller_t *controller);

/**
* @brief Destroy a controller object.
*
* @param controller
*/
void destroy_controller(controller_t *controller);

/**
* @brief Write to $4016.
*
* @param controller
* @param strobe
*/
void write_strobe_controller(controller_t *controller, unsigned char value);

/**
* @brief Read the button states of the first controller.
*
* @param controller
* @return unsigned char
*/
unsigned char read_joy1_controller(controller_t *controller);

/**
* @brief Read the button states of the second controller.
*
* @param controller
* @return unsigned char
*/
unsigned char read_joy2_controller(controller_t *controller);

/**
* @brief Set the button states of the first controller.
*
* @param controller
* @param a
* @param b
* @param select
* @param start
* @param up
* @param down
* @param left
* @param right
*/
void set_joy1_controller(controller_t *controller,
bool a,
bool b,
bool select,
bool start,
bool up,
bool down,
bool left,
bool right);

/**
* @brief Set the button states of the second controller.
*
* @param controller
* @param a
* @param b
* @param select
* @param start
* @param up
* @param down
* @param left
* @param right
*/
void set_joy2_controller(controller_t *controller,
bool a,
bool b,
bool select,
bool start,
bool up,
bool down,
bool left,
bool right);

#endif
13 changes: 11 additions & 2 deletions src/cpu_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ void create_cpu_bus(cpu_bus_t *bus,
rom_t *rom,
mapper_t *mapper,
apu_t *apu,
ppu_t *ppu) {
ppu_t *ppu,
controller_t *controller) {
bus->rom = rom;
bus->mapper = mapper;
bus->apu = apu;
bus->ppu = ppu;
bus->controller = controller;
memset(bus->memory, 0, CPU_RAM_SIZE);
}

Expand Down Expand Up @@ -56,6 +58,10 @@ unsigned char read_cpu_bus(cpu_bus_t *bus, address_t address) {
case PPU_REG_OAMADDR:
case PPU_REG_OAMDMA:
return bus->ppu->io_databus;
case CTRL_REG_STROBE:
return read_joy1_controller(bus->controller);
case APU_REG_FRAME_COUNTER:
return read_joy2_controller(bus->controller);
// TODO: Handle APU, controller input registers
default:
return bus->memory[address];
Expand Down Expand Up @@ -95,7 +101,10 @@ void write_cpu_bus(cpu_bus_t *bus, address_t address, unsigned char value) {
case PPU_REG_STATUS:
bus->ppu->io_databus = value;
break;
// TODO: Handle APU, controller input registers
case CTRL_REG_STROBE:
write_strobe_controller(bus->controller, value);
break;
// TODO: Handle APU registers
default:
bus->memory[address] = value;
break;
Expand Down
14 changes: 13 additions & 1 deletion src/cpu_bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define CPU_BUS_H

#include "./apu.h"
#include "./controller.h"
#include "./mapper.h"
#include "./ppu.h"
#include "./rom.h"
Expand Down Expand Up @@ -57,6 +58,9 @@
#define PPU_REG_DATA 0x2007
#define PPU_REG_OAMDMA 0x4014

// Memory mapped controller registers
#define CTRL_REG_STROBE 0x4016

/**
* @brief Bus for memory accessing and communication between the CPU and its
* peripherals.
Expand Down Expand Up @@ -98,6 +102,12 @@ typedef struct {
*
*/
ppu_t *ppu;

/**
* @brief Pointer to the input controller.
*
*/
controller_t *controller;
} cpu_bus_t;

/**
Expand All @@ -108,12 +118,14 @@ typedef struct {
* @param mapper
* @param apu
* @param ppu
* @param controller
*/
void create_cpu_bus(cpu_bus_t *bus,
rom_t *rom,
mapper_t *mapper,
apu_t *apu,
ppu_t *ppu);
ppu_t *ppu,
controller_t *controller);

/**
* @brief Mirror an address according to the CPU memory map.
Expand Down
5 changes: 4 additions & 1 deletion src/emulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ void create_emulator(emulator_t *emu, const char *rom_path) {
create_cpu(&emu->cpu, &emu->cpu_bus, &emu->interrupt);
create_apu(&emu->apu, &emu->interrupt);
create_ppu(&emu->ppu, &emu->ppu_bus, &emu->interrupt);
create_controller(&emu->controller);
create_cpu_bus(&emu->cpu_bus,
&emu->rom,
&emu->mapper,
&emu->apu,
&emu->ppu);
&emu->ppu,
&emu->controller);
create_ppu_bus(&emu->ppu_bus, &emu->rom, &emu->mapper);
reset_interrupt(&emu->interrupt);

Expand All @@ -28,6 +30,7 @@ void destroy_emulator(emulator_t *emu) {
destroy_cpu(&emu->cpu);
destroy_apu(&emu->apu);
destroy_ppu(&emu->ppu);
destroy_controller(&emu->controller);
destroy_mapper(&emu->mapper);
unload_rom(&emu->rom);
}
Expand Down
7 changes: 7 additions & 0 deletions src/emulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define EMULATOR_H

#include "./apu.h"
#include "./controller.h"
#include "./cpu.h"
#include "./cpu_bus.h"
#include "./mapper.h"
Expand Down Expand Up @@ -45,6 +46,12 @@ typedef struct {
*/
ppu_t ppu;

/**
* @brief Input controller.
*
*/
controller_t controller;

/**
* @brief CPU bus.
*
Expand Down
13 changes: 12 additions & 1 deletion src/nes.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,25 @@ int main(int argc, char **argv) {
}
}

// Handle input
// Handle debug input
if (is_keydown_input(&io.input, SDLK_o)) {
set_debug_io(&io, true);
}
if (is_keydown_input(&io.input, SDLK_p)) {
set_debug_io(&io, false);
}

// Handle controller 1 input
set_joy1_controller(&emu.controller,
is_keydown_input(&io.input, SDLK_z),
is_keydown_input(&io.input, SDLK_x),
is_keydown_input(&io.input, SDLK_a),
is_keydown_input(&io.input, SDLK_s),
is_keydown_input(&io.input, SDLK_UP),
is_keydown_input(&io.input, SDLK_DOWN),
is_keydown_input(&io.input, SDLK_LEFT),
is_keydown_input(&io.input, SDLK_RIGHT));

// Refresh IO
bool io_state = refresh_io(&io, &emu);
if (!emu_state || !io_state) {
Expand Down

0 comments on commit 3d963f1

Please sign in to comment.