main debug.c
   1#include "debug.h"
   2#include "genesis.h"
   3#include "68kinst.h"
   4#include <stdlib.h>
   5#include <string.h>
   6#include <sys/select.h>
   7#include "render.h"
   8#include "util.h"
   9#include "terminal.h"
  10#include "z80inst.h"
  11
  12#define Z80_OPTS options
  13
  14static bp_def * breakpoints = NULL;
  15static bp_def * zbreakpoints = NULL;
  16static uint32_t bp_index = 0;
  17static uint32_t zbp_index = 0;
  18
  19bp_def ** find_breakpoint(bp_def ** cur, uint32_t address)
  20{
  21	while (*cur) {
  22		if ((*cur)->address == address) {
  23			break;
  24		}
  25		cur = &((*cur)->next);
  26	}
  27	return cur;
  28}
  29
  30bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index)
  31{
  32	while (*cur) {
  33		if ((*cur)->index == index) {
  34			break;
  35		}
  36		cur = &((*cur)->next);
  37	}
  38	return cur;
  39}
  40
  41disp_def * displays = NULL;
  42disp_def * zdisplays = NULL;
  43uint32_t disp_index = 0;
  44uint32_t zdisp_index = 0;
  45
  46void add_display(disp_def ** head, uint32_t *index, char format_char, char * param)
  47{
  48	disp_def * ndisp = malloc(sizeof(*ndisp));
  49	ndisp->format_char = format_char;
  50	ndisp->param = strdup(param);
  51	ndisp->next = *head;
  52	ndisp->index = *index++;
  53	*head = ndisp;
  54}
  55
  56void remove_display(disp_def ** head, uint32_t index)
  57{
  58	while (*head) {
  59		if ((*head)->index == index) {
  60			disp_def * del_disp = *head;
  61			*head = del_disp->next;
  62			free(del_disp->param);
  63			free(del_disp);
  64		} else {
  65			head = &(*head)->next;
  66		}
  67	}
  68}
  69
  70char * find_param(char * buf)
  71{
  72	for (; *buf; buf++) {
  73		if (*buf == ' ') {
  74			if (*(buf+1)) {
  75				return buf+1;
  76			}
  77		}
  78	}
  79	return NULL;
  80}
  81
  82void strip_nl(char * buf)
  83{
  84	for(; *buf; buf++) {
  85		if (*buf == '\n') {
  86			*buf = 0;
  87			return;
  88		}
  89	}
  90}
  91
  92uint16_t m68k_read_word(uint32_t address, m68k_context *context)
  93{
  94	return read_word(address, (void **)context->mem_pointers, &context->options->gen, context);
  95}
  96
  97uint32_t m68k_read_long(uint32_t address, m68k_context *context)
  98{
  99	return m68k_read_word(address, context) << 16 | m68k_read_word(address + 2, context);
 100}
 101
 102void debugger_print(m68k_context *context, char format_char, char *param)
 103{
 104	uint32_t value;
 105	char format[8];
 106	strcpy(format, "%s: %d\n");
 107	switch (format_char)
 108	{
 109	case 'x':
 110	case 'X':
 111	case 'd':
 112	case 'c':
 113		format[5] = format_char;
 114		break;
 115	case '\0':
 116		break;
 117	default:
 118		fprintf(stderr, "Unrecognized format character: %c\n", format_char);
 119	}
 120	if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
 121		value = context->dregs[param[1]-'0'];
 122		if (param[2] == '.') {
 123			if (param[3] == 'w') {
 124				value &= 0xFFFF;
 125			} else if (param[3] == 'b') {
 126				value &= 0xFF;
 127			}
 128		}
 129	} else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') {
 130		value = context->aregs[param[1]-'0'];
 131		if (param[2] == '.') {
 132			if (param[3] == 'w') {
 133				value &= 0xFFFF;
 134			} else if (param[3] == 'b') {
 135				value &= 0xFF;
 136			}
 137		}
 138	} else if (param[0] == 'S' && param[1] == 'R') {
 139		value = (context->status << 8);
 140		for (int flag = 0; flag < 5; flag++) {
 141			value |= context->flags[flag] << (4-flag);
 142		}
 143	} else if(param[0] == 'c') {
 144		value = context->current_cycle;
 145	} else if(param[0] == 'f') {
 146		genesis_context *gen = context->system;
 147		value = gen->vdp->frame;
 148	} else if ((param[0] == '0' && param[1] == 'x') || param[0] == '$') {
 149		char *after;
 150		uint32_t p_addr = strtol(param+(param[0] == '0' ? 2 : 1), &after, 16);
 151		if (after[0] == '.' && after[1] == 'l') {
 152			value = m68k_read_long(p_addr, context);
 153		} else {
 154			value = m68k_read_word(p_addr, context);
 155		}
 156	} else if(param[0] == '(' && (param[1] == 'a' || param[1] == 'd') && param[2] >= '0' && param[2] <= '7' && param[3] == ')') {
 157		uint8_t reg = param[2] - '0';
 158		uint32_t p_addr = param[1] == 'a' ? context->aregs[reg] : context->dregs[reg];
 159		if (param[4] == '.' && param[5] == 'l') {
 160			value = m68k_read_long(p_addr, context);
 161		} else {
 162			value = m68k_read_word(p_addr, context);
 163		}
 164	} else {
 165		fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
 166		return;
 167	}
 168	printf(format, param, value);
 169}
 170
 171void zdebugger_print(z80_context * context, char format_char, char * param)
 172{
 173	uint32_t value;
 174	char format[8];
 175	strcpy(format, "%s: %d\n");
 176	genesis_context *system = context->system;
 177	switch (format_char)
 178	{
 179	case 'x':
 180	case 'X':
 181	case 'd':
 182	case 'c':
 183		format[5] = format_char;
 184		break;
 185	case '\0':
 186		break;
 187	default:
 188		fprintf(stderr, "Unrecognized format character: %c\n", format_char);
 189	}
 190	switch (param[0])
 191	{
 192	case 'a':
 193		if (param[1] == 'f') {
 194			if(param[2] == '\'') {
 195				value = context->alt_regs[Z80_A] << 8;
 196				value |= context->alt_flags[ZF_S] << 7;
 197				value |= context->alt_flags[ZF_Z] << 6;
 198				value |= context->alt_flags[ZF_H] << 4;
 199				value |= context->alt_flags[ZF_PV] << 2;
 200				value |= context->alt_flags[ZF_N] << 1;
 201				value |= context->alt_flags[ZF_C];
 202			} else {
 203				value = context->regs[Z80_A] << 8;
 204				value |= context->flags[ZF_S] << 7;
 205				value |= context->flags[ZF_Z] << 6;
 206				value |= context->flags[ZF_H] << 4;
 207				value |= context->flags[ZF_PV] << 2;
 208				value |= context->flags[ZF_N] << 1;
 209				value |= context->flags[ZF_C];
 210			}
 211		} else if(param[1] == '\'') {
 212			value = context->alt_regs[Z80_A];
 213		} else {
 214			value = context->regs[Z80_A];
 215		}
 216		break;
 217	case 'b':
 218		if (param[1] == 'c') {
 219			if(param[2] == '\'') {
 220				value = context->alt_regs[Z80_B] << 8;
 221				value |= context->alt_regs[Z80_C];
 222			} else {
 223				value = context->regs[Z80_B] << 8;
 224				value |= context->regs[Z80_C];
 225			}
 226		} else if(param[1] == '\'') {
 227			value = context->alt_regs[Z80_B];
 228		} else if(param[1] == 'a') {
 229			value = context->bank_reg << 15;
 230		} else {
 231			value = context->regs[Z80_B];
 232		}
 233		break;
 234	case 'c':
 235		if(param[1] == '\'') {
 236			value = context->alt_regs[Z80_C];
 237		} else if(param[1] == 'y') {
 238			value = context->current_cycle;
 239		} else {
 240			value = context->regs[Z80_C];
 241		}
 242		break;
 243	case 'd':
 244		if (param[1] == 'e') {
 245			if(param[2] == '\'') {
 246				value = context->alt_regs[Z80_D] << 8;
 247				value |= context->alt_regs[Z80_E];
 248			} else {
 249				value = context->regs[Z80_D] << 8;
 250				value |= context->regs[Z80_E];
 251			}
 252		} else if(param[1] == '\'') {
 253			value = context->alt_regs[Z80_D];
 254		} else {
 255			value = context->regs[Z80_D];
 256		}
 257		break;
 258	case 'e':
 259		if(param[1] == '\'') {
 260			value = context->alt_regs[Z80_E];
 261		} else {
 262			value = context->regs[Z80_E];
 263		}
 264		break;
 265	case 'f':
 266		if(param[2] == '\'') {
 267			value = context->alt_flags[ZF_S] << 7;
 268			value |= context->alt_flags[ZF_Z] << 6;
 269			value |= context->alt_flags[ZF_H] << 4;
 270			value |= context->alt_flags[ZF_PV] << 2;
 271			value |= context->alt_flags[ZF_N] << 1;
 272			value |= context->alt_flags[ZF_C];
 273		} else {
 274			value = context->flags[ZF_S] << 7;
 275			value |= context->flags[ZF_Z] << 6;
 276			value |= context->flags[ZF_H] << 4;
 277			value |= context->flags[ZF_PV] << 2;
 278			value |= context->flags[ZF_N] << 1;
 279			value |= context->flags[ZF_C];
 280		}
 281		break;
 282	case 'h':
 283		if (param[1] == 'l') {
 284			if(param[2] == '\'') {
 285				value = context->alt_regs[Z80_H] << 8;
 286				value |= context->alt_regs[Z80_L];
 287			} else {
 288				value = context->regs[Z80_H] << 8;
 289				value |= context->regs[Z80_L];
 290			}
 291		} else if(param[1] == '\'') {
 292			value = context->alt_regs[Z80_H];
 293		} else {
 294			value = context->regs[Z80_H];
 295		}
 296		break;
 297	case 'l':
 298		if(param[1] == '\'') {
 299			value = context->alt_regs[Z80_L];
 300		} else {
 301			value = context->regs[Z80_L];
 302		}
 303		break;
 304	case 'i':
 305		if(param[1] == 'x') {
 306			if (param[2] == 'h') {
 307				value = context->regs[Z80_IXH];
 308			} else if(param[2] == 'l') {
 309				value = context->regs[Z80_IXL];
 310			} else {
 311				value = context->regs[Z80_IXH] << 8;
 312				value |= context->regs[Z80_IXL];
 313			}
 314		} else if(param[1] == 'y') {
 315			if (param[2] == 'h') {
 316				value = context->regs[Z80_IYH];
 317			} else if(param[2] == 'l') {
 318				value = context->regs[Z80_IYL];
 319			} else {
 320				value = context->regs[Z80_IYH] << 8;
 321				value |= context->regs[Z80_IYL];
 322			}
 323		} else if(param[1] == 'n') {
 324			value = context->int_cycle;
 325		} else if(param[1] == 'f' && param[2] == 'f' && param[3] == '1') {
 326			value = context->iff1;
 327		} else if(param[1] == 'f' && param[2] == 'f' && param[3] == '2') {
 328			value = context->iff2;
 329		} else {
 330			value = context->im;
 331		}
 332		break;
 333	case 's':
 334		if (param[1] == 'p') {
 335			value = context->sp;
 336		}
 337		break;
 338	case '0':
 339		if (param[1] == 'x') {
 340			uint16_t p_addr = strtol(param+2, NULL, 16);
 341			if (p_addr < 0x4000) {
 342				value = system->zram[p_addr & 0x1FFF];
 343			} else if(p_addr >= 0x8000) {
 344				uint32_t v_addr = system->z80_bank_reg << 15;
 345				v_addr += p_addr & 0x7FFF;
 346				if (v_addr < 0x400000) {
 347					value = system->cart[v_addr/2];
 348				} else if(v_addr > 0xE00000) {
 349					value = system->work_ram[(v_addr & 0xFFFF)/2];
 350				}
 351				if (v_addr & 1) {
 352					value &= 0xFF;
 353				} else {
 354					value >>= 8;
 355				}
 356			}
 357		}
 358		break;
 359	}
 360	printf(format, param, value);
 361}
 362
 363z80_context * zdebugger(z80_context * context, uint16_t address)
 364{
 365	static char last_cmd[1024];
 366	char input_buf[1024];
 367	static uint16_t branch_t;
 368	static uint16_t branch_f;
 369	z80inst inst;
 370	genesis_context *system = context->system;
 371	init_terminal();
 372	//Check if this is a user set breakpoint, or just a temporary one
 373	bp_def ** this_bp = find_breakpoint(&zbreakpoints, address);
 374	if (*this_bp) {
 375		printf("Z80 Breakpoint %d hit\n", (*this_bp)->index);
 376	} else {
 377		zremove_breakpoint(context, address);
 378	}
 379	uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
 380	if (!pc) {
 381		fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address);
 382	}
 383	for (disp_def * cur = zdisplays; cur; cur = cur->next) {
 384		zdebugger_print(context, cur->format_char, cur->param);
 385	}
 386	uint8_t * after_pc = z80_decode(pc, &inst);
 387	z80_disasm(&inst, input_buf, address);
 388	printf("%X:\t%s\n", address, input_buf);
 389	uint16_t after = address + (after_pc-pc);
 390	int debugging = 1;
 391	while(debugging) {
 392		fputs(">", stdout);
 393		if (!fgets(input_buf, sizeof(input_buf), stdin)) {
 394			fputs("fgets failed", stderr);
 395			break;
 396		}
 397		strip_nl(input_buf);
 398		//hitting enter repeats last command
 399		if (input_buf[0]) {
 400			strcpy(last_cmd, input_buf);
 401		} else {
 402			strcpy(input_buf, last_cmd);
 403		}
 404		char * param;
 405		char format[8];
 406		uint32_t value;
 407		bp_def * new_bp;
 408		switch(input_buf[0])
 409		{
 410			case 'a':
 411				param = find_param(input_buf);
 412				if (!param) {
 413					fputs("a command requires a parameter\n", stderr);
 414					break;
 415				}
 416				value = strtol(param, NULL, 16);
 417				zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
 418				debugging = 0;
 419				break;
 420			case 'b':
 421				param = find_param(input_buf);
 422				if (!param) {
 423					fputs("b command requires a parameter\n", stderr);
 424					break;
 425				}
 426				value = strtol(param, NULL, 16);
 427				zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
 428				new_bp = malloc(sizeof(bp_def));
 429				new_bp->next = zbreakpoints;
 430				new_bp->address = value;
 431				new_bp->index = zbp_index++;
 432				new_bp->commands = NULL;
 433				zbreakpoints = new_bp;
 434				printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
 435				break;
 436			case 'c':
 437				puts("Continuing");
 438				debugging = 0;
 439				break;
 440			case 'd':
 441				if (input_buf[1] == 'i') {
 442					char format_char = 0;
 443					for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
 444						if (input_buf[i] == '/') {
 445							format_char = input_buf[i+1];
 446							break;
 447						}
 448					}
 449					param = find_param(input_buf);
 450					if (!param) {
 451						fputs("display command requires a parameter\n", stderr);
 452						break;
 453					}
 454					zdebugger_print(context, format_char, param);
 455					add_display(&zdisplays, &zdisp_index, format_char, param);
 456				} else if (input_buf[1] == 'e' || input_buf[1] == ' ') {
 457					param = find_param(input_buf);
 458					if (!param) {
 459						fputs("delete command requires a parameter\n", stderr);
 460						break;
 461					}
 462					if (param[0] >= '0' && param[0] <= '9') {
 463						value = atoi(param);
 464						this_bp = find_breakpoint_idx(&zbreakpoints, value);
 465						if (!*this_bp) {
 466							fprintf(stderr, "Breakpoint %d does not exist\n", value);
 467							break;
 468						}
 469						new_bp = *this_bp;
 470						zremove_breakpoint(context, new_bp->address);
 471						*this_bp = new_bp->next;
 472						free(new_bp);
 473					} else if (param[0] == 'd') {
 474						param = find_param(param);
 475						if (!param) {
 476							fputs("delete display command requires a parameter\n", stderr);
 477							break;
 478						}
 479						remove_display(&zdisplays, atoi(param));
 480					}
 481				}
 482				break;
 483			case 'n':
 484				//TODO: Handle conditional branch instructions
 485				if (inst.op == Z80_JP) {
 486					if (inst.addr_mode == Z80_IMMED) {
 487						after = inst.immed;
 488					} else if (inst.ea_reg == Z80_HL) {
 489						after = context->regs[Z80_H] << 8 | context->regs[Z80_L];
 490					} else if (inst.ea_reg == Z80_IX) {
 491						after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL];
 492					} else if (inst.ea_reg == Z80_IY) {
 493						after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL];
 494					}
 495				} else if(inst.op == Z80_JR) {
 496					after += inst.immed;
 497				} else if(inst.op == Z80_RET) {
 498					uint8_t *sp = get_native_pointer(context->sp, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
 499					if (sp) {
 500						after = *sp;
 501						sp = get_native_pointer((context->sp + 1) & 0xFFFF, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
 502						if (sp) {
 503							after |= *sp << 8;
 504						}
 505					}
 506				}
 507				zinsert_breakpoint(context, after, (uint8_t *)zdebugger);
 508				debugging = 0;
 509				break;
 510			case 'p':
 511				param = find_param(input_buf);
 512				if (!param) {
 513					fputs("p command requires a parameter\n", stderr);
 514					break;
 515				}
 516				zdebugger_print(context, input_buf[1] == '/' ? input_buf[2] : 0, param);
 517				break;
 518			case 'q':
 519				puts("Quitting");
 520				exit(0);
 521				break;
 522			case 's': {
 523				param = find_param(input_buf);
 524				if (!param) {
 525					fputs("s command requires a file name\n", stderr);
 526					break;
 527				}
 528				memmap_chunk const *ram_chunk = NULL;
 529				for (int i = 0; i < context->Z80_OPTS->gen.memmap_chunks; i++)
 530				{
 531					memmap_chunk const *cur = context->Z80_OPTS->gen.memmap + i;
 532					if (cur->flags & MMAP_WRITE) {
 533						ram_chunk = cur;
 534						break;
 535					}
 536				}
 537				if (ram_chunk) {
 538					uint32_t size = ram_chunk->end - ram_chunk->start;
 539					if (size > ram_chunk->mask) {
 540						size = ram_chunk->mask+1;
 541					}
 542					uint8_t *buf = get_native_pointer(ram_chunk->start, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
 543					FILE * f = fopen(param, "wb");
 544					if (f) {
 545						if(fwrite(buf, 1, size, f) != size) {
 546							fputs("Error writing file\n", stderr);
 547						}
 548						fclose(f);
 549						printf("Wrote %d bytes to %s\n", size, param);
 550					} else {
 551						fprintf(stderr, "Could not open %s for writing\n", param);
 552					}
 553				} else {
 554					fputs("Failed to find a RAM memory chunk\n", stderr);
 555				}
 556				break;
 557			}
 558			default:
 559				if (
 560					!context->Z80_OPTS->gen.debug_cmd_handler
 561					|| !context->Z80_OPTS->gen.debug_cmd_handler(&system->header, input_buf)
 562				) {
 563					fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
 564				}
 565				break;
 566		}
 567	}
 568	return context;
 569}
 570
 571static uint32_t branch_t;
 572static uint32_t branch_f;
 573
 574int run_debugger_command(m68k_context *context, char *input_buf, m68kinst inst, uint32_t after)
 575{
 576	char * param;
 577	char format_char;
 578	genesis_context *system = context->system;
 579	uint32_t value;
 580	bp_def *new_bp, **this_bp;
 581	switch(input_buf[0])
 582	{
 583		case 'c':
 584			if (input_buf[1] == 0 || input_buf[1] == 'o' && input_buf[2] == 'n')
 585			{
 586				puts("Continuing");
 587				return 0;
 588			} else if (input_buf[1] == 'o' && input_buf[2] == 'm') {
 589				param = find_param(input_buf);
 590				if (!param) {
 591					fputs("com command requires a parameter\n", stderr);
 592					break;
 593				}
 594				bp_def **target = find_breakpoint_idx(&breakpoints, atoi(param));
 595				if (!target) {
 596					fprintf(stderr, "Breakpoint %s does not exist!\n", param);
 597					break;
 598				}
 599				printf("Enter commands for breakpoing %d, type end when done\n", atoi(param));
 600				char cmd_buf[1024];
 601				char *commands = NULL;
 602				for (;;)
 603				{
 604					fputs(">>", stdout);
 605					fflush(stdout);
 606					fgets(cmd_buf, sizeof(cmd_buf), stdin);
 607					if (strcmp(cmd_buf, "end\n")) {
 608						if (commands) {
 609							char *tmp = commands;
 610							commands = alloc_concat(commands, cmd_buf);
 611							free(tmp);
 612						} else {
 613							commands = strdup(cmd_buf);
 614						}
 615					} else {
 616						break;
 617					}
 618				}
 619				(*target)->commands = commands;
 620			} else {
 621			}
 622			break;
 623		case 'b':
 624			if (input_buf[1] == 't') {
 625				uint32_t stack = context->aregs[7];
 626				if (stack >= 0xE00000) {
 627					stack &= 0xFFFF;
 628					uint8_t non_adr_count = 0;
 629					do {
 630						uint32_t bt_address = system->work_ram[stack/2] << 16 | system->work_ram[stack/2+1];
 631						bt_address = get_instruction_start(context->options, bt_address - 2);
 632						if (bt_address) {
 633							stack += 4;
 634							non_adr_count = 0;
 635							uint16_t *bt_pc = NULL;
 636							if (bt_address < 0x400000) {
 637								bt_pc = system->cart + bt_address/2;
 638							} else if(bt_address > 0xE00000) {
 639								bt_pc = system->work_ram + (bt_address & 0xFFFF)/2;
 640							}
 641							m68k_decode(bt_pc, &inst, bt_address);
 642							m68k_disasm(&inst, input_buf);
 643							printf("%X: %s\n", bt_address, input_buf);
 644						} else {
 645							//non-return address value on stack can be word wide
 646							stack += 2;
 647							non_adr_count++;
 648						}
 649						stack &= 0xFFFF;
 650					} while (stack && non_adr_count < 6);
 651				}
 652			} else {
 653				param = find_param(input_buf);
 654				if (!param) {
 655					fputs("b command requires a parameter\n", stderr);
 656					break;
 657				}
 658				value = strtol(param, NULL, 16);
 659				insert_breakpoint(context, value, debugger);
 660				new_bp = malloc(sizeof(bp_def));
 661				new_bp->next = breakpoints;
 662				new_bp->address = value;
 663				new_bp->index = bp_index++;
 664				new_bp->commands = NULL;
 665				breakpoints = new_bp;
 666				printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
 667			}
 668			break;
 669		case 'a':
 670			param = find_param(input_buf);
 671			if (!param) {
 672				fputs("a command requires a parameter\n", stderr);
 673				break;
 674			}
 675			value = strtol(param, NULL, 16);
 676			insert_breakpoint(context, value, debugger);
 677			return 0;
 678		case 'd':
 679			if (input_buf[1] == 'i') {
 680				format_char = 0;
 681				for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
 682					if (input_buf[i] == '/') {
 683						format_char = input_buf[i+1];
 684						break;
 685					}
 686				}
 687				param = find_param(input_buf);
 688				if (!param) {
 689					fputs("display command requires a parameter\n", stderr);
 690					break;
 691				}
 692				debugger_print(context, format_char, param);
 693				add_display(&displays, &disp_index, format_char, param);
 694			} else {
 695				param = find_param(input_buf);
 696				if (!param) {
 697					fputs("d command requires a parameter\n", stderr);
 698					break;
 699				}
 700				value = atoi(param);
 701				this_bp = find_breakpoint_idx(&breakpoints, value);
 702				if (!*this_bp) {
 703					fprintf(stderr, "Breakpoint %d does not exist\n", value);
 704					break;
 705				}
 706				new_bp = *this_bp;
 707				*this_bp = (*this_bp)->next;
 708				if (new_bp->commands) {
 709					free(new_bp->commands);
 710				}
 711				free(new_bp);
 712			}
 713			break;
 714		case 'p':
 715			format_char = 0;
 716			for(int i = 1; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
 717				if (input_buf[i] == '/') {
 718					format_char = input_buf[i+1];
 719					break;
 720				}
 721			}
 722			param = find_param(input_buf);
 723			if (!param) {
 724				fputs("p command requires a parameter\n", stderr);
 725				break;
 726			}
 727			debugger_print(context, format_char, param);
 728			break;
 729		case 'n':
 730			if (inst.op == M68K_RTS) {
 731				after = m68k_read_long(context->aregs[7], context);
 732			} else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
 733				after = m68k_read_long(context->aregs[7] + 2, context);
 734			} else if(m68k_is_noncall_branch(&inst)) {
 735				if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
 736					branch_f = after;
 737					branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
 738					insert_breakpoint(context, branch_t, debugger);
 739				} else if(inst.op == M68K_DBCC) {
 740					if ( inst.extra.cond == COND_FALSE) {
 741						if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
 742							after = m68k_branch_target(&inst, context->dregs, context->aregs);
 743						}
 744					} else {
 745						branch_t = after;
 746						branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
 747						insert_breakpoint(context, branch_f, debugger);
 748					}
 749				} else {
 750					after = m68k_branch_target(&inst, context->dregs, context->aregs);
 751				}
 752			}
 753			insert_breakpoint(context, after, debugger);
 754			return 0;
 755		case 'o':
 756			if (inst.op == M68K_RTS) {
 757				after = m68k_read_long(context->aregs[7], context);
 758			} else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
 759				after = m68k_read_long(context->aregs[7] + 2, context);
 760			} else if(m68k_is_noncall_branch(&inst)) {
 761				if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
 762					branch_t = m68k_branch_target(&inst, context->dregs, context->aregs)  & 0xFFFFFF;
 763					if (branch_t < after) {
 764							branch_t = 0;
 765					} else {
 766						branch_f = after;
 767						insert_breakpoint(context, branch_t, debugger);
 768					}
 769				} else if(inst.op == M68K_DBCC) {
 770					uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs)  & 0xFFFFFF;
 771					if (target > after) {
 772						if (inst.extra.cond == COND_FALSE) {
 773							after = target;
 774						} else {
 775							branch_f = target;
 776							branch_t = after;
 777							insert_breakpoint(context, branch_f, debugger);
 778						}
 779					}
 780				} else {
 781					after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
 782				}
 783			}
 784			insert_breakpoint(context, after, debugger);
 785			return 0;
 786		case 's':
 787			if (input_buf[1] == 'e') {
 788				param = find_param(input_buf);
 789				if (!param) {
 790					fputs("Missing destination parameter for set\n", stderr);
 791				}
 792				char *val = find_param(param);
 793				if (!val) {
 794					fputs("Missing value parameter for set\n", stderr);
 795				}
 796				long int_val;
 797				int reg_num;
 798				switch (val[0])
 799				{
 800				case 'd':
 801				case 'a':
 802					reg_num = val[1] - '0';
 803					if (reg_num < 0 || reg_num > 8) {
 804						fprintf(stderr, "Invalid register %s\n", val);
 805						return 1;
 806					}
 807					int_val = (val[0] == 'd' ? context->dregs : context->aregs)[reg_num];
 808					break;
 809				case '$':
 810					int_val = strtol(val+1, NULL, 16);
 811					break;
 812				case '0':
 813					if (val[1] == 'x') {
 814						int_val = strtol(val+2, NULL, 16);
 815						break;
 816					}
 817				default:
 818					int_val = strtol(val, NULL, 10);
 819				}
 820				switch(param[0])
 821				{
 822				case 'd':
 823				case 'a':
 824					reg_num = param[1] - '0';
 825					if (reg_num < 0 || reg_num > 8) {
 826						fprintf(stderr, "Invalid register %s\n", param);
 827						return 1;
 828					}
 829					(param[0] == 'd' ? context->dregs : context->aregs)[reg_num] = int_val;
 830					break;
 831				default:
 832					fprintf(stderr, "Invalid destinatino %s\n", param);
 833				}
 834				break;
 835			} else {
 836				if (inst.op == M68K_RTS) {
 837					after = m68k_read_long(context->aregs[7], context);
 838				} else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
 839					after = m68k_read_long(context->aregs[7] + 2, context);
 840				} else if(m68k_is_branch(&inst)) {
 841					if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
 842						branch_f = after;
 843						branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
 844						insert_breakpoint(context, branch_t, debugger);
 845					} else if(inst.op == M68K_DBCC) {
 846						if (inst.extra.cond == COND_FALSE) {
 847							if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
 848								after = m68k_branch_target(&inst, context->dregs, context->aregs);
 849							}
 850						} else {
 851							branch_t = after;
 852							branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
 853							insert_breakpoint(context, branch_f, debugger);
 854						}
 855					} else {
 856						after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
 857					}
 858				}
 859				insert_breakpoint(context, after, debugger);
 860				return 0;
 861			}
 862		case 'v': {
 863			genesis_context * gen = context->system;
 864			//VDP debug commands
 865			switch(input_buf[1])
 866			{
 867			case 's':
 868				vdp_print_sprite_table(gen->vdp);
 869				break;
 870			case 'r':
 871				vdp_print_reg_explain(gen->vdp);
 872				break;
 873			}
 874			break;
 875		}
 876		case 'y': {
 877			genesis_context * gen = context->system;
 878			//YM-2612 debug commands
 879			switch(input_buf[1])
 880			{
 881			case 'c':
 882				if (input_buf[2] == ' ') {
 883					int channel = atoi(input_buf+3)-1;
 884					ym_print_channel_info(gen->ym, channel);
 885				} else {
 886					for (int i = 0; i < 6; i++) {
 887						ym_print_channel_info(gen->ym, i);
 888					}
 889				}
 890				break;
 891			case 't':
 892				ym_print_timer_info(gen->ym);
 893				break;
 894			}
 895			break;
 896		}
 897		case 'z': {
 898			genesis_context * gen = context->system;
 899			//Z80 debug commands
 900			switch(input_buf[1])
 901			{
 902			case 'b':
 903				param = find_param(input_buf);
 904				if (!param) {
 905					fputs("zb command requires a parameter\n", stderr);
 906					break;
 907				}
 908				value = strtol(param, NULL, 16);
 909				zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger);
 910				new_bp = malloc(sizeof(bp_def));
 911				new_bp->next = zbreakpoints;
 912				new_bp->address = value;
 913				new_bp->index = zbp_index++;
 914				zbreakpoints = new_bp;
 915				printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
 916				break;
 917			case 'p':
 918				param = find_param(input_buf);
 919				if (!param) {
 920					fputs("zp command requires a parameter\n", stderr);
 921					break;
 922				}
 923				zdebugger_print(gen->z80, input_buf[2] == '/' ? input_buf[3] : 0, param);
 924			}
 925			break;
 926		}
 927		case 'q':
 928			puts("Quitting");
 929			exit(0);
 930			break;
 931		default:
 932			fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
 933			break;
 934	}
 935	return 1;
 936}
 937
 938
 939void debugger(m68k_context * context, uint32_t address)
 940{
 941	static char last_cmd[1024];
 942	char input_buf[1024];
 943	m68kinst inst;
 944
 945	init_terminal();
 946
 947	sync_components(context, 0);
 948	genesis_context *gen = context->system;
 949	vdp_force_update_framebuffer(gen->vdp);
 950	//probably not necessary, but let's play it safe
 951	address &= 0xFFFFFF;
 952	if (address == branch_t) {
 953		bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f);
 954		if (!*f_bp) {
 955			remove_breakpoint(context, branch_f);
 956		}
 957		branch_t = branch_f = 0;
 958	} else if(address == branch_f) {
 959		bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
 960		if (!*t_bp) {
 961			remove_breakpoint(context, branch_t);
 962		}
 963		branch_t = branch_f = 0;
 964	}
 965
 966	uint16_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->options->gen);
 967	if (!pc) {
 968		fatal_error("Entered 68K debugger at address %X\n", address);
 969	}
 970	uint16_t * after_pc = m68k_decode(pc, &inst, address);
 971	uint32_t after = address + (after_pc-pc)*2;
 972	int debugging = 1;
 973	//Check if this is a user set breakpoint, or just a temporary one
 974	bp_def ** this_bp = find_breakpoint(&breakpoints, address);
 975	if (*this_bp) {
 976
 977		if ((*this_bp)->commands)
 978		{
 979			char *commands = strdup((*this_bp)->commands);
 980			char *copy = commands;
 981
 982			while (debugging && *commands)
 983			{
 984				char *cmd = commands;
 985				strip_nl(cmd);
 986				commands += strlen(cmd) + 1;
 987				debugging = run_debugger_command(context, cmd, inst, after);
 988			}
 989			free(copy);
 990		}
 991		if (debugging) {
 992			printf("68K Breakpoint %d hit\n", (*this_bp)->index);
 993		} else {
 994			return;
 995		}
 996	} else {
 997		remove_breakpoint(context, address);
 998	}
 999	for (disp_def * cur = displays; cur; cur = cur->next) {
1000		debugger_print(context, cur->format_char, cur->param);
1001	}
1002	m68k_disasm(&inst, input_buf);
1003	printf("%X: %s\n", address, input_buf);
1004	int prompt = 1;
1005	fd_set read_fds;
1006	FD_ZERO(&read_fds);
1007	struct timeval timeout;
1008	while (debugging) {
1009		if (prompt) {
1010			fputs(">", stdout);
1011			fflush(stdout);
1012		}
1013		process_events();
1014		timeout.tv_sec = 0;
1015		timeout.tv_usec = 16667;
1016		FD_SET(fileno(stdin), &read_fds);
1017		if(select(fileno(stdin) + 1, &read_fds, NULL, NULL, &timeout) < 1) {
1018			prompt = 0;
1019			continue;
1020		} else {
1021			prompt = 1;
1022		}
1023		if (!fgets(input_buf, sizeof(input_buf), stdin)) {
1024			fputs("fgets failed", stderr);
1025			break;
1026		}
1027		strip_nl(input_buf);
1028		//hitting enter repeats last command
1029		if (input_buf[0]) {
1030			strcpy(last_cmd, input_buf);
1031		} else {
1032			strcpy(input_buf, last_cmd);
1033		}
1034		debugging = run_debugger_command(context, input_buf, inst, after);
1035	}
1036	return;
1037}