changeset 523:450c7745379a

Merge
author Michael Pavone <pavone@retrodev.com>
date Tue, 11 Feb 2014 21:52:15 -0800
parents 6a14c5a95648 (current diff) 0b21a1a73fb7 (diff)
children fb39534b6604
files
diffstat 7 files changed, 450 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- a/68kinst.c	Tue Feb 11 12:52:28 2014 -0800
+++ b/68kinst.c	Tue Feb 11 21:52:15 2014 -0800
@@ -1,6 +1,6 @@
 /*
  Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
+ This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include "68kinst.h"
@@ -434,8 +434,8 @@
 				}
 				break;
 			case 7:
-				
-				
+
+
 				break;
 			}
 		}
@@ -459,7 +459,7 @@
 		}
 		break;
 	case MISC:
-		
+
 		if ((*istream & 0x1C0) == 0x1C0) {
 			decoded->op = M68K_LEA;
 			decoded->extra.size = OPSIZE_LONG;
@@ -682,7 +682,7 @@
 								}
 							}
 						}
-						break;	
+						break;
 					case 6:
 						//MULU, MULS, DIVU, DIVUL, DIVS, DIVSL
 #ifdef M68020
@@ -918,7 +918,7 @@
 					decoded->op = M68K_INVALID;
 					return start+1;
 				}
-				break;		
+				break;
 			}
 		} else {
 			decoded->op = M68K_OR;
@@ -1259,7 +1259,7 @@
 			}
 			decoded->dst.addr_mode = MODE_REG;
 			decoded->dst.params.regs.pri = *istream & 0x7;
-			
+
 		} else {
 #ifdef M68020
 			//TODO: Implement bitfield instructions for M68020+ support
@@ -1273,6 +1273,79 @@
 	return istream+1;
 }
 
+uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs)
+{
+	if(inst->op == M68K_BCC || inst->op == M68K_BSR || inst->op == M68K_DBCC) {
+		return inst->address + 2 + inst->src.params.immed;
+	} else if(inst->op == M68K_JMP || inst->op == M68K_JSR) {
+		uint32_t ret = 0;
+		switch(inst->src.addr_mode)
+		{
+		case MODE_AREG_INDIRECT:
+			ret = aregs[inst->src.params.regs.pri];
+			break;
+		case MODE_AREG_INDEX_DISP8: {
+			uint8_t sec_reg = inst->src.params.regs.sec >> 1 & 0x7;
+			ret = aregs[inst->src.params.regs.pri];
+			uint32_t * regfile = inst->src.params.regs.sec & 0x10 ? aregs : dregs;
+			if (inst->src.params.regs.sec & 1) {
+				//32-bit index register
+				ret += regfile[sec_reg];
+			} else {
+				//16-bit index register
+				if (regfile[sec_reg] & 0x8000) {
+					ret += (0xFFFF0000 | regfile[sec_reg]);
+				} else {
+					ret += regfile[sec_reg];
+				}
+			}
+			ret += inst->src.params.regs.displacement;
+			break;
+		}
+		case MODE_PC_DISPLACE:
+			ret = inst->src.params.regs.displacement + inst->address + 2;
+			break;
+		case MODE_PC_INDEX_DISP8: {
+			uint8_t sec_reg = inst->src.params.regs.sec >> 1 & 0x7;
+			ret = inst->address + 2;
+			uint32_t * regfile = inst->src.params.regs.sec & 0x10 ? aregs : dregs;
+			if (inst->src.params.regs.sec & 1) {
+				//32-bit index register
+				ret += regfile[sec_reg];
+			} else {
+				//16-bit index register
+				if (regfile[sec_reg] & 0x8000) {
+					ret += (0xFFFF0000 | regfile[sec_reg]);
+				} else {
+					ret += regfile[sec_reg];
+				}
+			}
+			ret += inst->src.params.regs.displacement;
+			break;
+		}
+		case MODE_ABSOLUTE:
+		case MODE_ABSOLUTE_SHORT:
+			ret = inst->src.params.immed;
+			break;
+		}
+		return ret;
+	}
+	return 0;
+}
+
+uint8_t m68k_is_branch(m68kinst * inst)
+{
+	return (inst->op == M68K_BCC && inst->extra.cond != COND_FALSE)
+		|| (inst->op == M68K_DBCC && inst->extra.cond != COND_TRUE)
+		|| inst->op == M68K_BSR || inst->op == M68K_JMP || inst->op == M68K_JSR;
+}
+
+uint8_t m68k_is_noncall_branch(m68kinst * inst)
+{
+	return m68k_is_branch(inst) && inst->op != M68K_BSR && inst->op != M68K_JSR;
+}
+
+
 char * mnemonics[] = {
 	"abcd",
 	"add",
@@ -1504,7 +1577,7 @@
 		break;
 	case M68K_BSR:
 		if (labels) {
-			ret = sprintf(dst, "bsr%s ADR_%X", decoded->variant == VAR_BYTE ? ".s" : "", 
+			ret = sprintf(dst, "bsr%s ADR_%X", decoded->variant == VAR_BYTE ? ".s" : "",
 			decoded->address + 2 + decoded->src.params.immed);
 		} else {
 			ret = sprintf(dst, "bsr%s #%d <%X>", decoded->variant == VAR_BYTE ? ".s" : "", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
@@ -1540,9 +1613,9 @@
 		return ret;
 	default:
 		size = decoded->extra.size;
-		ret = sprintf(dst, "%s%s%s", 
-				mnemonics[decoded->op], 
-				decoded->variant == VAR_QUICK ? "q" : (decoded->variant == VAR_IMMEDIATE ? "i" : ""), 
+		ret = sprintf(dst, "%s%s%s",
+				mnemonics[decoded->op],
+				decoded->variant == VAR_QUICK ? "q" : (decoded->variant == VAR_IMMEDIATE ? "i" : ""),
 				size == OPSIZE_BYTE ? ".b" : (size == OPSIZE_WORD ? ".w" : (size == OPSIZE_LONG ? ".l" : "")));
 	}
 	if (decoded->op == M68K_MOVEM) {
--- a/68kinst.h	Tue Feb 11 12:52:28 2014 -0800
+++ b/68kinst.h	Tue Feb 11 21:52:15 2014 -0800
@@ -1,6 +1,6 @@
 /*
  Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
+ This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #ifndef M68KINST_H_
@@ -230,7 +230,9 @@
 } m68k_vector;
 
 uint16_t * m68k_decode(uint16_t * istream, m68kinst * dst, uint32_t address);
-uint32_t m68k_cycles(m68kinst * inst);
+uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs);
+uint8_t m68k_is_branch(m68kinst * inst);
+uint8_t m68k_is_noncall_branch(m68kinst * inst);
 int m68k_disasm(m68kinst * decoded, char * dst);
 int m68k_disasm_labels(m68kinst * decoded, char * dst);
 
--- a/Makefile	Tue Feb 11 12:52:28 2014 -0800
+++ b/Makefile	Tue Feb 11 21:52:15 2014 -0800
@@ -26,8 +26,8 @@
 
 all : dis zdis stateview vgmplay blastem
 
-blastem : blastem.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS)
-	$(CC) -ggdb -o blastem  blastem.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(LDFLAGS)
+blastem : blastem.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS)
+	$(CC) -ggdb -o blastem  blastem.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(LDFLAGS)
 
 dis : dis.o 68kinst.o
 	$(CC) -o dis dis.o 68kinst.o
--- a/blastem.c	Tue Feb 11 12:52:28 2014 -0800
+++ b/blastem.c	Tue Feb 11 21:52:15 2014 -0800
@@ -10,6 +10,7 @@
 #include "vdp.h"
 #include "render.h"
 #include "blastem.h"
+#include "gdb_remote.h"
 #include "gst.h"
 #include "util.h"
 #include <stdio.h>
@@ -1410,7 +1411,7 @@
 			case 'd':
 				param = find_param(input_buf);
 				if (!param) {
-					fputs("b command requires a parameter\n", stderr);
+					fputs("d command requires a parameter\n", stderr);
 					break;
 				}
 				value = atoi(param);
@@ -1464,16 +1465,80 @@
 				printf(format, param, value);
 				break;
 			case 'n':
-				//TODO: Deal with jmp, dbcc, rtr and rte
+				if (inst.op == M68K_RTS) {
+					after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
+				} else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
+					after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
+				} else if(m68k_is_noncall_branch(&inst)) {
+					if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
+						branch_f = after;
+						branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
+						insert_breakpoint(context, branch_t, (uint8_t *)debugger);
+					} else if(inst.op == M68K_DBCC) {
+						if ( inst.extra.cond == COND_FALSE) {
+							if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
+								after = m68k_branch_target(&inst, context->dregs, context->aregs);
+							}
+						} else {
+							branch_t = after;
+							branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
+							insert_breakpoint(context, branch_f, (uint8_t *)debugger);
+						}
+					} else {
+						after = m68k_branch_target(&inst, context->dregs, context->aregs);
+					}
+				}
+				insert_breakpoint(context, after, (uint8_t *)debugger);
+				debugging = 0;
+				break;
+			case 'o':
 				if (inst.op == M68K_RTS) {
 					after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
-				} else if(inst.op == M68K_BCC && inst.extra.cond != COND_FALSE) {
-					if (inst.extra.cond = COND_TRUE) {
-						after = inst.address + 2 + inst.src.params.immed;
+				} else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
+					after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
+				} else if(m68k_is_noncall_branch(&inst)) {
+					if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
+						branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
+						if (branch_t < after) {
+								branch_t = 0;
+						} else {
+							branch_f = after;
+							insert_breakpoint(context, branch_t, (uint8_t *)debugger);
+						}
+					} else if(inst.op == M68K_DBCC) {
+						uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs);
+						if (target > after) {
+							if (inst.extra.cond == COND_FALSE) {
+								after = target;
+							} else {
+								branch_f = target;
+								branch_t = after;
+								insert_breakpoint(context, branch_f, (uint8_t *)debugger);
+							}
+						}
 					} else {
+						after = m68k_branch_target(&inst, context->dregs, context->aregs);
+					}
+				}
+				insert_breakpoint(context, after, (uint8_t *)debugger);
+				debugging = 0;
+				break;
+			case 's':
+				if (inst.op == M68K_RTS) {
+					after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
+				} else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
+					after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
+				} else if(m68k_is_branch(&inst)) {
+					if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
 						branch_f = after;
-						branch_t = inst.address + 2 + inst.src.params.immed;
+						branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
 						insert_breakpoint(context, branch_t, (uint8_t *)debugger);
+					} else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) {
+						branch_t = after;
+						branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
+						insert_breakpoint(context, branch_f, (uint8_t *)debugger);
+					} else {
+						after = m68k_branch_target(&inst, context->dregs, context->aregs);
 					}
 				}
 				insert_breakpoint(context, after, (uint8_t *)debugger);
@@ -1585,7 +1650,7 @@
 	printf("Saved SRAM to %s\n", sram_filename);
 }
 
-void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * statefile)
+void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, uint8_t * debugger)
 {
 	m68k_context context;
 	x86_68k_options opts;
@@ -1706,15 +1771,15 @@
 			exit(1);
 		}
 		printf("Loaded %s\n", statefile);
-		if (debug) {
-			insert_breakpoint(&context, pc, (uint8_t *)debugger);
+		if (debugger) {
+			insert_breakpoint(&context, pc, debugger);
 		}
 		adjust_int_cycle(gen->m68k, gen->vdp);
 		gen->z80->native_pc =  z80_get_native_address_trans(gen->z80, gen->z80->pc);
 		start_68k_context(&context, pc);
 	} else {
-		if (debug) {
-			insert_breakpoint(&context, address, (uint8_t *)debugger);
+		if (debugger) {
+			insert_breakpoint(&context, address, debugger);
 		}
 		m68k_reset(&context);
 	}
@@ -1808,6 +1873,7 @@
 	char * romfname = NULL;
 	FILE *address_log = NULL;
 	char * statefile = NULL;
+	uint8_t * debuggerfun = NULL;
 	uint8_t fullscreen = 0, use_gl = 1;
 	for (int i = 1; i < argc; i++) {
 		if (argv[i][0] == '-') {
@@ -1822,7 +1888,11 @@
 				exit_after = atoi(argv[i]);
 				break;
 			case 'd':
-				debug = 1;
+				debuggerfun = (uint8_t *)debugger;
+				break;
+			case 'D':
+				gdb_remote_init();
+				debuggerfun = (uint8_t *)gdb_debug_enter;
 				break;
 			case 'f':
 				fullscreen = 1;
@@ -1980,6 +2050,6 @@
 	}
 	set_keybindings();
 
-	init_run_cpu(&gen, debug, address_log, statefile);
+	init_run_cpu(&gen, address_log, statefile, debuggerfun);
 	return 0;
 }
--- a/gdb_remote.c	Tue Feb 11 12:52:28 2014 -0800
+++ b/gdb_remote.c	Tue Feb 11 21:52:15 2014 -0800
@@ -3,14 +3,15 @@
  This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
-#include "blastem.h"
+#include "gdb_remote.h"
 #include <unistd.h>
 #include <fcntl.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 
-#define INITIAL_BUFFER_SIZE 4096
+#define INITIAL_BUFFER_SIZE (16*1024)
 
 char * buf = NULL;
 char * curbuf = NULL;
@@ -20,9 +21,261 @@
 int expect_break_response=0;
 uint32_t resume_pc;
 
-void gdb_debug_enter(genesis_context * gen, uint32_t pc)
+
+void hex_32(uint32_t num, char * out)
+{
+	for (int32_t shift = 28; shift >= 0; shift -= 4)
+	{
+		uint8_t nibble = num >> shift & 0xF;
+		*(out++) = nibble > 9 ? nibble - 0xA + 'A' : nibble + '0';
+	}
+}
+
+void hex_16(uint16_t num, char * out)
+{
+	for (int16_t shift = 14; shift >= 0; shift -= 4)
+	{
+		uint8_t nibble = num >> shift & 0xF;
+		*(out++) = nibble > 9 ? nibble - 0xA + 'A' : nibble + '0';
+	}
+}
+
+void hex_8(uint8_t num, char * out)
+{
+	uint8_t nibble = num >> 4;
+	*(out++) = nibble > 9 ? nibble - 0xA + 'A' : nibble + '0';
+	nibble = num & 0xF;
+	*out = nibble > 9 ? nibble - 0xA + 'A' : nibble + '0';
+}
+
+void gdb_calc_checksum(char * command, char *out)
+{
+	uint8_t checksum = 0;
+	while (*command)
+	{
+		checksum += *(command++);
+	}
+	hex_8(checksum, out);
+}
+
+void write_or_die(int fd, const void *buf, size_t count)
+{
+	if (write(fd, buf, count) < count) {
+		fputs("Error writing to stdout\n", stderr);
+		exit(1);
+	}
+}
+
+void gdb_send_command(char * command)
+{
+	char end[3];
+	write_or_die(STDOUT_FILENO, "$", 1);
+	write_or_die(STDOUT_FILENO, command, strlen(command));
+	end[0] = '#';
+	gdb_calc_checksum(command, end+1);
+	write_or_die(STDOUT_FILENO, end, 3);
+	fprintf(stderr, "Sent $%s#%c%c\n", command, end[1], end[2]);
+}
+
+uint32_t calc_status(m68k_context * context)
+{
+	uint32_t status = context->status << 3;
+	for (int i = 0; i < 5; i++)
+	{
+		status <<= 1;
+		status |= context->flags[i];
+	}
+	return status;
+}
+
+uint8_t read_byte(m68k_context * context, uint32_t address)
+{
+	uint16_t * word;
+	//TODO: Use generated read/write functions so that memory map is properly respected
+	if (address < 0x400000) {
+		word = context->mem_pointers[0] + address/2;
+	} else if (address >= 0xE00000) {
+		word = context->mem_pointers[1] + (address & 0xFFFF)/2;
+	} else {
+		return 0;
+	}
+	if (address & 1) {
+		return *word;
+	}
+	return *word >> 8;
+}
+
+void gdb_run_command(m68k_context * context, uint32_t pc, char * command)
 {
-	fcntl(STDIN_FILENO, FD_SETFL, 0);
+	char send_buf[512];
+	fprintf(stderr, "Received command %s\n", command);
+	switch(*command)
+	{
+
+	case 'c':
+		if (*(command+1) != 0) {
+			//TODO: implement resuming at an arbitrary address
+			goto not_impl;
+		}
+		cont = 1;
+		expect_break_response = 1;
+		break;
+	case 'H':
+		if (command[1] == 'g' || command[1] == 'c') {;
+			//no thread suport, just acknowledge
+			gdb_send_command("OK");
+		} else {
+			goto not_impl;
+		}
+		break;
+	case 'Z': {
+		uint8_t type = command[1];
+		if (type < '2') {
+			uint32_t address = strtoul(command+3, NULL, 16);
+			insert_breakpoint(context, address, (uint8_t *)gdb_debug_enter);
+			gdb_send_command("OK");
+		} else {
+			//watchpoints are not currently supported
+			gdb_send_command("");
+		}
+		break;
+	}
+	case 'z': {
+		uint8_t type = command[1];
+		if (type < '2') {
+			uint32_t address = strtoul(command+3, NULL, 16);
+			remove_breakpoint(context, address);
+			gdb_send_command("OK");
+		} else {
+			//watchpoints are not currently supported
+			gdb_send_command("");
+		}
+		break;
+	}
+	case 'g': {
+		char * cur = send_buf;
+		for (int i = 0; i < 8; i++)
+		{
+			hex_32(context->dregs[i], cur);
+			cur += 8;
+		}
+		for (int i = 0; i < 8; i++)
+		{
+			hex_32(context->aregs[i], cur);
+			cur += 8;
+		}
+		hex_32(calc_status(context), cur);
+		cur += 8;
+		hex_32(pc, cur);
+		cur += 8;
+		*cur = 0;
+		gdb_send_command(send_buf);
+		break;
+	}
+	case 'm': {
+		char * rest;
+		uint32_t address = strtoul(command+1, &rest, 16);
+		uint32_t size = strtoul(rest+1, NULL, 16);
+		if (size > sizeof(send_buf-1)/2) {
+			size = sizeof(send_buf-1)/2;
+		}
+		char *cur = send_buf;
+		while (size)
+		{
+			hex_8(read_byte(context, address), cur);
+			cur += 2;
+			address++;
+			size--;
+		}
+		*cur = 0;
+		gdb_send_command(send_buf);
+		break;
+	}
+	case 'p': {
+		unsigned long reg = strtoul(command+1, NULL, 16);
+
+		if (reg < 8) {
+			hex_32(context->dregs[reg], send_buf);
+		} else if (reg < 16) {
+			hex_32(context->aregs[reg-8], send_buf);
+		} else if (reg == 16) {
+			hex_32(calc_status(context), send_buf);
+		} else if (reg == 17) {
+			hex_32(pc, send_buf);
+		} else {
+			send_buf[0] = 0;
+		}
+		send_buf[8] = 0;
+		gdb_send_command(send_buf);
+		break;
+	}
+	case 'q':
+		if (!memcmp("Supported", command+1, strlen("Supported"))) {
+			sprintf(send_buf, "PacketSize=%X", (int)bufsize);
+			gdb_send_command(send_buf);
+		} else if (!memcmp("Attached", command+1, strlen("Supported"))) {
+			//not really meaningful for us, but saying we spawned a new process
+			//is probably closest to the truth
+			gdb_send_command("0");
+		} else if (!memcmp("Offsets", command+1, strlen("Offsets"))) {
+			//no relocations, so offsets are all 0
+			gdb_send_command("Text=0;Data=0;Bss=0");
+		} else if (!memcmp("Symbol", command+1, strlen("Symbol"))) {
+			gdb_send_command("");
+		} else if (!memcmp("TStatus", command+1, strlen("TStatus"))) {
+			//TODO: actual tracepoint support
+			gdb_send_command("T0;tnotrun:0");
+		} else if (!memcmp("TfV", command+1, strlen("TfV")) || !memcmp("TfP", command+1, strlen("TfP"))) {
+			//TODO: actual tracepoint support
+			gdb_send_command("");
+		} else if (command[1] == 'C') {
+			//we only support a single thread currently, so send 1
+			gdb_send_command("1");
+		} else {
+			goto not_impl;
+		}
+		break;
+	case 'v':
+		if (!memcmp("Cont?", command+1, strlen("Cont?"))) {
+			gdb_send_command("vCont;c;C;s;S");
+		} else if (!memcmp("Cont;", command+1, strlen("Cont;"))) {
+			switch (*(command + 1 + strlen("Cont;")))
+			{
+			case 'c':
+			case 'C':
+				//might be interesting to have continue with signal fire a
+				//trap exception or something, but for no we'll treat it as
+				//a normal continue
+				cont = 1;
+				expect_break_response = 1;
+				break;
+			default:
+				goto not_impl;
+			}
+		} else {
+			goto not_impl;
+		}
+		break;
+	case '?':
+		gdb_send_command("S05");
+		break;
+	default:
+		goto not_impl;
+
+	}
+	return;
+not_impl:
+	fprintf(stderr, "Command %s is not implemented, exiting...\n", command);
+	exit(1);
+}
+
+m68k_context *  gdb_debug_enter(m68k_context * context, uint32_t pc)
+{
+	fprintf(stderr, "Entered debugger at address %X\n", pc);
+	if (expect_break_response) {
+		gdb_send_command("S05");
+		expect_break_response = 0;
+	}
 	resume_pc = pc;
 	cont = 0;
 	uint8_t partial = 0;
@@ -35,7 +288,7 @@
 		} else if (partial) {
 			if (curbuf != buf) {
 				memmove(curbuf, buf, end-curbuf);
-				end -= cufbuf - buf;
+				end -= curbuf - buf;
 			}
 			int numread = read(STDIN_FILENO, end, bufsize - (end-buf));
 			end += numread;
@@ -55,10 +308,13 @@
 					if (end-curbuf >= 2) {
 						//TODO: verify checksum
 						//Null terminate payload
-						*curbuf = 0
+						*curbuf = 0;
 						//send acknowledgement
-						write(FILENO_STDOUT, "+", 1);
-						gdb_run_command(genesis_context * gen, start);
+						if (write(STDOUT_FILENO, "+", 1) < 1) {
+							fputs("Error writing to stdout\n", stderr);
+							exit(1);
+						}
+						gdb_run_command(context, pc, start);
 						curbuf += 2;
 					}
 				} else {
@@ -66,115 +322,20 @@
 					partial = 1;
 					break;
 				}
+			} else {
+				fprintf(stderr, "Ignoring character %c\n", *curbuf);
 			}
 		}
+		if (curbuf == end) {
+			curbuf = NULL;
+		}
 	}
-	fcntl(STDIN_FILENO, FD_SETFL, O_NONBLOCK);
-}
-
-void gdb_run_command(genesis_context * gen, char * command)
-{
-	switch(*command)
-	{
-	case 'c':
-		if (*(command+1) != 0) {
-			resume_pc =
-		}
-		cont = 1;
-		expect_break_response = 1;
-		break;
-	case 's':
-
-	}
+	return context;
 }
 
-void gdb_run_commands(genesis_context * gen)
+void gdb_remote_init(void)
 {
-	int enter_debugger = 0;
-	char * cur = buf;
-	while(cur < curbuf);
-	{
-		if(*cur == '$') {
-			cur++
-			char * start = cur;
-			while (cur < curbuf && *cur != '#') {
-				cur++;
-			}
-			if (*cur == '#') {
-				//check to make sure we've received the checksum bytes
-				if (curbuf-cur >= 2) {
-					//TODO: verify checksum
-					//Null terminate payload
-					//send acknowledgement
-					write(FILENO_STDOUT, "+", 1);
-					gdb_run_command(genesis_context * gen, start);
-					cur += 2;
-				} else {
-					cur = start - 1;
-					break;
-				}
-			} else {
-				cur = start - 1;
-				break;
-			}
-		} else {
-			if (*cur == 0x03) {
-				enter_debugger = 1;
-			}
-			cur++;
-		}
-	}
-
-	//FIXME
-	if (consumed == curbuf-buf) {
-		curbuf = buf;
-	} else if (consumed > 0) {
-		memmove(buf, buf + consumed, curbuf - buf - consumed);
-		curbuf -= consumed;
-	}
+	buf = malloc(INITIAL_BUFFER_SIZE);
+	curbuf = NULL;
+	bufsize = INITIAL_BUFFER_SIZE;
 }
-
-int gdb_command_poll(genesis_context * gen)
-{
-	for(;;)
-	{
-		if (curbuf == buf + bufsize) {
-			//buffer is full, expand it
-			bufsize *= 2;
-			buf = realloc(buf, bufsize);
-			if (!buf) {
-				fprintf(stderr, "Failed to grow GDB command buffer to %d bytes\n", (int)bufsize);
-				exit(1);
-			}
-			curbuf = buf + bufsize/2;
-		}
-		int numread = read(STDIN_FILENO, buf, bufsize);
-		if (numread < 0) {
-			if (errno == EAGAIN || errno == EWOULDBLOCK) {
-				return 0;
-			} else {
-				fprintf(stderr, "Error %d while reading GDB commands from stdin", errno);
-				exit(1);
-			}
-		} else if (numread == 0) {
-			exit(0);
-		}
-		for (curbuf = buf, end = buf+numread; curbuf < end; curbuf++)
-		{
-			if (*curbuf = 0x03)
-			{
-				curbuf++;
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-void gdb_remote_init()
-{
-	fcntl(STDIN_FILENO, FD_SETFL, O_NONBLOCK);
-	buf = malloc(INITIAL_BUFFER_SIZE);
-	curbuf = buf;
-	bufzie = INITIAL_BUFFER_SIZE;
-}
--- a/m68k_to_x86.c	Tue Feb 11 12:52:28 2014 -0800
+++ b/m68k_to_x86.c	Tue Feb 11 21:52:15 2014 -0800
@@ -1953,6 +1953,7 @@
 		}
 		sec_reg = (inst->src.params.regs.sec >> 1) & 0x7;
 		if (inst->src.params.regs.sec & 1) {
+			//32-bit index register
 			if (inst->src.params.regs.sec & 0x10) {
 				if (opts->aregs[sec_reg] >= 0) {
 					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
@@ -1967,6 +1968,7 @@
 				}
 			}
 		} else {
+			//16-bit index register
 			if (inst->src.params.regs.sec & 0x10) {
 				if (opts->aregs[sec_reg] >= 0) {
 					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
--- a/vdp.c	Tue Feb 11 12:52:28 2014 -0800
+++ b/vdp.c	Tue Feb 11 21:52:15 2014 -0800
@@ -197,7 +197,7 @@
 		uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3;
 		uint8_t pri = context->vdpmem[address + 4] >> 7;
 		uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5;
-		//printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern);
+		printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern);
 		current_index = link;
 		count++;
 	} while (current_index != 0 && count < 80);