/* * Apple // emulator for Linux: Main debugger routines * * Copyright 1997, 1998, 2013 Aaron Culliney * Copyright 1998, 1999, 2000 Michael Deutschmann * * This software package is subject to the GNU General Public License * version 2 or later (your choice) as published by the Free Software * Foundation. * * THERE ARE NO WARRANTIES WHATSOEVER. * * Originally added to emulator project in 1997 by Aaron Culliney * */ #include "common.h" const struct opcode_struct *opcodes; int step_next; /* stepping over instructions */ char second_buf[BUF_Y][BUF_X]; /* scratch buffer for output */ int num_buffer_lines; /* num lines of output */ int arg1, arg2, arg3; /* command arguments */ int breakpoints[MAX_BRKPTS]; /* memory breakpoints */ int watchpoints[MAX_BRKPTS]; /* memory watchpoints */ /* debugger globals */ //1. 5. 10. 15. 20. 25. 30. 35. 40. 45. 50. 55. 60. 65. 70. 75. 80.", static char screen[SCREEN_Y][SCREEN_X] = { "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "| | |", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" }; static char command_buf[BUF_Y][BUF_X]; /* command line prompt */ char lexbuf[BUF_X+2]; /* comman line to be flex'ed */ unsigned char current_opcode; int op_breakpoints[256]; /* opcode breakpoints */ /* in debug.l */ extern int yylex(); extern void init_lex(char *buf, int size); /* ------------------------------------------------------------------------- c_get_current_rambank (addrs) - return the current ram bank for addrs. returns 0 = bank 0 1 = bank 1 ------------------------------------------------------------------------- */ int c_get_current_rambank(int addrs) { if ((addrs >= 0x200) && (addrs < 0xD000)) { /* SLOTROM */ if ((addrs >= 0xC100) && (addrs < 0xD000)) { /* expansion rom */ if ((addrs >= 0xC800) && (addrs < 0xD000)) { return 1; /* always internal * (the real rules are more complex, but * this'll suffice since the slot 3 pseudo-card * is the only one with c8 space) */ } /* if SLOTCXROM, then internal rom (regardless of SLOTC3ROM setting). */ if (softswitches & SS_CXROM) { return 1; } /* slot 3 rom */ if ((addrs >= 0xC300) && (addrs < 0xC400)) { return !!(softswitches & SS_C3ROM); } return 0; /* peripheral rom */ } /* text page 1 */ if ((addrs >= 0x400) && (addrs < 0x800)) { return !!(softswitches & SS_TEXTRD); } /* hires page 1 with 80STORE and HIRES on */ if ((addrs >= 0x2000) && (addrs < 0x4000)) { return !!(softswitches & SS_HGRRD); } /* otherwise return RAMRD flag */ return !!(softswitches & SS_RAMRD); } /* executing in ALTZP space. */ return !!(softswitches & SS_ALTZP); } /* ------------------------------------------------------------------------- get_current_opcode () - returns the opcode from the address that the PC is currently reading from. returns 0 = bank 0 1 = bank 1 ------------------------------------------------------------------------- */ unsigned char get_current_opcode() { int bank = c_get_current_rambank(cpu65_current.pc); int lcbank = 0; /* main RAM */ if (cpu65_current.pc < 0xD000) { return apple_ii_64k[bank][cpu65_current.pc]; } /* LC RAM */ if (cpu65_current.pc >= 0xE000) { if (softswitches & SS_LCRAM) { return language_card[bank][cpu65_current.pc-0xE000]; } else { return apple_ii_64k[bank][cpu65_current.pc]; } } /* LC BANK RAM */ if (softswitches & SS_BANK2) { lcbank = 0x1000; } if (softswitches & SS_LCRAM) { return language_banks[bank][cpu65_current.pc-0xD000+lcbank]; } else { return apple_ii_64k[bank][cpu65_current.pc]; } } /* ------------------------------------------------------------------------- dump_mem () - hexdump of memory to debug console we DO NOT wrap the display : 0xffff -> 0x0 (programs can't wrap) ------------------------------------------------------------------------- */ void dump_mem(int addrs, int len, int lc, int do_ascii, int rambank) { int i, j, mod, end; unsigned char op; int orig_addrs = addrs; /* address for display */ /* check which rambank */ if (rambank == -1) { rambank = c_get_current_rambank(addrs); } if (!lc && (softswitches & SS_LCRAM) && (addrs >= 0xd000)) { /* read lc anyway */ lc = 1 + !!(softswitches & SS_BANK2); } if ((addrs < 0) || (addrs > 0xffff)) { addrs = cpu65_current.pc; orig_addrs = addrs; } if (lc) { orig_addrs = addrs; if ((addrs >= 0xd000) && (addrs <= 0xffff)) { addrs -= 0xd000; } if ((addrs < 0) || (addrs > 0x2fff)) { addrs = 0; } } if ((len < 1) || (len > 256)) { len = 256; } if (do_ascii && (len > 128)) { len = 128; } /* save hexdump in second_buf */ end = (lc) ? 0x3000 : 0x10000; for (i = num_buffer_lines-1, j = 0; ((j < len) && (addrs+j < end)); j++) { mod = j % (16 >> do_ascii); if (lc) { op = (addrs+j >= 0x1000) ? language_card[rambank][(addrs+j)-0x1000] : (lc == 1) ? language_banks[rambank][addrs+j] : language_banks[rambank][0x1000+addrs+j]; } else { op = apple_ii_64k[rambank][addrs+j]; } if (!mod) { if (++i) { for (mod=0; mod 31) ? (op&0x7f) : '.'); } continue; } sprintf(second_buf[i]+5+mod*2, "%02X", op); if (do_ascii) { sprintf(second_buf[i]+23+mod, "%c", ((op&0x7f) > 31) ? (op&0x7f) : '.'); } } for (mod=0; mod= 0x1000) ? language_card[rambank][i-0x1000] : (lc == 1) ? language_banks[rambank][i] : language_banks[rambank][0x1000+i]; } else { op = apple_ii_64k[rambank][i]; } if (byte == op) /* matched byte? */ { ++j; /* increment */ if (!isxdigit(*(hexstr+j))) /* end of bytes? */ { /* then we found a match */ sprintf(second_buf[num_buffer_lines], "%04X: %s", i-(j>>1), hexstr); num_buffer_lines = (num_buffer_lines + 1) % (BUF_Y-2); j = 0; continue; } ++j; if (!isxdigit(*(hexstr+j))) /* end of bytes? */ { /* then we found a match */ sprintf(second_buf[num_buffer_lines], "%04X: %s", i-(j>>1)+1, hexstr); num_buffer_lines = (num_buffer_lines + 1) % (BUF_Y-2); j = 0; continue; } continue; } j = 0; } } /* ------------------------------------------------------------------------- set_mem () - write to memory. we use the do_write_memory routine to "safely" set memory... ------------------------------------------------------------------------- */ void set_mem(int addrs, char *hexstr) { static char scratch[3]; unsigned char data; if ((addrs < 0) || (addrs > 0xffff)) { sprintf(second_buf[num_buffer_lines++], "invalid address"); return; } while (*hexstr) { strncpy(scratch, hexstr, 2); data = (unsigned char) strtol(scratch, (char**)NULL, 16); /* call the set_memory routine, which knows how to route the request */ cpu65_direct_write(addrs,data); ++hexstr; if (!*hexstr) { break; } ++hexstr; if (++addrs > 0xffff) { return; /* don't overwrite memory */ } } } /* ------------------------------------------------------------------------- set_lc_mem () - specifically write to apple II language card RAM memory ------------------------------------------------------------------------- */ void set_lc_mem(int addrs, int lcbank, char *hexstr) { static char scratch[3]; unsigned char data; if ((addrs >= 0xd000) && (addrs <= 0xffff)) { addrs -= 0xd000; } if ((addrs < 0) || (addrs > 0x2fff)) { sprintf(second_buf[num_buffer_lines++], "invalid LC address"); return; } while (*hexstr) { strncpy(scratch, hexstr, 2); data = (unsigned char) strtol(scratch, (char**)NULL, 16); /* ??? no way to write to aux LC banks */ if (addrs >= 0x1000) { language_card[0][addrs - 0x1000] = data; } else if (lcbank) { language_banks[0][addrs] = data; } else { language_banks[0][addrs + 0x1000] = data; } ++hexstr; if (!*hexstr) { break; } ++hexstr; if (++addrs > 0x2fff) { return; } } } /* ------------------------------------------------------------------------- bload () - bload file data into emulator. this is essentially the same as the set_mem routine. we use the do_write_memory routine to "safely" set memory... ------------------------------------------------------------------------- */ void bload(FILE *f, char *name, int addrs) { unsigned char *hexstr = NULL; int len = -1; unsigned char data; if ((addrs < 0) || (addrs > 0xffff)) { sprintf(second_buf[num_buffer_lines++], "invalid address"); return; } while ((len = fread(temp, 1, TEMPSIZE, f))) { hexstr = (unsigned char*)temp; for (; len > 0; len--) { data = *hexstr; /* call the set_memory routine, which knows how to route the request */ cpu65_direct_write(addrs,data); ++hexstr; if (++addrs > 0xffff) { return; /* don't overwrite memory */ } } } sprintf(second_buf[num_buffer_lines++], "bloaded: %s", name); } /* ------------------------------------------------------------------------- disasm () - disassemble instructions we DO NOT wrap the display : 0xffff -> 0x0 ------------------------------------------------------------------------- */ void disasm(int addrs, int len, int lc, int rambank) { static char fmt[64]; unsigned char op; char arg1, arg2; int i, j, k, end, orig_addrs = addrs; /* check which rambank for cpu65_current.pc */ if (rambank == -1) { rambank = c_get_current_rambank(addrs); } if (!lc && (softswitches & SS_LCRAM) && (addrs >= 0xd000)) { /* read lc anyway */ lc = 1 + !!(softswitches & SS_BANK2); } /* handle invalid address request */ if ((addrs < 0) || (addrs > 0xffff)) { addrs = cpu65_current.pc; orig_addrs = addrs; } /* disassembling from language card */ if (lc) { if ((addrs >= 0xd000) && (addrs <= 0xffff)) { addrs -= 0xd000; } if ((addrs < 0) || (addrs > 0x2fff)) { addrs = 0; } } if (len > BUF_Y - 2) { len = BUF_Y - 2 - num_buffer_lines; } /* save hexdump in second_buf */ end = (lc) ? 0x3000 : 0x10000; for (i = num_buffer_lines, j = addrs, k=orig_addrs; ((i= 0x1000) ? language_card[rambank][j-0x1000] : (lc == 1) ? language_banks[rambank][j] : language_banks[rambank][0x1000+j]; } else { op = apple_ii_64k[rambank][j]; } switch (opcodes[op].mode) { case addr_implied: case addr_accumulator: /* no arg */ sprintf(second_buf[i], "/%02X/%04X: %02X %s %s", rambank, k++, op, opcodes[op].mnemonic, disasm_templates[opcodes[op].mode]); break; case addr_immediate: case addr_zeropage: case addr_zeropage_x: case addr_zeropage_y: case addr_indirect: case addr_indirect_x: case addr_indirect_y: /* byte arg */ if (k == 0xffff) { num_buffer_lines = i; return; } if (lc) { arg1 = (j >= 0x1000) ? language_card[rambank][++j-0x1000] : (lc == 1) ? language_banks[rambank][++j] : language_banks[rambank][++j+0x1000]; } else { arg1 = apple_ii_64k[rambank][++j]; } sprintf(fmt, "/%02X/%04X: %02X%02X %s %s", rambank, k, op, (unsigned char)arg1, opcodes[op].mnemonic, disasm_templates[opcodes[op].mode]); sprintf(second_buf[i], fmt, (unsigned char)arg1); k+=2; break; case addr_absolute: case addr_absolute_x: case addr_absolute_y: case addr_j_indirect: case addr_j_indirect_x: /* word arg */ if (k >= 0xfffe) { num_buffer_lines = i; return; } if (lc) { arg1 = (j >= 0x1000) ? language_card[rambank][++j-0x1000] : (lc == 1) ? language_banks[rambank][++j] : language_banks[rambank][++j+0x1000]; arg2 = (j >= 0x1000) ? language_card[rambank][++j-0x1000] : (lc == 1) ? language_banks[rambank][++j] : language_banks[rambank][++j+0x1000]; } else { arg1 = apple_ii_64k[rambank][++j]; arg2 = apple_ii_64k[rambank][++j]; } sprintf(fmt, "/%02X/%04X: %02X%02X%02X %s %s", rambank, k, op, (unsigned char)arg1, (unsigned char)arg2, opcodes[op].mnemonic, disasm_templates[opcodes[op].mode]); sprintf(second_buf[i], fmt, (unsigned char)arg2, (unsigned char)arg1); k+=3; break; case addr_relative: /* offset */ if (k == 0xffff) { num_buffer_lines = i; return; } if (lc) { arg1 = (j >= 0x1000) ? language_card[rambank][++j-0x1000] : (lc == 1) ? language_banks[rambank][++j] : language_banks[rambank][++j+0x1000]; } else { arg1 = apple_ii_64k[rambank][++j]; } sprintf(fmt, "/%02X/%04X: %02X%02X %s %s", rambank, k, op, (unsigned char)arg1, opcodes[op].mnemonic, disasm_templates[opcodes[op].mode]); if (arg1 < 0) { sprintf(second_buf[i], fmt, k + arg1 + 2, '-', (unsigned char)(-arg1)); } else { sprintf(second_buf[i], fmt, k + arg1 + 2, '+', (unsigned char)arg1); } k+=2; break; default: /* shouldn't happen */ sprintf(second_buf[i], "args to opcode incorrect!"); break; } } num_buffer_lines = i; } /* ------------------------------------------------------------------------- show_regs () - shows 6502 registers ------------------------------------------------------------------------- */ void show_regs() { sprintf(second_buf[num_buffer_lines++], "PC = %04X EA = %04X SP = %04X", cpu65_current.pc, cpu65_debug.ea, cpu65_current.sp + 0x0100); sprintf(second_buf[num_buffer_lines++], "X = %02X Y = %02X A = %02X F = %02X", cpu65_current.x, cpu65_current.y, cpu65_current.a, cpu65_current.f); memset(second_buf[num_buffer_lines], ' ', BUF_X); if (cpu65_current.f & C_Flag) { second_buf[num_buffer_lines][0]='C'; } if (cpu65_current.f & X_Flag) { second_buf[num_buffer_lines][1]='X'; } if (cpu65_current.f & I_Flag) { second_buf[num_buffer_lines][2]='I'; } if (cpu65_current.f & V_Flag) { second_buf[num_buffer_lines][3]='V'; } if (cpu65_current.f & B_Flag) { second_buf[num_buffer_lines][4]='B'; } if (cpu65_current.f & D_Flag) { second_buf[num_buffer_lines][5]='D'; } if (cpu65_current.f & Z_Flag) { second_buf[num_buffer_lines][6]='Z'; } if (cpu65_current.f & N_Flag) { second_buf[num_buffer_lines][7]='N'; } ++num_buffer_lines; } /* ------------------------------------------------------------------------- will_branch () = will instruction branch? -1 - n/a 0 - no it won't >0 - yes it will ------------------------------------------------------------------------- */ static int will_branch() { unsigned char op = get_current_opcode(); switch (op) { case 0x10: /* BPL */ return (int) !(cpu65_current.f & N_Flag); case 0x30: /* BMI */ return (int) (cpu65_current.f & N_Flag); case 0x50: /* BVC */ return (int) !(cpu65_current.f & V_Flag); case 0x70: /* BVS */ return (int) (cpu65_current.f & V_Flag); case 0x80: /* BRA */ return 1; case 0x90: /* BCC */ return (int) !(cpu65_current.f & C_Flag); case 0xb0: /* BCS */ return (int) (cpu65_current.f & C_Flag); case 0xd0: /* BNE */ return (int) !(cpu65_current.f & Z_Flag); case 0xf0: /* BEQ */ return (int) (cpu65_current.f & Z_Flag); } return -1; } /* ------------------------------------------------------------------------- set_halt () = set a breakpoint or watchpoint in memory type = points to "watchpoints" or "breakpoints" array ------------------------------------------------------------------------- */ void set_halt(int *type, int addrs) { int i; for (i = 0; i < MAX_BRKPTS; i++) { if (type[i] == -1) { type[i] = addrs; sprintf(second_buf[num_buffer_lines++], "set at %04X", addrs); return; } } sprintf(second_buf[num_buffer_lines++], "too many!"); } /* ------------------------------------------------------------------------- clear_halt () = unset a critical breakpoint or watchpoint in memory type = points to "watchpoints" or "breakpoints" array pt = (pt - 1) into type. 0 indicates clear all. ------------------------------------------------------------------------- */ void clear_halt(int *type, int pt) { int i; if (!pt) /* unset all */ { for (i = 0; i < MAX_BRKPTS; i++) { type[i] = -1; } return; } type[pt-1] = -1; /* unset single */ } /* ------------------------------------------------------------------------- set_halt_opcode () = set a breakpoint on a particular opcode. ------------------------------------------------------------------------- */ void set_halt_opcode(unsigned char opcode) { op_breakpoints[opcode] = 1; } /* ------------------------------------------------------------------------- clear_halt_opcode () = unset an opcode breakpoint. ------------------------------------------------------------------------- */ void clear_halt_opcode(unsigned char opcode) { op_breakpoints[opcode] = 0; } /* ------------------------------------------------------------------------- set_halt_65c02 () = set a breakpoint on all 65c02 instructions. assumes that you are in //e mode... ------------------------------------------------------------------------- */ void set_halt_65c02() { set_halt_opcode((uchar)0x02); set_halt_opcode((uchar)0x04); set_halt_opcode((uchar)0x0C); set_halt_opcode((uchar)0x12); set_halt_opcode((uchar)0x14); set_halt_opcode((uchar)0x1A); set_halt_opcode((uchar)0x1C); set_halt_opcode((uchar)0x32); set_halt_opcode((uchar)0x34); set_halt_opcode((uchar)0x3A); set_halt_opcode((uchar)0x3C); set_halt_opcode((uchar)0x52); set_halt_opcode((uchar)0x5A); set_halt_opcode((uchar)0x64); set_halt_opcode((uchar)0x72); set_halt_opcode((uchar)0x74); set_halt_opcode((uchar)0x7A); set_halt_opcode((uchar)0x7C); set_halt_opcode((uchar)0x80); set_halt_opcode((uchar)0x89); set_halt_opcode((uchar)0x92); set_halt_opcode((uchar)0x9C); set_halt_opcode((uchar)0x9E); set_halt_opcode((uchar)0xB2); set_halt_opcode((uchar)0xD2); set_halt_opcode((uchar)0xDA); set_halt_opcode((uchar)0xF2); set_halt_opcode((uchar)0xFA); } /* ------------------------------------------------------------------------- clear_halt_65c02 () = clear all 65c02 instructions ------------------------------------------------------------------------- */ void clear_halt_65c02() { clear_halt_opcode((uchar)0x02); clear_halt_opcode((uchar)0x04); clear_halt_opcode((uchar)0x0C); clear_halt_opcode((uchar)0x12); clear_halt_opcode((uchar)0x14); clear_halt_opcode((uchar)0x1A); clear_halt_opcode((uchar)0x1C); clear_halt_opcode((uchar)0x32); clear_halt_opcode((uchar)0x34); clear_halt_opcode((uchar)0x3A); clear_halt_opcode((uchar)0x3C); clear_halt_opcode((uchar)0x52); clear_halt_opcode((uchar)0x5A); clear_halt_opcode((uchar)0x64); clear_halt_opcode((uchar)0x72); clear_halt_opcode((uchar)0x74); clear_halt_opcode((uchar)0x7A); clear_halt_opcode((uchar)0x7C); clear_halt_opcode((uchar)0x80); clear_halt_opcode((uchar)0x89); clear_halt_opcode((uchar)0x92); clear_halt_opcode((uchar)0x9C); clear_halt_opcode((uchar)0x9E); clear_halt_opcode((uchar)0xB2); clear_halt_opcode((uchar)0xD2); clear_halt_opcode((uchar)0xDA); clear_halt_opcode((uchar)0xF2); clear_halt_opcode((uchar)0xFA); } /* ------------------------------------------------------------------------- at_haltpt () - tests if at haltpt returns 0 = no breaks or watches 1 = one break or watchpoint fired n = two or more breaks and/or watches fired ------------------------------------------------------------------------- */ int at_haltpt() { int i; /* check op_breakpoints */ unsigned char op = get_current_opcode(); if (op_breakpoints[op]) { sprintf(second_buf[num_buffer_lines++], "stopped at %04X bank %d instruction %02X", cpu65_current.pc, c_get_current_rambank(cpu65_current.pc), op); } for (i = 0; i < MAX_BRKPTS; i++) { if (cpu65_current.pc == breakpoints[i]) { sprintf(second_buf[num_buffer_lines++], "stopped at %04X bank %d", breakpoints[i], c_get_current_rambank(cpu65_current.pc)); } } if (cpu65_debug.rw) /* only check watchpoints if read/write occured */ { for (i = 0; i < MAX_BRKPTS; i++) { if (cpu65_debug.ea == watchpoints[i]) { if (cpu65_debug.rw & 2) { sprintf(second_buf[num_buffer_lines++], "wrote: %04X: %02X", watchpoints[i], cpu65_debug.d); } else { sprintf(second_buf[num_buffer_lines++], "read: %04X", watchpoints[i]); } cpu65_debug.rw = 0; /* only allow WP to trip once */ } } } return num_buffer_lines; /* 0 indicates nothing happened */ } /* ------------------------------------------------------------------------- show_breakpts () - show breakpoints and watchpoints ------------------------------------------------------------------------- */ void show_breakpts() { int i=num_buffer_lines, k; for (k = 0; k < MAX_BRKPTS; k++) { if ((breakpoints[k] >= 0) && (watchpoints[k] >= 0)) { sprintf(second_buf[i++], "break %02d at %04X watch %02d at %04X", k+1, breakpoints[k], k+1, watchpoints[k]); } else if (breakpoints[k] >= 0) { sprintf(second_buf[i++], "break %02d at %04X", k+1, breakpoints[k]); } else if (watchpoints[k] >= 0) { memset(second_buf[i], ' ', BUF_X); sprintf(second_buf[i++]+16, " watch %02d at %04X", k+1, watchpoints[k]); } } num_buffer_lines = i; } /* ------------------------------------------------------------------------- show_opcode_breakpts () - show opcode breakpoints ------------------------------------------------------------------------- */ void show_opcode_breakpts() { int i=num_buffer_lines, k; sprintf(second_buf[i++], " 0 1 2 3 4 5 6 7 8 9 A B C D E F"); sprintf(second_buf[i++], " |-------------------------------|"); for (k = 0; k < 0x10; k++) { sprintf(second_buf[i++], " %X|%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s|", k, op_breakpoints[k ] ? "x" : " ", op_breakpoints[k+0x10] ? "x" : " ", op_breakpoints[k+0x20] ? "x" : " ", op_breakpoints[k+0x30] ? "x" : " ", op_breakpoints[k+0x40] ? "x" : " ", op_breakpoints[k+0x50] ? "x" : " ", op_breakpoints[k+0x60] ? "x" : " ", op_breakpoints[k+0x70] ? "x" : " ", op_breakpoints[k+0x80] ? "x" : " ", op_breakpoints[k+0x90] ? "x" : " ", op_breakpoints[k+0xA0] ? "x" : " ", op_breakpoints[k+0xB0] ? "x" : " ", op_breakpoints[k+0xC0] ? "x" : " ", op_breakpoints[k+0xD0] ? "x" : " ", op_breakpoints[k+0xE0] ? "x" : " ", op_breakpoints[k+0xF0] ? "x" : " "); } sprintf(second_buf[i++], " |-------------------------------|"); num_buffer_lines = i; } /* ------------------------------------------------------------------------- show_lc_info () - show language card info ------------------------------------------------------------------------- */ void show_lc_info() { int i = num_buffer_lines; sprintf(second_buf[i++], "lc bank = %d", 1 + !!(softswitches && SS_BANK2)); (softswitches & SS_LCWRT) ? sprintf(second_buf[i++], "write LC") : sprintf(second_buf[i++], "LC write protected"); (softswitches & SS_LCRAM) ? sprintf(second_buf[i++], "read LC") : sprintf(second_buf[i++], "read ROM"); sprintf(second_buf[i++], "second = %d", !!(softswitches && SS_LCSEC)); num_buffer_lines = i; } void show_misc_info() { int i = num_buffer_lines; sprintf(second_buf[i++], "TEXT (%04X): %s", SW_TEXT + !!(softswitches & SS_TEXT), (softswitches & SS_TEXT) ? "on" : "off"); sprintf(second_buf[i++], "MIXED (%04X): %s", SW_MIXED + !!(softswitches & SS_MIXED), (softswitches & SS_MIXED) ? "on" : "off"); sprintf(second_buf[i++], "PAGE2 (%04X): %s", SW_PAGE2 + !!(softswitches & SS_PAGE2), (softswitches & SS_PAGE2) ? "on" : "off"); sprintf(second_buf[i++], "HIRES (%04X): %s", SW_HIRES + !!(softswitches & SS_HIRES), (softswitches & SS_HIRES) ? "on" : "off"); sprintf(second_buf[i++], "80STORE (%04X): %s", SW_80STORE + !!(softswitches & SS_80STORE), (softswitches & SS_80STORE) ? "on" : "off"); sprintf(second_buf[i++], "RAMRD (%04X): %s", SW_RAMRD + !!(softswitches & SS_RAMRD), (softswitches & SS_RAMRD) ? "on" : "off"); sprintf(second_buf[i++], "RAMWRT (%04X): %s", SW_RAMWRT + !!(softswitches & SS_RAMWRT), (softswitches & SS_RAMWRT) ? "on" : "off"); sprintf(second_buf[i++], "ALTZP (%04X): %s", SW_ALTZP + !!(softswitches & SS_ALTZP), (softswitches & SS_ALTZP) ? "on" : "off"); sprintf(second_buf[i++], "80COL (%04X): %s", SW_80COL + !!(softswitches & SS_80COL), (softswitches & SS_80COL) ? "on" : "off"); sprintf(second_buf[i++], "ALTCHAR (%04X): %s", SW_ALTCHAR + !!(softswitches & SS_ALTCHAR), (softswitches & SS_ALTCHAR) ? "on" : "off"); sprintf(second_buf[i++], "SLOTC3ROM (%04X): %s", SW_SLOTC3ROM -/*anomaly*/ !!(softswitches & SS_C3ROM), (softswitches & SS_C3ROM) ? "on" : "off"); sprintf(second_buf[i++], "SLOTCXROM (%04X): %s", SW_SLOTCXROM + !!(softswitches & SS_CXROM), (softswitches & SS_CXROM) ? "on" : "off"); sprintf(second_buf[i++], "DHIRES (%04X): %s", SW_DHIRES + !!(softswitches && SS_DHIRES), (softswitches & SS_DHIRES) ? "on" : "off"); sprintf(second_buf[i++], "IOUDIS (%04X): %s", SW_IOUDIS + !!(softswitches && SS_IOUDIS), (softswitches && SS_IOUDIS) ? "on" : "off"); /* sprintf(second_buf[i++], "RDVBLBAR: %s", (SLOTCXROM & 0x80) */ /* ? "on" : "off"); */ num_buffer_lines = i; } /* ------------------------------------------------------------------------- show_disk_info () - disk II info ------------------------------------------------------------------------- */ void show_disk_info() { static char tmp[32]; int i = num_buffer_lines, len = 0, off = 19; /* generic information */ sprintf(second_buf[i++], "drive %s", (disk6.drive) ? "B" : "A"); sprintf(second_buf[i++], "motor %s", (disk6.motor) ? "off" : "on"); sprintf(second_buf[i++], "%s", (disk6.ddrw) ? "write" : "read"); sprintf(second_buf[i++], "byte = %02X", disk6.disk_byte); if (!disk6.disk[disk6.drive].nibblized) { sprintf(second_buf[i++], "volume = %d", disk6.volume); sprintf(second_buf[i++], "checksum = %d", disk6.checksum); } sprintf(second_buf[i++], "-------------------------------------"); /* drive / image specific information */ memset(second_buf[i], ' ', BUF_X); if ((len = strlen(disk6.disk[0].file_name))) { while ((--len) && (disk6.disk[0].file_name[len] != '/')) { } strncpy(tmp, disk6.disk[0].file_name + len + 1, 31); *(second_buf[i] + sprintf(second_buf[i], "%s", tmp)) = ' '; } if ((len = strlen(disk6.disk[1].file_name))) { while ((--len) && (disk6.disk[1].file_name[len] != '/')) { } strncpy(tmp, disk6.disk[1].file_name + len + 1, 31); sprintf(second_buf[i]+off, "%s", tmp); } memset(second_buf[++i], ' ', BUF_X); *(second_buf[i] + sprintf(second_buf[i], "%s %d bytes", (disk6.disk[0].nibblized) ? ".nib" : ".dsk", (int)disk6.disk[0].file_size)) = ' '; sprintf(second_buf[i++]+off, "%s %d bytes", (disk6.disk[1].nibblized) ? ".nib" : ".dsk", (int)disk6.disk[1].file_size); memset(second_buf[i], ' ', BUF_X); *(second_buf[i] + sprintf(second_buf[i], "write %s", (disk6.disk[0].is_protected) ? "protected" : "enabled")) = ' '; sprintf(second_buf[i++]+off, "write %s", (disk6.disk[1].is_protected) ? "protected" : "enabled"); memset(second_buf[i], ' ', BUF_X); *(second_buf[i] + sprintf(second_buf[i], "phase %d %s", disk6.disk[0].phase, (disk6.disk[0].phase_change) ? "(new)" : "")) = ' '; sprintf(second_buf[i++]+off, "phase %d %s", disk6.disk[1].phase, (disk6.disk[1].phase_change) ? "(new)" : ""); memset(second_buf[i], ' ', BUF_X); if (!disk6.disk[0].nibblized) { *(second_buf[i] + sprintf(second_buf[i], "sector %d", disk6.disk[0].sector)) = ' '; if (disk6.disk[1].nibblized) { ++i; } } if (!disk6.disk[1].nibblized) { sprintf(second_buf[i++]+off, "sector %d", disk6.disk[1].sector); } num_buffer_lines = i; } /* ------------------------------------------------------------------------- clear_debugger_screen () - clears the screen of graphics artifacts. ------------------------------------------------------------------------- */ void clear_debugger_screen() { int i; video_setpage( 0 ); for (i = 0; i < 24; i++) { c_interface_print(0, i, 2, screen[ i ] ); } } /* ------------------------------------------------------------------------- end_cpu_step () - finish a stepping command display the next instruction, and tell whether it will branch ------------------------------------------------------------------------- */ void end_cpu_step() { cpu65_set_stepping(0); clear_debugger_screen(); disasm(cpu65_current.pc, 1, 0, -1); int branch = will_branch(); if (branch == -1) { return; } sprintf(second_buf[num_buffer_lines++], "%s", (branch) ? "will branch" : "will not branch"); } /* ------------------------------------------------------------------------- begin_cpu_step() - step the CPU set the CPU into stepping mode and yield to CPU thread ------------------------------------------------------------------------- */ void begin_cpu_step() { cpu65_set_stepping(1); c_stepping_yield(); } /* ------------------------------------------------------------------------- c_stepping_yield() called to yield execution between cpu and main threads when stepping ------------------------------------------------------------------------- */ void c_stepping_yield() { int err = 0; if ((err = pthread_mutex_unlock(&interface_mutex))) { ERRLOG("pthread_mutex_unlock : %d", err); } // presumably other thread executes while we yield and sleep ... if ((err = pthread_yield())) { ERRLOG("pthread_yield ; %d", err); } static struct timespec deltat = { .tv_sec=0, .tv_nsec=1 }; nanosleep(&deltat, NULL); if ((err = pthread_mutex_lock(&interface_mutex))) { ERRLOG("pthread_mutex_lock : %d", err); } } /* ------------------------------------------------------------------------- do_step_or_next () - step into or step over commands ------------------------------------------------------------------------- */ void do_step_or_next(int step_count) { char ch; unsigned char op; int step_frame = 0; /* do step while step_count AND no breaks AND no keypress */ do { op = get_current_opcode(); if (step_next && (op == 0x20)) { do { op = get_current_opcode(); if (op == 0x20) { ++step_frame; /* JSR */ } if (op == 0x60) { --step_frame; /* RTS */ } begin_cpu_step(); } while (((ch = c_mygetch(0)) == -1) && !at_haltpt() && step_frame); } else { begin_cpu_step(); } } while (--step_count && !at_haltpt() && (c_mygetch(0) == -1)); end_cpu_step(); } /* ------------------------------------------------------------------------- display_help () show quick reference command usage ------------------------------------------------------------------------- */ void display_help() { /* "|||||||||||||||||||||||||||||||||||||" */ int i = num_buffer_lines; sprintf(second_buf[i++], "d{is} {lc1|lc2} {/bank/addr} {+}{len}"); sprintf(second_buf[i++], "m{em} {lc1|lc2} {/bank/addr} {+}{len}"); sprintf(second_buf[i++], "a{sc} {lc1|lc2} {/bank/addr} {+}{len}"); sprintf(second_buf[i++], "r{egs} "); sprintf(second_buf[i++], " {lc1|lc2} : "); sprintf(second_buf[i++], "(s{tep} | n{ext}) {len} "); sprintf(second_buf[i++], "f{inish} "); sprintf(second_buf[i++], "u{ntil} "); sprintf(second_buf[i++], "g{o} {addr} "); sprintf(second_buf[i++], "sea{rch} {lc1|lc2} {bank} "); sprintf(second_buf[i++], "(b{reak} | w{atch}) {addr} "); sprintf(second_buf[i++], "b{reak} op "); sprintf(second_buf[i++], "(c{lear} | i{gnore}) {num} "); sprintf(second_buf[i++], "c{lear} op "); sprintf(second_buf[i++], "(sta{tus} | op{codes}) "); sprintf(second_buf[i++], "(l{ang} | d{rive} | vm) "); sprintf(second_buf[i++], "bsave "); sprintf(second_buf[i++], "bload "); sprintf(second_buf[i++], "fr{esh} "); sprintf(second_buf[i++], "(h{elp} | ?) "); num_buffer_lines = i; } /* ------------------------------------------------------------------------- do_debug_command () perform a debugger command ------------------------------------------------------------------------- */ void do_debug_command() { int i = 0, j = 0, k = 0; /* reset key local vars */ step_next = 0; num_buffer_lines = 0; /* call lex to perform the command.*/ strncpy(lexbuf, command_line + PROMPT_X, BUF_X); init_lex(lexbuf, BUF_X+2); yylex(); /* set up to copy results into main buffer */ if (num_buffer_lines >= PROMPT_Y) { k = BUF_Y - PROMPT_Y; } else { /* scroll buffer */ for (i = 0, j = 0; i < PROMPT_Y - num_buffer_lines; i++, j = 0) { memcpy(command_buf[i], command_buf[num_buffer_lines+1+i], BUF_X); while ((j < BUF_X) && (command_buf[i][j] != '\0')) { j++; } memset(command_buf[i] + j, ' ', BUF_X - j - 1); command_buf[i][BUF_X - 1] = '\0'; } } /* copy the debug results into debug console window. change '\0's to ' 's and cap with a single '\0' */ while (i < PROMPT_Y) { j = 0; memcpy(command_buf[i], second_buf[k++], BUF_X); while ((j < BUF_X) && (command_buf[i][j] != '\0')) { ++j; } memset(command_buf[i] + j, ' ', BUF_X - j/* - 1*/); command_buf[i++][BUF_X - 1] = '\0'; } /* new prompt */ memset(command_line, ' ', BUF_X); command_line[0] = '>'; command_line[BUF_X - 1] = '\0'; /* display the new information */ for (i=0; i PROMPT_X)) { command_line[--command_pos] = ' '; } /* return */ else if (ch == 13) { command_line[command_pos] = '\0'; do_debug_command(); command_pos = PROMPT_X; } /* normal character */ else if ((ch >= ' ') && (ch < 127) && (command_pos < PROMPT_END_X)) { command_line[command_pos++] = ch; } } } }