diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d6cf3ab --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +gb diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5d09430 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +compile: + g++ -g *.cpp -lSDL2 -o gb + +run: compile + ./gb + +debug: compile + gdb -ex run gb diff --git a/debug.cpp b/debug.cpp new file mode 100644 index 0000000..f1bbc05 --- /dev/null +++ b/debug.cpp @@ -0,0 +1,1165 @@ +#include "debug.h" +#include +#include "sm83.h" +#include "sm83dis.h" +#include "mem.h" +//#include "z80analyze.h" +#include "ui.h" +#include "ui_window.h" +//#include "zx_screen.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(); + //zxscreen::redraw(); + } else if (e->window.event == SDL_WINDOWEVENT_CLOSE) { + hide(); + //zxscreen::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() + { + //zx_ula::sound_disable(); + is_paused = true; + breakpoints[sm83::getPC()] &= ~8; + } + + void stop() + { + //history::gototop(); + //zxscreen::setTitle(" (stopped)"); + pause(); + is_debugging = true; + show(); + //if ( zxscreen::getFullRefresh()) zxscreen::fullrefresh(); + } + + void cont() { + //zxscreen::setTitle(""); + is_debugging = is_paused = false; + refresh(); + //zxscreen::focus(); + //zx_ula::sound_enable(); + } + + 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(0,5,"S", flags&0x80 ? (mod_flags&0x80 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x80 ? COLOR_BROWN : COLOR_GRAY) ); + ui::printtxt(1,5,"Z", flags&0x40 ? (mod_flags&0x40 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x40 ? COLOR_BROWN : COLOR_GRAY) ); + ui::printtxt(2,5,"X", flags&0x20 ? (mod_flags&0x20 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x20 ? COLOR_BROWN : COLOR_GRAY) ); + ui::printtxt(3,5,"H", flags&0x10 ? (mod_flags&0x10 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x10 ? COLOR_BROWN : COLOR_GRAY) ); + ui::printtxt(4,5,"Y", flags&0x08 ? (mod_flags&0x08 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x08 ? COLOR_BROWN : COLOR_GRAY) ); + ui::printtxt(5,5,"P", flags&0x04 ? (mod_flags&0x04 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x04 ? COLOR_BROWN : COLOR_GRAY) ); + ui::printtxt(6,5,"N", flags&0x02 ? (mod_flags&0x02 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x02 ? COLOR_BROWN : COLOR_GRAY) ); + ui::printtxt(7,5,"C", flags&0x01 ? (mod_flags&0x01 ? COLOR_RED : COLOR_WHITE) : (mod_flags&0x01 ? 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); + //zxscreen::fullrefresh(); + //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(); + } + + } + +} \ No newline at end of file diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..87b1587 --- /dev/null +++ b/debug.h @@ -0,0 +1,53 @@ +#pragma once +#include + +namespace debug +{ + void init(); + void show(); + void focus(); + void hide(); + + void pause(); + void stop(); + void cont(); + const bool debugging(); + const bool paused(); + void setmemmodified(const uint16_t addr); + + void refresh(); + void sendToConsole(const char* text); + void sendToConsoleLog(const char *text); + void sendMoreToConsoleLog(const char *text); + void DeleteCharConsole(); + void executeConsole(); + + const bool isbreak(const uint16_t address, const uint8_t type=1); + uint32_t next(); + uint32_t stepout(); + + void savestate(const char *filename); + void loadstate(const char *filename); + + void loadngo(const char* filename, const char* addr); + + void setcursor(const uint16_t address); + void cursorfwd(); + void cursorback(); + + void useOpcode(const uint8_t opcode, const uint8_t base); + void clearUsedOpcodes(); + void markUsedOpcodes(); + const int getNumOpcodesUsed(); + void printOpcodesUsed(); + + void search(const char *seq=nullptr); + + namespace history + { + void store(); + void gototop(); + void goforward(); + void goback(); + } +} \ No newline at end of file diff --git a/main.cpp b/main.cpp index 17d80f5..ef77f06 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,221 @@ +#include +#include + #include "sm83.h" #include "mem.h" +#include "sm83dis.h" +#include "debug.h" +//#include "zx_ula.h" +//#include "zx_screen.h" +//#include "zx_tape.h" +#include +#include +#include "ui.h" +#include "ui_menu.h" +//#include "z80analyze.h" +#include "ui_window.h" + +uint32_t time = 0; +uint32_t t_states = 0; + +namespace actions +{ + void exitMenu() + { + const uint8_t dt = sm83::step(); + debug::cont(); + //zxscreen::refresh(dt); + } + + int decZoom(int value) + { + //zxscreen::decZoom(); + return 0; + } + + int incZoom(int value) + { + //zxscreen::incZoom(); + return 0; + } + + int fullscreen(int value) + { + //zxscreen::toggleFullscreen(); + return 0; //zxscreen::getFullscreen(); + } + + int fullrefresh(int value) + { + //zxscreen::toggleFullRefresh(); + return 0; //zxscreen::getFullRefresh(); + } + + int showAnalyzer(int value) + { + //z80analyze::show(); + return 0; + } +} int main(int argc, char *argv[]) { - mem::init(nullptr, 0); - + if (argc < 2) { printf("ABORTING: No rom specified.\n"); exit(1); } + + const uint32_t clock = 4194304; + const uint32_t update_freq = clock / 10; + + FILE *f = fopen(argv[1], "rb"); + if (!f) { printf("ABORTING: Rom not found.\n"); exit(1); } + fseek(f, 0, SEEK_END); + const int filesize = ftell(f); + fseek(f, 0, SEEK_SET); + uint8_t *buffer = (uint8_t*)malloc(filesize); + fread(buffer, filesize, 1, f); + fclose(f); + mem::init(buffer, filesize); + + sm83dis::loadSymbols(); + sm83::reset(); + + SDL_Init(SDL_INIT_EVERYTHING); + debug::init(); + //zxscreen::init(SCREEN_MODE_48K); + + ui::menu::init(); + ui::menu::setexitcallback(actions::exitMenu); + + int menu = ui::menu::addsubmenu("FILE"); + ui::menu::addoption(menu, "LOAD ROM", nullptr); + ui::menu::addoption(menu, "SAVE ROM", nullptr); + ui::menu::addseparator(menu); + ui::menu::addoption(menu, "LOAD STATE", nullptr); + ui::menu::addoption(menu, "SAVE STATE", nullptr); + + menu = ui::menu::addsubmenu("SCREEN"); + ui::menu::addoption(menu, "DEC ZOOM", actions::decZoom); + ui::menu::addoption(menu, "INC ZOOM", actions::incZoom); + ui::menu::addbooloption(menu, "FULLSCREEN", false /*zxscreen::getFullscreen()*/, actions::fullscreen); + ui::menu::addseparator(menu); + ui::menu::addbooloption(menu, "FULL REFRESH", false /*zxscreen::getFullRefresh()*/, actions::fullrefresh); + + menu = ui::menu::addsubmenu("EMULATION"); + ui::menu::addbooloption(menu, "STOP ON INVALID OP", sm83::getOption(SM83_OPTION_STOP_ON_INVALID), actions::decZoom); + ui::menu::addoption(menu, "SHOW ANALYZER", actions::showAnalyzer); + + //zx_ula::sound_init(); + + debug::stop(); + + bool should_exit = false; + SDL_Event e; + + time = SDL_GetTicks(); + t_states = 0; + + while (!should_exit) + { + while (SDL_PollEvent(&e)) + { + bool result = true; + + if (e.type == SDL_QUIT) { should_exit=true; break; } + if (e.type == SDL_MOUSEBUTTONDOWN) result = ui::window::sendEvent(e.button.windowID, &e); + if (e.type == SDL_MOUSEBUTTONUP) result = ui::window::sendEvent(e.button.windowID, &e); + if (e.type == SDL_MOUSEMOTION) result = ui::window::sendEvent(e.motion.windowID, &e); + if (e.type == SDL_WINDOWEVENT) result = ui::window::sendEvent(e.window.windowID, &e); + if (e.type == SDL_MOUSEWHEEL) result = ui::window::sendEvent(e.wheel.windowID, &e); + if (e.type == SDL_TEXTINPUT) result = ui::window::sendEvent(e.text.windowID, &e); + if (e.type == SDL_KEYDOWN) { + if (e.key.keysym.scancode==SDL_SCANCODE_F5) { + if (debug::debugging()) { + debug::history::gototop(); + const uint8_t dt = sm83::step(); + debug::cont(); + //zxscreen::refresh(dt); + } + } else if (e.key.keysym.scancode==SDL_SCANCODE_F8) { + if (!debug::debugging()) { + debug::stop(); + //zxscreen::redraw(); + } else { + debug::show(); + } + } else if (e.key.keysym.scancode==SDL_SCANCODE_F10) { + if (debug::debugging()) { + debug::show(); + debug::history::gototop(); + const uint8_t dt = sm83::step(); + debug::refresh(); + //zxscreen::fullrefresh(); + //zxscreen::redraw(); + //z80analyze::refresh(); + } + } else if (e.key.keysym.scancode==SDL_SCANCODE_F11) { + if (debug::debugging()) { + debug::show(); + debug::history::gototop(); + const uint8_t dt = debug::next(); + debug::refresh(); + //zxscreen::refresh(dt); + //zxscreen::redraw(); + //z80analyze::refresh(); + } + } else if (e.key.keysym.scancode==SDL_SCANCODE_F12) { + if (debug::debugging()) { + debug::show(); + debug::history::gototop(); + const uint8_t dt = debug::stepout(); + debug::refresh(); + //zxscreen::refresh(dt); + //zxscreen::redraw(); + //z80analyze::refresh(); + } + } + result = ui::window::sendEvent(e.key.windowID, &e); + } + + if (e.type == SDL_MOUSEBUTTONUP && e.button.button==1) ui::setClicked(true); + + if (!result) + should_exit = true; break; + } + + if (!debug::debugging() && !debug::paused()) { + bool fastload=false; + + // En cada bucle fem 10 pasos de la CPU, sino s'ofega + for (int i=0;i<5;++i) { + if (debug::isbreak(sm83::getPC(), 9)) { + debug::stop(); + //zxscreen::redraw(); + break; + } else { + uint8_t dt = sm83::step(); + t_states += dt; + //zx_ula::sound_update(dt); + //zxscreen::refresh(dt); + if (debug::debugging()) break; + } + } + + if (t_states>=update_freq) + { + while (SDL_GetTicks() namespace mbc_none { @@ -10,6 +11,8 @@ namespace mbc_none uint8_t wram[8192]; uint8_t hram[512]; + uint8_t tags[65536]; + uint8_t readMem(uint16_t address) { if (address < 0x8000) { @@ -47,10 +50,49 @@ namespace mbc_none } } - void init(uint8_t *rom) + uint8_t getTag(uint16_t address) + { + return tags[address]; + } + + void setTag(uint16_t address, uint8_t value) + { + tags[address] = value; + } + + void saveState(FILE* f) + { + + } + + void loadState(FILE *f) + { + + } + + void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size) { mem::readMem = mbc_none::readMem; mem::writeMem = mbc_none::writeMem; + mem::getTag = mbc_none::getTag; + mem::setTag = mbc_none::setTag; + mem::saveState = mbc_none::saveState; + mem::loadState = mbc_none::loadState; + mbc_none::rom = rom; + + FILE *f = fopen("dmg_boot.bin", "rb"); + if (!f) { printf("ABORTING: 'dmg_boot.bin' not found!\n"); exit(1); } + fseek(f, 0, SEEK_END); + const int size = ftell(f); + fseek(f, 0, SEEK_SET); + fread(bootrom, size, 1, f); + fclose(f); + + for (int i=0; i<8192; ++i) { vram[i] = 0; } + for (int i=0; i<8192; ++i) { exram[i] = 0; } + for (int i=0; i<8192; ++i) { wram[i] = 0; } + for (int i=0; i<512; ++i) { hram[i] = 0; } + for (int i=0; i<65536; ++i) { tags[i] = MEMTAG_NONE; } } } \ No newline at end of file diff --git a/mbc_none.h b/mbc_none.h index 5323160..be6465f 100644 --- a/mbc_none.h +++ b/mbc_none.h @@ -1,6 +1,7 @@ #pragma once +#include namespace mbc_none { - void init(); + void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size); } diff --git a/mem.cpp b/mem.cpp index 1096581..5178e91 100644 --- a/mem.cpp +++ b/mem.cpp @@ -1,28 +1,20 @@ #include "mem.h" #include +#include +#include "mbc_none.h" namespace mem { uint8_t(*readMem)(uint16_t); void (*writeMem)(uint16_t, uint8_t); + uint8_t(*getTag)(uint16_t); + void (*setTag)(uint16_t, uint8_t); + void (*saveState)(FILE*); + void (*loadState)(FILE*); char *title = nullptr; - /*uint8_t *memory = nullptr; - uint8_t *mapper_type = nullptr; - uint8_t *rom_size = nullptr; - uint8_t *ram_size = nullptr;*/ - uint8_t r(uint16_t address) - { - return 0; - } - - void w(uint16_t address, uint8_t value) - { - - } - - void init(const uint8_t* rom, const int size) + void init(uint8_t* rom, const int size) { //if (memory) free(memory); //memory = (uint8_t*)malloc(size); @@ -32,8 +24,12 @@ namespace mem int sizes[] = { 0, 0, 8, 32, 128, 64}; uint32_t ram_size = sizes[rom[0x149]] * 1024; - readMem = r; - writeMem = w; + switch (mapper_type) + { + case 0x00: + mbc_none::init(rom, rom_size, ram_size); + break; + }; } void reset() diff --git a/mem.h b/mem.h index 06553a0..4835579 100644 --- a/mem.h +++ b/mem.h @@ -1,8 +1,21 @@ #pragma once #include - +#include namespace mem { + #define MEMTAG_NONE 0x00 + #define MEMTAG_DATA 0x01 + #define MEMTAG_INST 0x02 + #define MEMTAG_CODE 0x04 + #define MEMTAG_IGNORE 0x08 + #define MEMTAG_TDATA 0x10 + #define MEMTAG_TINST 0x20 + #define MEMTAG_TREPEAT 0x40 + #define MEMTAG_MODIFIED 0x80 + + #define MEMTAG_KNOWN 0x07 + #define MEMTAG_TOUCHED 0x70 + #define MBC_NONE 0 #define MBC1 1 #define MBC2 2 @@ -11,8 +24,15 @@ namespace mem #define MBC6 6 #define MBC7 7 - void init(const uint8_t* rom, const int size); + void init(uint8_t* rom, const int size); void reset(); + extern uint8_t(*readMem)(uint16_t); extern void (*writeMem)(uint16_t, uint8_t); + + extern uint8_t(*getTag)(uint16_t); + extern void (*setTag)(uint16_t, uint8_t); + + extern void (*saveState)(FILE*); + extern void (*loadState)(FILE*); } diff --git a/sm83.cpp b/sm83.cpp index c4ecb5b..799e230 100644 --- a/sm83.cpp +++ b/sm83.cpp @@ -1,7 +1,6 @@ #include "sm83.h" #include "mem.h" -//#include "z80debug.h" -//#include "z80mem.h" +#include "debug.h" #include namespace sm83 @@ -75,22 +74,21 @@ namespace sm83 uint8_t READ_MEM_8(const uint16_t addr, const bool code=false) { - //if (z80debug::isbreak(addr, 2)) z80debug::stop(); + if (debug::isbreak(addr, 2)) debug::stop(); t+=4; - /* - const uint8_t tag = z80mem::get()->getTag(addr); + + const uint8_t tag = mem::getTag(addr); if ( !(tag&MEMTAG_IGNORE) ) { if (!code) { if ( tag & MEMTAG_INST ) { } else { - z80mem::get()->setTag(addr, tag | MEMTAG_DATA); + mem::setTag(addr, tag | MEMTAG_DATA); } } else { if ( (reading_m1) && ( tag & MEMTAG_DATA ) ) { } } } - */ reading_m1 = false; return mem::readMem(addr); } @@ -98,8 +96,8 @@ namespace sm83 uint8_t READ_MEM_8() { const uint8_t data = READ_MEM_8(rPC, true); - //const uint8_t tag = z80mem::get()->getTag(rPC); - //if ( !(tag & MEMTAG_IGNORE) ) z80mem::get()->setTag(rPC, tag | MEMTAG_CODE); + const uint8_t tag = mem::getTag(rPC); + if ( !(tag & MEMTAG_IGNORE) ) mem::setTag(rPC, tag | MEMTAG_CODE); rPC++; return data; } @@ -127,20 +125,18 @@ namespace sm83 t+=4; mem::writeMem(addr, value); - /* - if (z80debug::isbreak(addr, 4)) z80debug::stop(); - z80debug::setmemmodified(addr); + if (debug::isbreak(addr, 4)) debug::stop(); + debug::setmemmodified(addr); - const uint8_t tag = z80mem::get()->getTag(addr); + const uint8_t tag = mem::getTag(addr); if ( !(tag & MEMTAG_IGNORE) ) { if ( tag & MEMTAG_INST ) { //printf("WARNING! WRITING DATA OVER CODE!!! $%4X\n", addr); //z80debug::stop(); } else { - z80mem::get()->setTag(addr, tag | MEMTAG_DATA | MEMTAG_TDATA); + mem::setTag(addr, tag | MEMTAG_DATA | MEMTAG_TDATA); } } - */ return value; } @@ -718,10 +714,10 @@ namespace sm83 t = 0; const uint8_t opcode = READ_M1(); - /*uint8_t tag = z80mem::get()->getTag(current_opcode_address); + uint8_t tag = mem::getTag(current_opcode_address); if ( !(tag & MEMTAG_IGNORE) ) tag = tag | MEMTAG_INST; - z80mem::get()->setTag(current_opcode_address, tag | (!(tag&MEMTAG_TOUCHED) ? MEMTAG_TREPEAT : MEMTAG_TINST) );*/ + mem::setTag(current_opcode_address, tag | (!(tag&MEMTAG_TOUCHED) ? MEMTAG_TREPEAT : MEMTAG_TINST) ); uint16_t tmp; @@ -1007,8 +1003,8 @@ namespace sm83 if (pending_ei==2) { pending_ei=0; actualEI(); } if (pending_ei==1) pending_ei=2; - /*z80debug::setcursor(rPC); - z80debug::history::store();*/ + debug::setcursor(rPC); + debug::history::store(); return t; } @@ -1308,32 +1304,6 @@ namespace sm83 void setPC(const uint16_t addr) { rPC = addr; } -/* - uint8_t getMemTag(const uint16_t addr) { return memtag[addr]; } - - void setMemTag(const uint16_t addr, const uint8_t value) { memtag[addr] = value; } - - void clearMemTag() - { - for (int i=0; i<65536; ++i) memtag[i] = MEMTAG_NONE; - } - - uint8_t getMemTouched(const uint16_t addr) { return memtouched[addr]; } - - void clearMemTouched() - { - for (int i=0; i<65536; ++i) memtouched[i] = MEMTAG_NONE; - } - - void fixMemTouched() - { - for (int i=0; i<65536; ++i) - if ( (memtouched[i]==MEMTAG_INST) || (memtouched[i]==MEMTAG_REPEAT) ) - memtouched[i] = MEMTAG_DATA; - //else if (memtouched[i]==MEMTAG_DATA) - // memtouched[i] = MEMTAG_REPEAT; - } -*/ const bool getOption(const int option) {