changeset 421:d0cacb4ade0b

Move IO code to a separate file and do a tiny bit of refactoring
author Mike Pavone <pavone@retrodev.com>
date Tue, 25 Jun 2013 19:20:39 -0700
parents 9fb111b5641f
children 642b2f8aee32
files blastem.c blastem.h gen_x86.h io.c io.h render_sdl.c
diffstat 6 files changed, 421 insertions(+), 410 deletions(-) [+]
line wrap: on
line diff
--- a/blastem.c	Mon Jun 24 21:32:25 2013 -0700
+++ b/blastem.c	Tue Jun 25 19:20:39 2013 -0700
@@ -22,7 +22,6 @@
 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
 
 //TODO: Figure out the exact value for this
-#define CYCLE_NEVER 0xFFFFFFFF
 #define LINES_NTSC 262
 #define LINES_PAL 312
 
@@ -32,9 +31,6 @@
 uint16_t ram[RAM_WORDS];
 uint8_t z80_ram[Z80_RAM_BYTES];
 
-io_port gamepad_1;
-io_port gamepad_2;
-
 int headless = 0;
 int z80_enabled = 1;
 int frame_limit = 0;
@@ -230,8 +226,9 @@
 		frame++;
 		mclks -= mclks_per_frame;
 		vdp_adjust_cycles(v_context, mclks_per_frame);
-		io_adjust_cycles(&gamepad_1, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
-		io_adjust_cycles(&gamepad_2, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
+		io_adjust_cycles(gen->ports, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
+		io_adjust_cycles(gen->ports+1, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
+		io_adjust_cycles(gen->ports+2, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
 		if (busack_cycle != CYCLE_NEVER) {
 			if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) {
 				busack_cycle -= mclks_per_frame/MCLKS_PER_68K;
@@ -288,8 +285,10 @@
 							wait_render_frame(v_context, frame_limit);
 						}
 						vdp_adjust_cycles(v_context, mclks_per_frame);
-						io_adjust_cycles(&gamepad_1, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
-						io_adjust_cycles(&gamepad_2, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
+						genesis_context * gen = context->system;
+						io_adjust_cycles(gen->ports, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
+						io_adjust_cycles(gen->ports+1, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
+						io_adjust_cycles(gen->ports+2, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
 						if (busack_cycle != CYCLE_NEVER) {
 							if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) {
 								busack_cycle -= mclks_per_frame/MCLKS_PER_68K;
@@ -313,8 +312,10 @@
 								wait_render_frame(v_context, frame_limit);
 							}
 							vdp_adjust_cycles(v_context, mclks_per_frame);
-							io_adjust_cycles(&gamepad_1, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
-							io_adjust_cycles(&gamepad_2, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
+							genesis_context * gen = context->system;
+							io_adjust_cycles(gen->ports, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
+							io_adjust_cycles(gen->ports+1, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
+							io_adjust_cycles(gen->ports+2, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K);
 							if (busack_cycle != CYCLE_NEVER) {
 								if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) {
 									busack_cycle -= mclks_per_frame/MCLKS_PER_68K;
@@ -421,76 +422,6 @@
 	}
 }
 
-#define TH 0x40
-#define TH_TIMEOUT 8000
-
-void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction)
-{
-	/*uint8_t control = pad->control | 0x80;
-	uint8_t th = control & pad->output;
-	if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
-		printf("adjust_cycles | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, current_cycle);
-	}*/
-	if (current_cycle >= pad->timeout_cycle) {
-		pad->th_counter = 0;
-	} else {
-		pad->timeout_cycle -= deduction;
-	}
-	if (busack_cycle < CYCLE_NEVER && current_cycle < busack_cycle) {
-		busack_cycle -= deduction;
-	}
-}
-
-void io_data_write(io_port * pad, m68k_context * context, uint8_t value)
-{
-	if (pad->control & TH) {
-		//check if TH has changed
-		if ((pad->output & TH) ^ (value & TH)) {
-			if (context->current_cycle >= pad->timeout_cycle) {
-				pad->th_counter = 0;
-			}
-			if (!(value & TH)) {
-				pad->th_counter++;
-			}
-			pad->timeout_cycle = context->current_cycle + TH_TIMEOUT;
-		}
-	}
-	pad->output = value;
-}
-
-uint8_t io_data_read(io_port * pad, m68k_context * context)
-{
-	uint8_t control = pad->control | 0x80;
-	uint8_t th = control & pad->output;
-	uint8_t input;
-	if (context->current_cycle >= pad->timeout_cycle) {
-		pad->th_counter = 0;
-	}
-	/*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
-		printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, context->current_cycle);
-	}*/
-	if (th) {
-		if (pad->th_counter == 3) {
-			input = pad->input[GAMEPAD_EXTRA];
-		} else {
-			input = pad->input[GAMEPAD_TH1];
-		}
-	} else {
-		if (pad->th_counter == 3) {
-			input = pad->input[GAMEPAD_TH0] | 0xF;
-		} else if(pad->th_counter == 4) {
-			input = pad->input[GAMEPAD_TH0]  & 0x30;
-		} else {
-			input = pad->input[GAMEPAD_TH0] | 0xC;
-		}
-	}
-	uint8_t value = ((~input) & (~control)) | (pad->output & control);
-	/*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
-		printf ("value: %X\n", value);
-	}*/
-	return value;
-}
-
 uint32_t zram_counter = 0;
 #define Z80_ACK_DELAY 3
 #define Z80_BUSY_DELAY 1//TODO: Find the actual value for this
@@ -538,18 +469,22 @@
 			switch(location/2)
 			{
 			case 0x1:
-				io_data_write(&gamepad_1, context, value);
+				io_data_write(gen->ports, value, context->current_cycle);
 				break;
 			case 0x2:
-				io_data_write(&gamepad_2, context, value);
+				io_data_write(gen->ports+1, value, context->current_cycle);
 				break;
-			case 0x3://PORT C Data
+			case 0x3:
+				io_data_write(gen->ports+2, value, context->current_cycle);
 				break;
 			case 0x4:
-				gamepad_1.control = value;
+				gen->ports[0].control = value;
 				break;
 			case 0x5:
-				gamepad_2.control = value;
+				gen->ports[1].control = value;
+				break;
+			case 0x6:
+				gen->ports[2].control = value;
 				break;
 			}
 		} else {
@@ -655,21 +590,22 @@
 				value = version_reg;
 				break;
 			case 0x1:
-				value = io_data_read(&gamepad_1, context);
+				value = io_data_read(gen->ports, context->current_cycle);
 				break;
 			case 0x2:
-				value = io_data_read(&gamepad_2, context);
+				value = io_data_read(gen->ports+1, context->current_cycle);
 				break;
-			case 0x3://PORT C Data
+			case 0x3:
+				value = io_data_read(gen->ports+2, context->current_cycle);
 				break;
 			case 0x4:
-				value = gamepad_1.control;
+				value = gen->ports[0].control;
 				break;
 			case 0x5:
-				value = gamepad_2.control;
+				value = gen->ports[1].control;
 				break;
-			case 0x6://PORT C control
-				value = 0;
+			case 0x6:
+				value = gen->ports[2].control;
 				break;
 			default:
 				value = 0xFF;
@@ -846,302 +782,6 @@
 	return context;
 }
 
-enum {
-	BIND_NONE,
-	BIND_GAMEPAD1,
-	BIND_GAMEPAD2,
-	BIND_UI
-};
-
-typedef enum {
-	UI_DEBUG_MODE_INC,
-	UI_DEBUG_PAL_INC,
-	UI_ENTER_DEBUGGER
-} ui_action;
-
-typedef struct {
-	uint8_t bind_type;
-	uint8_t subtype_a;
-	uint8_t subtype_b;
-	uint8_t value;
-} keybinding;
-
-typedef struct {
-	keybinding bindings[4];
-	uint8_t    state;
-} joydpad;
-
-keybinding * bindings[256];
-keybinding * joybindings[MAX_JOYSTICKS];
-joydpad * joydpads[MAX_JOYSTICKS];
-const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
-
-void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
-{
-	int bucket = keycode >> 8 & 0xFF;
-	if (!bindings[bucket]) {
-		bindings[bucket] = malloc(sizeof(keybinding) * 256);
-		memset(bindings[bucket], 0, sizeof(keybinding) * 256);
-	}
-	int idx = keycode & 0xFF;
-	bindings[bucket][idx].bind_type = bind_type;
-	bindings[bucket][idx].subtype_a = subtype_a;
-	bindings[bucket][idx].subtype_b = subtype_b;
-	bindings[bucket][idx].value = value;
-}
-
-void bind_button(int joystick, int button, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
-{
-	if (joystick >= MAX_JOYSTICKS) {
-		return;
-	}
-	if (!joybindings[joystick]) {
-		int num = render_joystick_num_buttons(joystick);
-		if (!num) {
-			return;
-		}
-		joybindings[joystick] = malloc(sizeof(keybinding)*num);
-		memset(joybindings[joystick], 0, sizeof(keybinding)*num);
-	}
-	joybindings[joystick][button].bind_type = bind_type;
-	joybindings[joystick][button].subtype_a = subtype_a;
-	joybindings[joystick][button].subtype_b = subtype_b;
-	joybindings[joystick][button].value = value;
-}
-
-void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
-{
-	if (joystick >= MAX_JOYSTICKS) {
-		return;
-	}
-	if (!joydpads[joystick]) {
-		int num = render_joystick_num_hats(joystick);
-		if (!num) {
-			return;
-		}
-		joydpads[joystick] = malloc(sizeof(joydpad)*num);
-		memset(joydpads[joystick], 0, sizeof(joydpad)*num);
-	}
-	for (int i = 0; i < 4; i ++) {
-		if (dpadbits[i] & direction) {
-			joydpads[joystick][dpad].bindings[i].bind_type = bind_type;
-			joydpads[joystick][dpad].bindings[i].subtype_a = subtype_a;
-			joydpads[joystick][dpad].bindings[i].subtype_b = subtype_b;
-			joydpads[joystick][dpad].bindings[i].value = value;
-			break;
-		}
-	}
-}
-
-#define GAMEPAD_BUTTON(PRI_SLOT, SEC_SLOT, VALUE)  (PRI_SLOT << 12 | SEC_SLOT << 8 | VALUE)
-
-#define DPAD_UP      GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_TH1, 0x01)
-#define BUTTON_Z     GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x01)
-#define DPAD_DOWN    GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_TH1, 0x02)
-#define BUTTON_Y     GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x02)
-#define DPAD_LEFT    GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x04)
-#define BUTTON_X     GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x04)
-#define DPAD_RIGHT   GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x08)
-#define BUTTON_MODE  GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x08)
-#define BUTTON_A     GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x10)
-#define BUTTON_B     GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x10)
-#define BUTTON_START GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x20)
-#define BUTTON_C     GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x20)
-
-void bind_gamepad(int keycode, int gamepadnum, int button)
-{
-	
-	if (gamepadnum < 1 || gamepadnum > 2) {
-		return;
-	}
-	uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
-	bind_key(keycode, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
-}
-
-void bind_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbutton)
-{
-	if (gamepadnum < 1 || gamepadnum > 2) {
-		return;
-	}
-	uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
-	bind_button(joystick, joybutton, bind_type, padbutton >> 12, padbutton >> 8 & 0xF, padbutton & 0xFF);
-}
-
-void bind_dpad_gamepad(int joystick, int dpad, uint8_t direction, int gamepadnum, int button)
-{
-	if (gamepadnum < 1 || gamepadnum > 2) {
-		return;
-	}
-	uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
-	bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
-}
-
-void bind_ui(int keycode, ui_action action)
-{
-	bind_key(keycode, BIND_UI, action, 0, 0);
-}
-
-void handle_binding_down(keybinding * binding)
-{
-	switch(binding->bind_type)
-	{
-	case BIND_GAMEPAD1:
-		if (binding->subtype_a <= GAMEPAD_EXTRA) {
-			gamepad_1.input[binding->subtype_a] |= binding->value;
-		}
-		if (binding->subtype_b <= GAMEPAD_EXTRA) {
-			gamepad_1.input[binding->subtype_b] |= binding->value;
-		}
-		break;
-	case BIND_GAMEPAD2:
-		if (binding->subtype_a <= GAMEPAD_EXTRA) {
-			gamepad_2.input[binding->subtype_a] |= binding->value;
-		}
-		if (binding->subtype_b <= GAMEPAD_EXTRA) {
-			gamepad_2.input[binding->subtype_b] |= binding->value;
-		}
-		break;
-	}
-}
-
-void handle_keydown(int keycode)
-{
-	int bucket = keycode >> 8 & 0xFF;
-	if (!bindings[bucket]) {
-		return;
-	}
-	int idx = keycode & 0xFF;
-	keybinding * binding = bindings[bucket] + idx;
-	handle_binding_down(binding);
-}
-
-void handle_joydown(int joystick, int button)
-{
-	if (!joybindings[joystick]) {
-		return;
-	}
-	keybinding * binding = joybindings[joystick] + button;
-	handle_binding_down(binding);
-}
-
-uint8_t ui_debug_mode = 0;
-uint8_t ui_debug_pal = 0;
-
-void handle_binding_up(keybinding * binding)
-{
-	switch(binding->bind_type)
-	{
-	case BIND_GAMEPAD1:
-		if (binding->subtype_a <= GAMEPAD_EXTRA) {
-			gamepad_1.input[binding->subtype_a] &= ~binding->value;
-		}
-		if (binding->subtype_b <= GAMEPAD_EXTRA) {
-			gamepad_1.input[binding->subtype_b] &= ~binding->value;
-		}
-		break;
-	case BIND_GAMEPAD2:
-		if (binding->subtype_a <= GAMEPAD_EXTRA) {
-			gamepad_2.input[binding->subtype_a] &= ~binding->value;
-		}
-		if (binding->subtype_b <= GAMEPAD_EXTRA) {
-			gamepad_2.input[binding->subtype_b] &= ~binding->value;
-		}
-		break;
-	case BIND_UI:
-		switch (binding->subtype_a)
-		{
-		case UI_DEBUG_MODE_INC:
-			ui_debug_mode++;
-			if (ui_debug_mode == 4) {
-				ui_debug_mode = 0;
-			}
-			render_debug_mode(ui_debug_mode);
-			break;
-		case UI_DEBUG_PAL_INC:
-			ui_debug_pal++;
-			if (ui_debug_pal == 4) {
-				ui_debug_pal = 0;
-			}
-			render_debug_pal(ui_debug_pal);
-			break;
-		case UI_ENTER_DEBUGGER:
-			break_on_sync = 1;
-			break;
-		}
-		break;
-	}
-}
-
-void handle_keyup(int keycode)
-{
-	int bucket = keycode >> 8 & 0xFF;
-	if (!bindings[bucket]) {
-		return;
-	}
-	int idx = keycode & 0xFF;
-	keybinding * binding = bindings[bucket] + idx;
-	handle_binding_up(binding);
-}
-
-void handle_joyup(int joystick, int button)
-{
-	if (!joybindings[joystick]) {
-		return;
-	}
-	keybinding * binding = joybindings[joystick] + button;
-	handle_binding_up(binding);
-}
-
-void handle_joy_dpad(int joystick, int dpadnum, uint8_t value)
-{
-	if (!joydpads[joystick]) {
-		return;
-	}
-	joydpad * dpad = joydpads[joystick] + dpadnum;
-	uint8_t newdown = (value ^ dpad->state) & value;
-	uint8_t newup = ((~value) ^ (~dpad->state)) & (~value);
-	dpad->state = value;
-	for (int i = 0; i < 4; i++) {
-		if (newdown & dpadbits[i]) {
-			handle_binding_down(dpad->bindings + i);
-		} else if(newup & dpadbits[i]) {
-			handle_binding_up(dpad->bindings + i);
-		}
-	}
-}
-
-void set_keybindings()
-{
-	bind_gamepad(RENDERKEY_UP, 1, DPAD_UP);
-	bind_gamepad(RENDERKEY_DOWN, 1, DPAD_DOWN);
-	bind_gamepad(RENDERKEY_LEFT, 1, DPAD_LEFT);
-	bind_gamepad(RENDERKEY_RIGHT, 1, DPAD_RIGHT);
-	bind_gamepad('a', 1, BUTTON_A);
-	bind_gamepad('s', 1, BUTTON_B);
-	bind_gamepad('d', 1, BUTTON_C);
-	bind_gamepad('q', 1, BUTTON_X);
-	bind_gamepad('w', 1, BUTTON_Y);
-	bind_gamepad('e', 1, BUTTON_Z);
-	bind_gamepad('\r', 1, BUTTON_START);
-	bind_gamepad('f', 1, BUTTON_MODE);
-	bind_ui('[', UI_DEBUG_MODE_INC);
-	bind_ui(']', UI_DEBUG_PAL_INC);
-	bind_ui('u', UI_ENTER_DEBUGGER);
-	
-	bind_dpad_gamepad(0, 0, RENDER_DPAD_UP, 2, DPAD_UP);
-	bind_dpad_gamepad(0, 0, RENDER_DPAD_DOWN, 2, DPAD_DOWN);
-	bind_dpad_gamepad(0, 0, RENDER_DPAD_LEFT, 2, DPAD_LEFT);
-	bind_dpad_gamepad(0, 0, RENDER_DPAD_RIGHT, 2, DPAD_RIGHT);
-	bind_button_gamepad(0, 0, 2, BUTTON_A);
-	bind_button_gamepad(0, 1, 2, BUTTON_B);
-	bind_button_gamepad(0, 2, 2, BUTTON_C);
-	bind_button_gamepad(0, 3, 2, BUTTON_X);
-	bind_button_gamepad(0, 4, 2, BUTTON_Y);
-	bind_button_gamepad(0, 5, 2, BUTTON_Z);
-	bind_button_gamepad(0, 6, 2, BUTTON_START);
-	bind_button_gamepad(0, 7, 2, BUTTON_MODE);
-}
-
 typedef struct bp_def {
 	struct bp_def * next;
 	uint32_t address;
@@ -2131,7 +1771,8 @@
 	init_x86_z80_opts(&z_opts);
 	init_z80_context(&z_context, &z_opts);
 
-	genesis_context gen;	
+	genesis_context gen;
+	memset(&gen, 0, sizeof(gen));
 
 	z_context.system = &gen;
 	z_context.mem_pointers[0] = z80_ram;
--- a/blastem.h	Mon Jun 24 21:32:25 2013 -0700
+++ b/blastem.h	Tue Jun 25 19:20:39 2013 -0700
@@ -7,19 +7,14 @@
 #include "ym2612.h"
 #include "vdp.h"
 #include "psg.h"
-
-typedef struct {
-	uint32_t th_counter;
-	uint32_t timeout_cycle;
-	uint8_t output;
-	uint8_t control;
-	uint8_t input[3];
-} io_port;
+#include "io.h"
 
 #define RAM_FLAG_ODD  0x1800
 #define RAM_FLAG_EVEN 0x1000
 #define RAM_FLAG_BOTH 0x0000
 
+#define CYCLE_NEVER 0xFFFFFFFF
+
 typedef struct {
 	m68k_context   *m68k;
 	z80_context    *z80;
@@ -30,24 +25,14 @@
 	uint32_t       save_ram_mask;
 	uint32_t       save_flags;
 	uint8_t        bank_regs[8];
+	io_port        ports[3];
 } genesis_context;
 
-#define GAMEPAD_TH0 0
-#define GAMEPAD_TH1 1
-#define GAMEPAD_EXTRA 2
-#define GAMEPAD_NONE 0xF
+extern genesis_context * genesis;
+extern int break_on_sync;
 
-extern io_port gamepad_1;
-extern io_port gamepad_2;
-
-void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction);
 uint16_t read_dma_value(uint32_t address);
 m68k_context * debugger(m68k_context * context, uint32_t address);
-void handle_keydown(int keycode);
-void handle_keyup(int keycode);
-void handle_joydown(int joystick, int button);
-void handle_joyup(int joystick, int button);
-void handle_joy_dpad(int joystick, int dpad, uint8_t state);
 
 #endif //BLASTEM_H_
 
--- a/gen_x86.h	Mon Jun 24 21:32:25 2013 -0700
+++ b/gen_x86.h	Tue Jun 25 19:20:39 2013 -0700
@@ -110,6 +110,7 @@
 uint8_t * sbb_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
 uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
 uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * add_irdisp32(uint8_t * out, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
 uint8_t * adc_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
 uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
 uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/io.c	Tue Jun 25 19:20:39 2013 -0700
@@ -0,0 +1,354 @@
+#include "io.h"
+#include "blastem.h"
+#include "render.h"
+
+enum {
+	BIND_NONE,
+	BIND_GAMEPAD1,
+	BIND_GAMEPAD2,
+	BIND_UI
+};
+
+typedef enum {
+	UI_DEBUG_MODE_INC,
+	UI_DEBUG_PAL_INC,
+	UI_ENTER_DEBUGGER
+} ui_action;
+
+typedef struct {
+	uint8_t bind_type;
+	uint8_t subtype_a;
+	uint8_t subtype_b;
+	uint8_t value;
+} keybinding;
+
+typedef struct {
+	keybinding bindings[4];
+	uint8_t    state;
+} joydpad;
+
+keybinding * bindings[256];
+keybinding * joybindings[MAX_JOYSTICKS];
+joydpad * joydpads[MAX_JOYSTICKS];
+const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
+
+void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
+{
+	int bucket = keycode >> 8 & 0xFF;
+	if (!bindings[bucket]) {
+		bindings[bucket] = malloc(sizeof(keybinding) * 256);
+		memset(bindings[bucket], 0, sizeof(keybinding) * 256);
+	}
+	int idx = keycode & 0xFF;
+	bindings[bucket][idx].bind_type = bind_type;
+	bindings[bucket][idx].subtype_a = subtype_a;
+	bindings[bucket][idx].subtype_b = subtype_b;
+	bindings[bucket][idx].value = value;
+}
+
+void bind_button(int joystick, int button, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
+{
+	if (joystick >= MAX_JOYSTICKS) {
+		return;
+	}
+	if (!joybindings[joystick]) {
+		int num = render_joystick_num_buttons(joystick);
+		if (!num) {
+			return;
+		}
+		joybindings[joystick] = malloc(sizeof(keybinding)*num);
+		memset(joybindings[joystick], 0, sizeof(keybinding)*num);
+	}
+	joybindings[joystick][button].bind_type = bind_type;
+	joybindings[joystick][button].subtype_a = subtype_a;
+	joybindings[joystick][button].subtype_b = subtype_b;
+	joybindings[joystick][button].value = value;
+}
+
+void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
+{
+	if (joystick >= MAX_JOYSTICKS) {
+		return;
+	}
+	if (!joydpads[joystick]) {
+		int num = render_joystick_num_hats(joystick);
+		if (!num) {
+			return;
+		}
+		joydpads[joystick] = malloc(sizeof(joydpad)*num);
+		memset(joydpads[joystick], 0, sizeof(joydpad)*num);
+	}
+	for (int i = 0; i < 4; i ++) {
+		if (dpadbits[i] & direction) {
+			joydpads[joystick][dpad].bindings[i].bind_type = bind_type;
+			joydpads[joystick][dpad].bindings[i].subtype_a = subtype_a;
+			joydpads[joystick][dpad].bindings[i].subtype_b = subtype_b;
+			joydpads[joystick][dpad].bindings[i].value = value;
+			break;
+		}
+	}
+}
+
+#define GAMEPAD_BUTTON(PRI_SLOT, SEC_SLOT, VALUE)  (PRI_SLOT << 12 | SEC_SLOT << 8 | VALUE)
+
+#define DPAD_UP      GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_TH1, 0x01)
+#define BUTTON_Z     GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x01)
+#define DPAD_DOWN    GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_TH1, 0x02)
+#define BUTTON_Y     GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x02)
+#define DPAD_LEFT    GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x04)
+#define BUTTON_X     GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x04)
+#define DPAD_RIGHT   GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x08)
+#define BUTTON_MODE  GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x08)
+#define BUTTON_A     GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x10)
+#define BUTTON_B     GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x10)
+#define BUTTON_START GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x20)
+#define BUTTON_C     GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x20)
+
+void bind_gamepad(int keycode, int gamepadnum, int button)
+{
+	
+	if (gamepadnum < 1 || gamepadnum > 2) {
+		return;
+	}
+	uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
+	bind_key(keycode, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
+}
+
+void bind_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbutton)
+{
+	if (gamepadnum < 1 || gamepadnum > 2) {
+		return;
+	}
+	uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
+	bind_button(joystick, joybutton, bind_type, padbutton >> 12, padbutton >> 8 & 0xF, padbutton & 0xFF);
+}
+
+void bind_dpad_gamepad(int joystick, int dpad, uint8_t direction, int gamepadnum, int button)
+{
+	if (gamepadnum < 1 || gamepadnum > 2) {
+		return;
+	}
+	uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
+	bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
+}
+
+void bind_ui(int keycode, ui_action action)
+{
+	bind_key(keycode, BIND_UI, action, 0, 0);
+}
+
+void handle_binding_down(keybinding * binding)
+{
+	switch(binding->bind_type)
+	{
+	case BIND_GAMEPAD1:
+	case BIND_GAMEPAD2:
+		if (binding->subtype_a <= GAMEPAD_EXTRA) {
+			genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_a] |= binding->value;
+		}
+		if (binding->subtype_b <= GAMEPAD_EXTRA) {
+			genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_b] |= binding->value;
+		}
+		break;
+	}
+}
+
+void handle_keydown(int keycode)
+{
+	int bucket = keycode >> 8 & 0xFF;
+	if (!bindings[bucket]) {
+		return;
+	}
+	int idx = keycode & 0xFF;
+	keybinding * binding = bindings[bucket] + idx;
+	handle_binding_down(binding);
+}
+
+void handle_joydown(int joystick, int button)
+{
+	if (!joybindings[joystick]) {
+		return;
+	}
+	keybinding * binding = joybindings[joystick] + button;
+	handle_binding_down(binding);
+}
+
+uint8_t ui_debug_mode = 0;
+uint8_t ui_debug_pal = 0;
+
+void handle_binding_up(keybinding * binding)
+{
+	switch(binding->bind_type)
+	{
+	case BIND_GAMEPAD1:
+	case BIND_GAMEPAD2:
+		if (binding->subtype_a <= GAMEPAD_EXTRA) {
+			genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_a] &= ~binding->value;
+		}
+		if (binding->subtype_b <= GAMEPAD_EXTRA) {
+			genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_b] &= ~binding->value;
+		}
+		break;
+	case BIND_UI:
+		switch (binding->subtype_a)
+		{
+		case UI_DEBUG_MODE_INC:
+			ui_debug_mode++;
+			if (ui_debug_mode == 4) {
+				ui_debug_mode = 0;
+			}
+			render_debug_mode(ui_debug_mode);
+			break;
+		case UI_DEBUG_PAL_INC:
+			ui_debug_pal++;
+			if (ui_debug_pal == 4) {
+				ui_debug_pal = 0;
+			}
+			render_debug_pal(ui_debug_pal);
+			break;
+		case UI_ENTER_DEBUGGER:
+			break_on_sync = 1;
+			break;
+		}
+		break;
+	}
+}
+
+void handle_keyup(int keycode)
+{
+	int bucket = keycode >> 8 & 0xFF;
+	if (!bindings[bucket]) {
+		return;
+	}
+	int idx = keycode & 0xFF;
+	keybinding * binding = bindings[bucket] + idx;
+	handle_binding_up(binding);
+}
+
+void handle_joyup(int joystick, int button)
+{
+	if (!joybindings[joystick]) {
+		return;
+	}
+	keybinding * binding = joybindings[joystick] + button;
+	handle_binding_up(binding);
+}
+
+void handle_joy_dpad(int joystick, int dpadnum, uint8_t value)
+{
+	if (!joydpads[joystick]) {
+		return;
+	}
+	joydpad * dpad = joydpads[joystick] + dpadnum;
+	uint8_t newdown = (value ^ dpad->state) & value;
+	uint8_t newup = ((~value) ^ (~dpad->state)) & (~value);
+	dpad->state = value;
+	for (int i = 0; i < 4; i++) {
+		if (newdown & dpadbits[i]) {
+			handle_binding_down(dpad->bindings + i);
+		} else if(newup & dpadbits[i]) {
+			handle_binding_up(dpad->bindings + i);
+		}
+	}
+}
+
+void set_keybindings()
+{
+	bind_gamepad(RENDERKEY_UP, 1, DPAD_UP);
+	bind_gamepad(RENDERKEY_DOWN, 1, DPAD_DOWN);
+	bind_gamepad(RENDERKEY_LEFT, 1, DPAD_LEFT);
+	bind_gamepad(RENDERKEY_RIGHT, 1, DPAD_RIGHT);
+	bind_gamepad('a', 1, BUTTON_A);
+	bind_gamepad('s', 1, BUTTON_B);
+	bind_gamepad('d', 1, BUTTON_C);
+	bind_gamepad('q', 1, BUTTON_X);
+	bind_gamepad('w', 1, BUTTON_Y);
+	bind_gamepad('e', 1, BUTTON_Z);
+	bind_gamepad('\r', 1, BUTTON_START);
+	bind_gamepad('f', 1, BUTTON_MODE);
+	bind_ui('[', UI_DEBUG_MODE_INC);
+	bind_ui(']', UI_DEBUG_PAL_INC);
+	bind_ui('u', UI_ENTER_DEBUGGER);
+	
+	bind_dpad_gamepad(0, 0, RENDER_DPAD_UP, 2, DPAD_UP);
+	bind_dpad_gamepad(0, 0, RENDER_DPAD_DOWN, 2, DPAD_DOWN);
+	bind_dpad_gamepad(0, 0, RENDER_DPAD_LEFT, 2, DPAD_LEFT);
+	bind_dpad_gamepad(0, 0, RENDER_DPAD_RIGHT, 2, DPAD_RIGHT);
+	bind_button_gamepad(0, 0, 2, BUTTON_A);
+	bind_button_gamepad(0, 1, 2, BUTTON_B);
+	bind_button_gamepad(0, 2, 2, BUTTON_C);
+	bind_button_gamepad(0, 3, 2, BUTTON_X);
+	bind_button_gamepad(0, 4, 2, BUTTON_Y);
+	bind_button_gamepad(0, 5, 2, BUTTON_Z);
+	bind_button_gamepad(0, 6, 2, BUTTON_START);
+	bind_button_gamepad(0, 7, 2, BUTTON_MODE);
+}
+
+#define TH 0x40
+#define TH_TIMEOUT 8000
+
+void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction)
+{
+	/*uint8_t control = pad->control | 0x80;
+	uint8_t th = control & pad->output;
+	if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
+		printf("adjust_cycles | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, current_cycle);
+	}*/
+	if (current_cycle >= pad->timeout_cycle) {
+		pad->th_counter = 0;
+	} else {
+		pad->timeout_cycle -= deduction;
+	}
+}
+
+void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle)
+{
+	if (pad->control & TH) {
+		//check if TH has changed
+		if ((pad->output & TH) ^ (value & TH)) {
+			if (current_cycle >= pad->timeout_cycle) {
+				pad->th_counter = 0;
+			}
+			if (!(value & TH)) {
+				pad->th_counter++;
+			}
+			pad->timeout_cycle = current_cycle + TH_TIMEOUT;
+		}
+	}
+	pad->output = value;
+}
+
+uint8_t io_data_read(io_port * pad, uint32_t current_cycle)
+{
+	uint8_t control = pad->control | 0x80;
+	uint8_t th = control & pad->output;
+	uint8_t input;
+	if (current_cycle >= pad->timeout_cycle) {
+		pad->th_counter = 0;
+	}
+	/*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
+		printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, context->current_cycle);
+	}*/
+	if (th) {
+		if (pad->th_counter == 3) {
+			input = pad->input[GAMEPAD_EXTRA];
+		} else {
+			input = pad->input[GAMEPAD_TH1];
+		}
+	} else {
+		if (pad->th_counter == 3) {
+			input = pad->input[GAMEPAD_TH0] | 0xF;
+		} else if(pad->th_counter == 4) {
+			input = pad->input[GAMEPAD_TH0]  & 0x30;
+		} else {
+			input = pad->input[GAMEPAD_TH0] | 0xC;
+		}
+	}
+	uint8_t value = ((~input) & (~control)) | (pad->output & control);
+	/*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
+		printf ("value: %X\n", value);
+	}*/
+	return value;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/io.h	Tue Jun 25 19:20:39 2013 -0700
@@ -0,0 +1,29 @@
+#ifndef IO_H_
+#define IO_H_
+#include <stdint.h>
+
+typedef struct {
+	uint32_t th_counter;
+	uint32_t timeout_cycle;
+	uint8_t output;
+	uint8_t control;
+	uint8_t input[3];
+} io_port;
+
+#define GAMEPAD_TH0 0
+#define GAMEPAD_TH1 1
+#define GAMEPAD_EXTRA 2
+#define GAMEPAD_NONE 0xF
+
+void set_keybindings();
+void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction);
+void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle);
+uint8_t io_data_read(io_port * pad, uint32_t current_cycle);
+void handle_keydown(int keycode);
+void handle_keyup(int keycode);
+void handle_joydown(int joystick, int button);
+void handle_joyup(int joystick, int button);
+void handle_joy_dpad(int joystick, int dpad, uint8_t state);
+
+#endif //IO_H_
+
--- a/render_sdl.c	Mon Jun 24 21:32:25 2013 -0700
+++ b/render_sdl.c	Tue Jun 25 19:20:39 2013 -0700
@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include "render.h"
 #include "blastem.h"
+#include "io.h"
 
 SDL_Surface *screen;
 uint8_t render_dbg = 0;