#include "debug.h" #include #include "sm83.h" #include "sm83dis.h" #include "mem.h" #include "APU.h" //#include "z80analyze.h" #include "ui.h" #include "ui_window.h" #include "gbscreen.h" #define RESIZING_NONE 0 #define RESIZING_MEMORY 1 #define RESIZING_CONSOLE 2 #define RESIZING_SYMBOLS 3 #define RESIZING_X 4 namespace debug { int midx = 58; int mem_y = 20; int con_y = 28; int sym_y = 24; int win_h = 44; int mem_h = 8; int con_h = 6; int sym_h = 14; int resizing_type = RESIZING_MEMORY; bool resizing = false; namespace history { uint16_t buffer[65536]; uint8_t top=0; uint8_t pos=0; } uint16_t oAF, oBC, oDE, oHL, oSP, oPC; bool mem_modified[65536]; //[CHECK] SDL_Window *win = nullptr; SDL_Renderer *ren = nullptr; SDL_Texture *tex = nullptr; SDL_Cursor *cur_df = nullptr; SDL_Cursor *cur_ns = nullptr; SDL_Cursor *cur_we = nullptr; bool is_debugging=false; bool is_paused=false; uint16_t mem_viewer_pos = 0; char console_log[256][256]; char console_history[256][256]; uint8_t console_log_pos = 255; uint8_t console_history_pos = 0; uint8_t console_history_nav = 0; uint8_t breakpoints[65536]; uint16_t cursor = 0; uint8_t use[7][256]; uint16_t line_address[256]; uint16_t line_breakpoint_address[256]; int num_breakpoint_lines=0; bool sync_mem_with_cursor = false; uint8_t search_sequence[32]; int search_sequence_len=0; int search_pos=0; uint16_t inspected_value = 255; char temp[256]; const char *tohex(int value, int numdigits) { if (numdigits==2) sprintf(temp, "%02X", value); else if (numdigits==4) sprintf(temp, "%04X", value); return temp; } const char *todec(int value, bool sign) { if (sign) sprintf(temp, "%i", int8_t(value)); else sprintf(temp, "%u", value); return temp; } bool eventHandler(SDL_Event *e) { if (e->type == SDL_MOUSEMOTION) { SDL_ShowCursor(SDL_ENABLE); } if (debug::debugging()) { if (e->type==SDL_WINDOWEVENT) { if ((e->window.event==SDL_WINDOWEVENT_SHOWN) || (e->window.event==SDL_WINDOWEVENT_EXPOSED)) { int w; int h; SDL_GetWindowSize(win, &w, &h); midx = (w/CHR_W) - 25; win_h = (h/CHR_H); mem_y = win_h - mem_h - con_h; con_y = win_h - con_h; sym_h = win_h - sym_y; debug::refresh(); gbscreen::redraw(); } else if (e->window.event == SDL_WINDOWEVENT_CLOSE) { hide(); gbscreen::focus(); } } if (e->type == SDL_MOUSEWHEEL) { if (e->wheel.mouseXwheel.mouseYwheel.y>0) { debug::cursorback(); debug::refresh(); } else if (e->wheel.y<0) { debug::cursorfwd(); debug::refresh(); } } else if (e->wheel.mouseXwheel.mouseY>=mem_y*CHR_H && e->wheel.mouseYwheel.y>0) { mem_viewer_pos-=0x10; debug::refresh(); } else if (e->wheel.y<0) { mem_viewer_pos+=0x10; debug::refresh(); } } } if (e->type == SDL_KEYDOWN) { if (e->key.keysym.scancode==SDL_SCANCODE_ESCAPE) { return false; } else if (e->key.keysym.scancode==SDL_SCANCODE_F1) { debug::history::gototop(); debug::refresh(); //z80analyze::refresh(); } else if (e->key.keysym.scancode==SDL_SCANCODE_F2) { debug::history::goback(); debug::refresh(); //z80analyze::refresh(); } else if (e->key.keysym.scancode==SDL_SCANCODE_F3) { debug::history::goforward(); debug::refresh(); //z80analyze::refresh(); } else if (e->key.keysym.scancode==SDL_SCANCODE_F9) { const uint16_t address = cursor; if (breakpoints[line_address[address]]==0) breakpoints[line_address[address]]=1; else breakpoints[line_address[address]]=0; refresh(); } else if (e->key.keysym.scancode==SDL_SCANCODE_UP) { if (console_history_nav != console_history_pos+1 && console_history[console_history_nav-1][0]!=0) console_history_nav--; //z80debug::cursorback(); debug::refresh(); } else if (e->key.keysym.scancode==SDL_SCANCODE_DOWN) { if (console_history_nav != console_history_pos) console_history_nav++; //z80debug::cursorfwd(); debug::refresh(); } else if ( (e->key.keysym.scancode==SDL_SCANCODE_RETURN) || (e->key.keysym.scancode==SDL_SCANCODE_KP_ENTER)) { debug::executeConsole(); } else if (e->key.keysym.scancode==SDL_SCANCODE_BACKSPACE) { debug::DeleteCharConsole(); } } if (e->type == SDL_MOUSEMOTION) { if (!resizing) { if ( (e->motion.y > (mem_y*CHR_H)-8) && (e->motion.y < (mem_y*CHR_H)+8) && ( e->motion.x < midx*CHR_W ) ) { if (resizing_type != RESIZING_MEMORY) SDL_SetCursor(cur_ns); resizing_type = RESIZING_MEMORY; } else if ( (e->motion.y > (sym_y*CHR_H)-8) && (e->motion.y < (sym_y*CHR_H)+8) && ( e->motion.x >= midx*CHR_W ) ) { if (resizing_type != RESIZING_SYMBOLS) SDL_SetCursor(cur_ns); resizing_type = RESIZING_SYMBOLS; } else if ( (e->motion.y > (con_y*CHR_H)-8) && (e->motion.y < (con_y*CHR_H)+8) && (e->motion.x < midx*CHR_W) ) { if (resizing_type != RESIZING_CONSOLE) SDL_SetCursor(cur_ns); resizing_type = RESIZING_CONSOLE; } else { if (resizing_type != RESIZING_NONE) SDL_SetCursor(cur_df); resizing_type = RESIZING_NONE; } const int chrx = e->motion.x/CHR_W; const int chry = e->motion.y/CHR_H; //printf("%ix%i\n", chrx, chry); // Si pasa per damunt de l'adreça en el desensamblador if ( (chrx>1) && (chrx<6) && (chry0) ) { inspected_value = line_address[chry-1]; refresh(); // Si pasa per damunt dels bytes que formen el opcode en el desensamblador } else if ((chrx>=19) && (chrx<30) && (chry0)) { const uint16_t address = line_address[chry-1]; const int opcodesize = sm83dis::getOpcodeSize(address); const int byte = (chrx-19)/3; if (byte < opcodesize) { inspected_value = mem::readMem(address+byte); refresh(); } // Si pasa per damunt de l'adreça en el visor de memòria } else if ((chrx>1) && (chrx<6) && (chry>mem_y) && (chry6) && (chrx<55) && (chry>mem_y) && (chry=midx+4) && (chrx=midx+4) && (chrx=midx+4) && (chrx=midx+4) && (chrx=midx+20) && (chrx=midx+20) && (chrx=midx+6) && (chrx=midx+14) && (chrx=midx+22) && (chrxmotion.y/CHR_H; const int new_mem_h = win_h - new_mem_y - con_h; if (new_mem_y>=5 && new_mem_h>=3) { mem_y = new_mem_y; mem_h = new_mem_h; refresh(); } } else if (resizing_type==RESIZING_CONSOLE) { const int new_con_y = e->motion.y/CHR_H; const int new_con_h = win_h - new_con_y; const int new_mem_y = win_h - mem_h - new_con_h; if (new_mem_y>=5 && new_con_h>=3) { mem_y = new_mem_y; con_y = new_con_y; con_h = new_con_h; refresh(); } } else if (resizing_type==RESIZING_SYMBOLS) { const int new_sym_y = e->motion.y/CHR_H; const int new_sym_h = win_h - new_sym_y; if (new_sym_y>=12 && new_sym_h >=3) { sym_y = new_sym_y; sym_h = new_sym_h; refresh(); } } } } if (e->type == SDL_MOUSEBUTTONDOWN) { const int chrx = e->button.x/CHR_W; const int chry = e->button.y/CHR_H; //printf("%ix%i\n", chrx, chry); if ( (e->button.xbutton.y<(mem_y-1)*CHR_H) && (e->button.y>CHR_H) ) { const uint16_t address = ((e->button.y)/CHR_H)-1; if (breakpoints[line_address[address]]==0) breakpoints[line_address[address]]=1; else breakpoints[line_address[address]]=0; refresh(); } if (chrx>=midx+12 && chry>=9 && chrybreakpoint_selected) { cursor = line_breakpoint_address[breakpoint_selected]; refresh(); } } if (chrx>=10 && chrx<=12 && chry==mem_y) { sync_mem_with_cursor = ! sync_mem_with_cursor; refresh(); } if (chrx>=midx+2 && chry>=sym_y+1) { const int line = chry-(sym_y+1); if (linetype == SDL_MOUSEBUTTONUP) { if (resizing) { resizing = false; } } if (e->type == SDL_TEXTINPUT) { debug::sendToConsole(e->text.text); } } return true; } void processCommand(); void init() { is_debugging = is_paused = false; for (int i=0; i<65536; ++i) breakpoints[i]=0; if (!cur_df) cur_df = SDL_GetCursor(); if (!cur_ns) cur_ns = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); if (!cur_we) cur_we = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); memchr(console_log, 0, 65536); memchr(console_history, 0, 65536); //show(); } void show() { if (!win) { win = SDL_CreateWindow("Z80 Debugger", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 98*CHR_W, 44*CHR_H, SDL_WINDOW_RESIZABLE); ren = SDL_CreateRenderer(win, -1, 0); ui::window::registerWindow(SDL_GetWindowID(win), eventHandler); tex = ui::createtexture(ren); } focus(); //z80analyze::refresh(); } void focus() { if (win) { SDL_RaiseWindow(win); debug::refresh(); } } void hide() { ui::window::unregisterWindow(SDL_GetWindowID(win)); if (tex) SDL_DestroyTexture(tex); if (ren) SDL_DestroyRenderer(ren); if (win) SDL_DestroyWindow(win); tex = NULL; ren = NULL; win = NULL; } void pause() { APU::silence(); is_paused = true; breakpoints[sm83::getPC()] &= ~8; } void stop() { //history::gototop(); gbscreen::setTitle(" (stopped)"); pause(); is_debugging = true; show(); gbscreen::redraw(true); //if ( gbscreen::getFullRefresh()) gbscreen::fullrefresh(); } void cont() { gbscreen::setTitle(""); is_debugging = is_paused = false; refresh(); gbscreen::focus(); APU::resume(); } const bool debugging() { return is_debugging; } const bool paused() { return is_paused; } uint16_t find_previous_opcode(uint16_t pc) { pc--; uint8_t tag = mem::getTag(pc); if ( !(tag & (MEMTAG_CODE | MEMTAG_INST) ) ) return pc; while ( !(mem::getTag(pc) & MEMTAG_INST) ) pc--; return pc; /*if (sm83dis::getOpcodeSize(pc-3) == 3) return pc-3; if (sm83dis::getOpcodeSize(pc-3) == 3) return pc-3; if (sm83dis::getOpcodeSize(pc-2) == 2) return pc-2; return pc-1;*/ /* pc-=4; if (sm83dis::getOpcodeSize(pc) == 4) return pc; if (sm83dis::getOpcodeSize(pc) == 3) return pc+3; pc++; if (sm83dis::getOpcodeSize(pc) == 3) return pc; if (sm83dis::getOpcodeSize(pc) == 2) return pc+2; pc++; if (sm83dis::getOpcodeSize(pc) == 2) return pc; return pc+1; */ } void printDissasemblerLine(const uint16_t address, const int line, const bool heuristics=false) { uint8_t colors[4] = { COLOR_RED, COLOR_CYAN, COLOR_WHITE, COLOR_WHITE}; const uint8_t tag = mem::getTag(address); if ( !(tag & (MEMTAG_TINST | MEMTAG_TREPEAT)) ) colors[3]=COLOR_GRAY; if ( !(tag & MEMTAG_TOUCHED) ) colors[1]=COLOR_GRAY; if (is_debugging && (address == sm83::getPC())) { for (int i=0; i<4;++i) colors[i]=COLOR_YELLOW; ui::printrect(0,line, midx-2,1, COLOR_BLUE); } if (breakpoints[address]&9) ui::printtxt(0,line,"*", colors[0]); ui::printtxt(1,line,tohex(address,4), colors[1]); if ( (tag & MEMTAG_INST) || heuristics ) { const char *sym = sm83dis::getSymbol(address); if (sym[0]!=0) ui::printtxt(7,line, sym, COLOR_YELLOW); const int opcodesize = sm83dis::getOpcodeSize(address); for (int i=0; i=0;--i) { pos = find_previous_opcode(pos); line_address[i] = pos; printDissasemblerLine(pos, i); } // REGISTERS // ****************************************** ui::setoffset(0, 0); ui::box(midx,0,25,8,COLOR_WHITE); ui::printrect(midx+2,0, 12,1, COLOR_DARK); ui::printtxt(midx+3,0, "REGISTERS:", COLOR_WHITE); ui::setoffset(midx+1, 1); ui::printtxt(0,0, "AF AF' IX ", COLOR_WHITE); ui::printtxt(0,1, "BC BC' IY ", COLOR_WHITE); ui::printtxt(0,2, "DE DE' SP ", COLOR_WHITE); ui::printtxt(0,3, "HL HL' PC ", COLOR_WHITE); ui::printtxt(0,4, "(BC) (DE) (HL) ", COLOR_WHITE); ui::printtxt(0,5, " I R ", COLOR_WHITE); ui::printtxt(3,0, tohex(sm83::getAF(), 4), oAF != sm83::getAF() ? COLOR_RED : COLOR_GRAY); //ui::printtxt(11,0, tohex(sm83::getAF(true), 4), oAF2 != sm83::getAF(true) ? COLOR_RED : COLOR_GRAY); //ui::printtxt(19,0, tohex(sm83::getIX(), 4), oIX != sm83::getIX() ? COLOR_RED : COLOR_GRAY); ui::printtxt(3,1, tohex(sm83::getBC(), 4), oBC != sm83::getBC() ? COLOR_RED : COLOR_GRAY); //ui::printtxt(11,1, tohex(sm83::getBC(true), 4), oBC2 != sm83::getBC(true) ? COLOR_RED : COLOR_GRAY); //ui::printtxt(19,1, tohex(sm83::getIY(), 4), oIY != sm83::getIY() ? COLOR_RED : COLOR_GRAY); ui::printtxt(3,2, tohex(sm83::getDE(), 4), oDE != sm83::getDE() ? COLOR_RED : COLOR_GRAY); //ui::printtxt(11,2, tohex(sm83::getDE(true), 4), oDE2 != sm83::getDE(true) ? COLOR_RED : COLOR_GRAY); ui::printtxt(19,2, tohex(sm83::getSP(), 4), oSP != sm83::getSP() ? COLOR_RED : COLOR_GRAY); ui::printtxt(3,3, tohex(sm83::getHL(), 4), oHL != sm83::getHL() ? COLOR_RED : COLOR_GRAY); ui::printtxt(19,3, tohex(sm83::getPC(), 4), oPC != sm83::getPC() ? COLOR_RED : COLOR_GRAY); ui::printtxt(5,4, tohex(mem::readMem(sm83::getBC()), 2), COLOR_GRAY); ui::printtxt(13,4, tohex(mem::readMem(sm83::getDE()), 2), COLOR_GRAY); ui::printtxt(21,4, tohex(mem::readMem(sm83::getHL()), 2), COLOR_GRAY); const uint8_t flags = (sm83::getAF() & 0xFF); const uint8_t mod_flags = flags ^ (oAF & 0xFF); ui::printtxt(1,5,"Z", flags&0x80 ? (mod_flags&0x80 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x80 ? COLOR_BROWN : COLOR_GRAY) ); ui::printtxt(6,5,"N", flags&0x40 ? (mod_flags&0x40 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x40 ? COLOR_BROWN : COLOR_GRAY) ); ui::printtxt(3,5,"H", flags&0x20 ? (mod_flags&0x20 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x20 ? COLOR_BROWN : COLOR_GRAY) ); ui::printtxt(7,5,"C", flags&0x10 ? (mod_flags&0x10 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x10 ? COLOR_BROWN : COLOR_GRAY) ); // STACK // ****************************************** ui::setoffset(0, 0); ui::box(midx,8,11,12,COLOR_WHITE); ui::printrect(midx+2,8, 8,1, COLOR_DARK); ui::printtxt(midx+3,8, "STACK:", COLOR_WHITE); ui::setoffset(midx+1, 9); uint16_t sp = sm83::getSP();//-(((sym_y-12)>>1)<<1); for (int i=0; i<10; ++i) { uint8_t c1=COLOR_CYAN, c2=COLOR_GRAY; if (sp == sm83::getSP()) { ui::printrect(0,i,9,1,COLOR_BLUE); c1 = c2 = COLOR_YELLOW; } ui::printtxt(0,i, tohex(sp, 4), c1); uint16_t value = mem::readMem(sp) + (mem::readMem(sp+1)<<8); ui::printtxt(5,i, tohex(value, 4), c2); sp+=2; } // BREAKPOINTS // ****************************************** ui::setoffset(0, 0); ui::box(midx+11,8,14,12,COLOR_WHITE); ui::printrect(midx+13,8, 9,1, COLOR_DARK); ui::printtxt(midx+14,8, "BREAKS:", COLOR_WHITE); ui::setoffset(midx+12, 9); int line=0; num_breakpoint_lines=0; for (int i=0; i<65536; ++i) { if (breakpoints[i]&7) { line_breakpoint_address[line] = i; num_breakpoint_lines++; uint8_t colors[2] = {COLOR_WHITE, COLOR_GRAY}; if (i==cursor) { ui::printrect(1,line,10,1,COLOR_BLUE); colors[0]=colors[1]=COLOR_YELLOW; } ui::printtxt(2,line, tohex(i,4), colors[0]); ui::printtxt(7,line, breakpoints[i]&1?"x":"-", colors[1]); ui::printtxt(8,line, breakpoints[i]&2?"r":"-", colors[1]); ui::printtxt(9,line, breakpoints[i]&4?"w":"-", colors[1]); line++; if (line>9) break; } } // INSPECTOR // ****************************************** ui::setoffset(0, 0); ui::box(midx,20,25,4,COLOR_WHITE); ui::printrect(midx+2,20,12,1, COLOR_DARK); ui::printtxt(midx+3,20, "INSPECTOR:", COLOR_WHITE); ui::setoffset(midx+1, 21); ui::printtxt(1,0,"VALUE:", COLOR_GRAY); ui::printtxt(8,0,"$", COLOR_CYAN); ui::printtxt(9,0,tohex(inspected_value,4), COLOR_CYAN); ui::printtxt(14,0,todec(inspected_value,false), COLOR_WHITE); ui::printtxt(20,0,todec(inspected_value,true), COLOR_WHITE); ui::printtxt(1,1,"H:", COLOR_GRAY); ui::printtxt(4,1,"$", COLOR_CYAN); ui::printtxt(5,1,tohex(inspected_value>>8,2), COLOR_CYAN); ui::printtxt(8,1,todec(inspected_value>>8,false), COLOR_WHITE); ui::printtxt(12,1,"L:", COLOR_GRAY); ui::printtxt(15,1,"$", COLOR_CYAN); ui::printtxt(16,1,tohex(inspected_value&0xff,2), COLOR_CYAN); ui::printtxt(19,1,todec(inspected_value&0xff,false), COLOR_WHITE); // MEMORY // ****************************************** ui::setoffset(0, 0); ui::box(0,mem_y,midx,mem_h,COLOR_WHITE); ui::printrect(2,mem_y, 11,1, COLOR_DARK); ui::printtxt(3,mem_y, "MEMORY:", COLOR_WHITE); ui::printvoidrect(10,mem_y,3,1,COLOR_WHITE); if (sync_mem_with_cursor) ui::printchar(11,mem_y,'X',COLOR_WHITE); ui::setoffset(1, mem_y+1); uint16_t mem_viewer_cursor = mem_viewer_pos; for (int i=0; i", COLOR_WHITE); ui::printtxt(1,line, console_history[console_history_nav], COLOR_WHITE); ui::printtxt(strlen(console_history[console_history_nav])+1,line, "\x7F", COLOR_WHITE); uint8_t i = console_log_pos; while (line>0) { line--; ui::printtxt(1,line, console_log[i--], COLOR_GRAY); } // SYMBOLS // ***************************************** ui::setoffset(0, 0); ui::box(midx,sym_y,25,sym_h,COLOR_WHITE); ui::printrect(midx+2,sym_y, 9,1, COLOR_DARK); ui::printtxt(midx+3,sym_y, "SYMBOLS:", COLOR_WHITE); ui::setoffset(midx+1, sym_y+1); const int num_symbols = sm83dis::getNumSymbols(); for (int i=0;i"); strcat(console_log[console_log_pos], console_history[console_history_pos]); processCommand(); console_history_pos++; console_history_nav=console_history_pos; console_history[console_history_pos][0] = 0; refresh(); } const char integer_digits[] = "0123456789"; const char hex_digits[] = "0123456789ABCDEF"; const int getnum(const char *str) { int i=0; int return_value = 0; if (str[0]=='$') { i++; while(str[i]!=0) { int num = str[i]-48; if (num<0) return -1; if (num>9) { num-=7; if (num>15) { num-=32; if (num<10 || num>15) return -1; } } return_value = (return_value<<4)+num; i++; } } else { while(str[i]!=0) { int num = str[i]-48; if (num<0 || num>9) return -1; return_value = (return_value*10)+num; i++; } } return return_value; } #define getcmd() {while (*console_ptr==32) console_ptr++;while (console_ptr[i]!=0 && console_ptr[i]!=32) { cmd[i]=console_ptr[i]; i++; } cmd[i]=0; console_ptr = &console_ptr[i]; i=0;} void processCommand() { char cmd[256]; int i=0; char *console_ptr = console_history[console_history_pos]; getcmd(); if (strcmp(cmd, "s")==0 || strcmp(cmd, "step")==0) { uint8_t dt = sm83::step(); //zx_tape::update(dt); //zx_ula::sound_update(dt); gbscreen::refresh(dt); gbscreen::redraw(); //z80analyze::refresh(); } else if (strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) { sm83::step(); debug::cont(); //z80analyze::refresh(); } else if (strcmp(cmd, "r")==0 || strcmp(cmd, "reset")==0) { sm83::reset(); debug::refresh(); //z80analyze::refresh(); } else if (strcmp(cmd, "b")==0 || strcmp(cmd, "break")==0) { getcmd(); if (cmd[0] == 0) { breakpoints[sm83::getPC()]=1; return; } if (cmd[0] == 'i') { sm83::setOption(SM83_OPTION_BREAK_ON_INTERRUPT, !sm83::getOption(SM83_OPTION_BREAK_ON_INTERRUPT)); sendToConsoleLog("Break on interrupt."); return; } int address = getnum(cmd); if (address<0 || address>65536) { sendToConsoleLog("Illegal break address"); return; } getcmd(); uint8_t break_type = 1; if (cmd[0]!=0) { if (strcmp(cmd, "x")==0 || strcmp(cmd, "exec")==0) { break_type = 1; } else if (strcmp(cmd, "r")==0 || strcmp(cmd, "read")==0) { break_type = 2; } else if (strcmp(cmd, "w")==0 || strcmp(cmd, "write")==0) { break_type = 4; } else { sendToConsoleLog("Illegal break type"); return; } } breakpoints[address] |= break_type; } else if (strcmp(cmd, "d")==0 || strcmp(cmd, "delete")==0) { getcmd(); if (strcmp(cmd, "all")==0) { for (int i=0;i<65536;++i) breakpoints[i]=0; return; } if (cmd[0] == 0) { breakpoints[sm83::getPC()]=0; return; } int address = getnum(cmd); if (address<0 || address>65536) { sendToConsoleLog("Illegal address"); return; } getcmd(); uint8_t break_type = 7; if (cmd[0]!=0) { if (strcmp(cmd, "x")==0 || strcmp(cmd, "exec")==0) { break_type = 1; } else if (strcmp(cmd, "r")==0 || strcmp(cmd, "read")==0) { break_type = 2; } else if (strcmp(cmd, "w")==0 || strcmp(cmd, "write")==0) { break_type = 4; } else { sendToConsoleLog("Illegal break type"); return; } } breakpoints[address] &= ~break_type; } else if (strcmp(cmd, "m")==0 || strcmp(cmd, "mem")==0) { getcmd(); int address = getnum(cmd); if (address<0 || address>65536) { sendToConsoleLog("Illegal memory address"); return; } mem_viewer_pos = address; } else if (strcmp(cmd, "st")==0 || strcmp(cmd, "save")==0) { getcmd(); char filename[256]; strcpy(filename, cmd); savestate(filename); } else if (strcmp(cmd, "l")==0 || strcmp(cmd, "load")==0) { getcmd(); char filename[256]; strcpy(filename, cmd); loadstate(filename); //z80analyze::refresh(); } else if (strcmp(cmd, "t")==0 || strcmp(cmd, "tape")==0) { getcmd(); if (strcmp(cmd, "load")==0) { getcmd(); char filename[256]; strcpy(filename, cmd); //zx_tape::load(filename); } else if (strcmp(cmd, "play")==0) { //zx_tape::play(); } } else if (strcmp(cmd, "poke")==0) { getcmd(); int address = getnum(cmd); getcmd(); int value = getnum(cmd); mem::writeMem(address, value); } else if (strcmp(cmd, "peek")==0) { getcmd(); int address = getnum(cmd); int value = mem::readMem(address); char tmp[10]; sendToConsoleLog(SDL_itoa(value, tmp, 10)); } else if (strcmp(cmd, "reg")==0) { getcmd(); if (strcmp(cmd, "f")==0) { getcmd(); int value = getnum(cmd); sm83::getRegs()[0] = value; } else if (strcmp(cmd, "a")==0) { getcmd(); int value = getnum(cmd); sm83::getRegs()[1] = value; } else if (strcmp(cmd, "c")==0) { getcmd(); int value = getnum(cmd); sm83::getRegs()[2] = value; } else if (strcmp(cmd, "b")==0) { getcmd(); int value = getnum(cmd); sm83::getRegs()[3] = value; } else if (strcmp(cmd, "e")==0) { getcmd(); int value = getnum(cmd); sm83::getRegs()[4] = value; } else if (strcmp(cmd, "d")==0) { getcmd(); int value = getnum(cmd); sm83::getRegs()[5] = value; } else if (strcmp(cmd, "l")==0) { getcmd(); int value = getnum(cmd); sm83::getRegs()[6] = value; } else if (strcmp(cmd, "h")==0) { getcmd(); int value = getnum(cmd); sm83::getRegs()[7] = value; } else { sendToConsoleLog("Syntax error: invalid register"); return; } } else if (strcmp(cmd, "g")==0 || strcmp(cmd, "goto")==0) { getcmd(); int address = getnum(cmd); if (address<0 || address>=65536) { sendToConsoleLog("Illegal address"); return; } if ( !(mem::getTag(address) & MEMTAG_INST) ) address = find_previous_opcode(address); debug::setcursor(address); } else if (strcmp(cmd, "sym")==0 || strcmp(cmd, "symbol")==0) { getcmd(); if (strcmp(cmd, "add")==0) { getcmd(); char tmp[12]; strcpy(tmp, cmd); getcmd(); if (cmd[0]==0) { sm83dis::setSymbol(sm83::getPC(), tmp); } else { int value = getnum(cmd); sm83dis::setSymbol(value, tmp); } sendToConsoleLog("Symbol added"); } else if (strcmp(cmd, "del")==0) { getcmd(); if (cmd[0]==0) { sm83dis::setSymbol(sm83::getPC(), NULL); } else { int value = getnum(cmd); sm83dis::setSymbol(value, NULL); } sendToConsoleLog("Symbol removed"); } } else if (strcmp(cmd, "ula")==0) { getcmd(); if (strcmp(cmd, "keydown")==0) { getcmd(); //zx_ula::keydown(cmd[0]); sendToConsoleLog("Keydown sent for key: "); sendMoreToConsoleLog(cmd); } else if (strcmp(cmd, "keyup")==0) { getcmd(); //zx_ula::keyup(cmd[0]); sendToConsoleLog("Keyup sent for key: "); sendMoreToConsoleLog(cmd); } } else if (strcmp(cmd, "opcodes")==0) { getcmd(); if (strcmp(cmd, "clear")==0 || strcmp(cmd, "reset")==0) { clearUsedOpcodes(); } else if (strcmp(cmd, "mark")==0) { markUsedOpcodes(); } else if (strcmp(cmd, "count")==0) { printf("Num opcodes used: %i\n", getNumOpcodesUsed()); } else if (strcmp(cmd, "print")==0) { printOpcodesUsed(); } } else if (strcmp(cmd, "ignore")==0) { getcmd(); const int address = getnum(cmd); mem::setTag(address, mem::getTag(address) | MEMTAG_IGNORE); } else if (strcmp(cmd, "search")==0) { getcmd(); if (strcmp(cmd, "next")==0) { search(); } else { search(cmd); } } else if (strcmp(cmd, "show")==0) { getcmd(); if (strcmp(cmd, "analyzer")==0) { //z80analyze::show(); } else { sendToConsoleLog("Unrecognized window. Usage: Show [analyzer]"); } } else { sendToConsoleLog("Unrecognized command."); } } const bool isbreak(const uint16_t address, const uint8_t type) { return (breakpoints[address]&type); } uint32_t next() { breakpoints[sm83::getPC()+sm83dis::getOpcodeSize(sm83::getPC())] |= 8; const uint32_t t = sm83::step(); cont(); return t; } uint32_t stepout() { sm83::setOption(SM83_OPTION_BREAK_ON_RET, true); const uint32_t t = sm83::step(); cont(); return t; } void setmemmodified(const uint16_t addr) { mem_modified[addr] = true; } void loadngo(const char* filename, const char* addr) { /* int address = getnum(addr); if (address<0 || address>65536) { sendToConsoleLog("Illegal offset"); return; } FILE *f = fopen(filename, "rb"); fseek(f, 0, SEEK_END); int size = ftell(f); fseek(f, 0, SEEK_SET); uint32_t memsize; uint8_t *memory = mem::getRawPointer(&memsize); fread(memory+address, size, 1, f); fclose(f); sm83::setPC(address); is_debugging = is_paused = false; */ } void savestate(const char *filename) { uint8_t *regs = sm83::getRegs(); FILE *f = fopen(filename, "wb"); fwrite(regs, 31, 1, f); mem::saveState(f); fclose(f); } void loadstate(const char *filename) { uint8_t *regs = sm83::getRegs(); FILE *f = fopen(filename, "rb"); fread(regs, 31, 1, f); mem::loadState(f); fclose(f); history::store(); history::gototop(); } void setcursor(const uint16_t address) { //if (!debugging()) return; if ( !(mem::getTag(address) & MEMTAG_INST) ) cursor = find_previous_opcode(address); else cursor = address; } void cursorfwd() { cursor += sm83dis::getOpcodeSize(cursor); } void cursorback() { cursor = find_previous_opcode(cursor); } void useOpcode(const uint8_t opcode, const uint8_t base) { if (use[base][opcode]<255) use[base][opcode]++; } void clearUsedOpcodes() { for (int i=0; i<7; ++i) { for (int j=0; j<256; ++j) { use[i][j]=0; } } } void markUsedOpcodes() { for (int i=0; i<7; ++i) { for (int j=0; j<256; ++j) { if (use[i][j]==1) use[i][j]++; } } } const int getNumOpcodesUsed() { int count = 0; for (int i=0; i<7; ++i) { for (int j=0; j<256; ++j) { if (use[i][j]==1) count++; } } return count; } void printOpcodesUsed() { for (int i=0; i<7; ++i) { for (int j=0; j<256; ++j) { if (use[i][j]==1) { switch (i) { case 1: printf("ED "); break; case 2: printf("CB "); break; case 3: printf("DD "); break; case 4: printf("DD CB "); break; case 5: printf("FD "); break; case 6: printf("FD CB "); break; } printf("%2X\n",j); } } } } uint8_t hexchartonum(char chr) { int num = chr-48; if (num<0) return 0; if (num>9) { num-=7; if (num>15) { num-=32; if (num<10 || num>15) return 0; } } return uint8_t(num); } void search(const char *seq) { if (seq) { search_pos = 0; search_sequence_len=0; while (*seq!=0) search_sequence[search_sequence_len++] = (hexchartonum(*(seq++))<<4) + hexchartonum(*(seq++)); } int num_found=0; while (search_pos<65536) { if (search_sequence[num_found] == mem::readMem(search_pos)) { num_found++; search_pos++; if (num_found==search_sequence_len) { mem_viewer_pos=search_pos-search_sequence_len; return; } } else { num_found=0; search_pos++; } } sendToConsoleLog("Sequence not found."); } namespace history { void store() { buffer[++top] = sm83::getPC(); pos=top; } void gototop() { pos = top; sm83::setPC(buffer[pos]); cursor = sm83::getPC(); } void goforward() { if (pos == top) return; sm83::setPC(buffer[++pos]); cursor = sm83::getPC(); } void goback() { if (uint8_t(pos-1) == top) return; sm83::setPC(buffer[--pos]); cursor = sm83::getPC(); } } }