changeset 28:c677507682e3

Untested controller implementation
author Michael Pavone <pavone@retrodev.com>
date Sun, 03 Apr 2016 00:33:54 -0700
parents 351a0d0cce3b
children 5a8b5f9fc50a
files Makefile src/main.c src/system_sdl.c
diffstat 3 files changed, 74 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri Apr 01 21:51:46 2016 -0700
+++ b/Makefile	Sun Apr 03 00:33:54 2016 -0700
@@ -18,7 +18,7 @@
 $(TARGETDIR) : 
 	mkdir $(TARGETDIR)
 
-$(TARGETDIR)/s16 : $(TARGETDIR)/main.o $(TARGETDIR)/cpu.o $(TARGETDIR)/vdp.o $(TARGETDIR)/audio.o $(TARGETDIR)/timer.o $(TARGETDIR)/system_sdl.o 
+$(TARGETDIR)/s16 : $(TARGETDIR)/main.o $(TARGETDIR)/cpu.o $(TARGETDIR)/vdp.o $(TARGETDIR)/audio.o $(TARGETDIR)/timer.o $(TARGETDIR)/controller.o $(TARGETDIR)/system_sdl.o 
 	$(CC) -o $@ $^ $(LDFLAGS)
 	
 $(TARGETDIR)/asm : $(TARGETDIR)/asm.o $(TARGETDIR)/mnemonics.o
--- a/src/main.c	Fri Apr 01 21:51:46 2016 -0700
+++ b/src/main.c	Sun Apr 03 00:33:54 2016 -0700
@@ -6,6 +6,7 @@
 #include "vdp.h"
 #include "audio.h"
 #include "timer.h"
+#include "controller.h"
 #include "system.h"
 
 #define CYCLES_PER_FRAME (832*262)
@@ -17,8 +18,8 @@
 enum {
 	PORT_CONTROLLER_1,
 	PORT_CONTROLLER_2,
-	PORT_CONTROLLER_3,
-	PORT_CONTROLLER_4,
+	RESERVED_1,
+	RESERVED_2,
 	PORT_FREQUENCY_A,
 	PORT_FREQUENCY_B,
 	PORT_FREQUENCY_C,
@@ -34,10 +35,11 @@
 };
 
 typedef struct {
-	cpu   *proc;
-	audio *audio;
-	timer timer;
-	vdp   video;
+	cpu         *proc;
+	audio       *audio;
+	timer       timer;
+	controllers pads;
+	vdp         video;
 } console;
 
 void debug_port_write(cpu *context, uint8_t port, uint16_t value)
@@ -124,6 +126,14 @@
 	}
 }
 
+uint16_t controller_port_read(cpu *context, uint8_t port)
+{
+	//process events so controller state is as fresh as possible
+	system_poll_events();
+	console *system = context->system;
+	return controller_read(&system->pads, port - PORT_CONTROLLER_1);
+}
+
 uint32_t next_interrupt_cycle(cpu *context, uint8_t mask)
 {
 	console *system = context->system;
@@ -210,6 +220,8 @@
 	context.proc->system = &context;
 	vdp_init(&context.video, 2);
 	timer_init(&context.timer, 16);
+	context.proc->port_handlers[PORT_CONTROLLER_1].read = controller_port_read;
+	context.proc->port_handlers[PORT_CONTROLLER_2].read = controller_port_read;
 	context.proc->port_handlers[PORT_FREQUENCY_A].write = frequency_port_write;
 	context.proc->port_handlers[PORT_FREQUENCY_B].write = frequency_port_write;
 	context.proc->port_handlers[PORT_FREQUENCY_C].write = frequency_port_write;
--- a/src/system_sdl.c	Fri Apr 01 21:51:46 2016 -0700
+++ b/src/system_sdl.c	Sun Apr 03 00:33:54 2016 -0700
@@ -1,6 +1,7 @@
 #include <SDL.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include "controller.h"
 
 
 static SDL_Window   *window;
@@ -69,9 +70,12 @@
 	return buffer_size;
 }
 
+static int num_controllers;
+static SDL_GameController **game_controllers;
+
 int system_init(int width, int height, int desired_sample_rate)
 {
-	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
+	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER) < 0) {
 		fprintf(stderr, "Failed to init SDL: %s\n", SDL_GetError());
 		return 0;
 	}
@@ -116,6 +120,18 @@
 	atexit(close_audio);
 	SDL_PauseAudio(0);
 	
+	num_controllers = SDL_NumJoysticks();
+	game_controllers = calloc(num_controllers, sizeof(*game_controllers));
+	
+	for (int i = 0; i < num_controllers; i++)
+	{
+		if (!SDL_IsGameController(i)) {
+			printf("Joystick %d: %s is not recognized as a controller by SDL2\n", i, SDL_JoystickNameForIndex(i));
+			continue;
+		}
+		game_controllers[i] = SDL_GameControllerOpen(i);
+	}
+	
 	return 1;
 	
 error:
@@ -142,6 +158,36 @@
 	SDL_RenderPresent(renderer);
 }
 
+//SDL2 provides this, but only in 2.0.4+
+SDL_GameController *controller_by_id(SDL_JoystickID which)
+{
+	for (int i = 0; i < num_controllers; i++)
+	{
+		if (!game_controllers[i]) {
+			continue;
+		}
+		if (SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(game_controllers[i])) == which) {
+			return game_controllers[i];
+		}
+	}
+	return NULL;
+}
+
+const uint16_t mapping[SDL_CONTROLLER_BUTTON_MAX] = {
+	[SDL_CONTROLLER_BUTTON_LEFTSHOULDER]  = 0x001,
+	[SDL_CONTROLLER_BUTTON_Y]             = 0x002,
+	[SDL_CONTROLLER_BUTTON_X]             = 0x004,
+	[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER] = 0x008,
+	[SDL_CONTROLLER_BUTTON_B]             = 0x010,
+	[SDL_CONTROLLER_BUTTON_A]             = 0x020,
+	[SDL_CONTROLLER_BUTTON_BACK]          = 0x040,
+	[SDL_CONTROLLER_BUTTON_START]         = 0x080,
+	[SDL_CONTROLLER_BUTTON_DPAD_RIGHT]    = 0x100,
+	[SDL_CONTROLLER_BUTTON_DPAD_LEFT]     = 0x200,
+	[SDL_CONTROLLER_BUTTON_DPAD_DOWN]     = 0x400,
+	[SDL_CONTROLLER_BUTTON_DPAD_UP]       = 0x800,
+};
+
 void system_poll_events()
 {
 	SDL_Event event;
@@ -152,6 +198,14 @@
 		case SDL_QUIT:
 			exit(0);
 			break;
+		case SDL_CONTROLLERBUTTONDOWN:
+			controller_pressed(event.cbutton.which, mapping[event.cbutton.button]);
+			break;
+		case SDL_CONTROLLERBUTTONUP:
+			controller_released(event.cbutton.which, mapping[event.cbutton.button]);
+			break;
+		//TODO: Keyboard input
+		//TODO: Controller hotplug
 		}
 	}
 }