- [NEW] La finestra del spectrum mostra en el titol si està stoppada l'execució - [FIX] Durante el debuguech la finestra del spectrum ara s'actualitza
683 lines
24 KiB
C++
683 lines
24 KiB
C++
#include "z80debug.h"
|
|
#include <SDL2/SDL.h>
|
|
#include "z80.h"
|
|
#include "z80dis.h"
|
|
#include "zx_ula.h"
|
|
#include "zx_tape.h"
|
|
#include "ui.h"
|
|
#include "ui_window.h"
|
|
#include "zx_screen.h"
|
|
#include "z80analyze.h"
|
|
|
|
namespace z80debug
|
|
{
|
|
#define midy 58
|
|
namespace history
|
|
{
|
|
uint16_t buffer[65536];
|
|
uint8_t top=0;
|
|
uint8_t pos=0;
|
|
}
|
|
|
|
uint16_t oAF, oBC, oDE, oHL, oAF2, oBC2, oDE2, oHL2, oIX, oIY, oSP, oPC;
|
|
uint8_t oI, oR;
|
|
|
|
bool mem_modified[65536];
|
|
|
|
SDL_Window *win = nullptr;
|
|
SDL_Renderer *ren = nullptr;
|
|
SDL_Texture *tex = nullptr;
|
|
|
|
bool is_debugging=false;
|
|
bool is_paused=false;
|
|
uint16_t mem_viewer_pos = 0;
|
|
char console[256];
|
|
char console_error[256];
|
|
|
|
uint8_t breakpoints[65536];
|
|
|
|
uint16_t cursor = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
bool eventHandler(SDL_Event *e)
|
|
{
|
|
if (z80debug::debugging()) {
|
|
if (e->type==SDL_WINDOWEVENT) {
|
|
if ((e->window.event==SDL_WINDOWEVENT_SHOWN) || (e->window.event==SDL_WINDOWEVENT_EXPOSED)) {
|
|
z80debug::refresh();
|
|
zxscreen::redraw();
|
|
} else if (e->window.event == SDL_WINDOWEVENT_CLOSE) {
|
|
hide();
|
|
zxscreen::focus();
|
|
}
|
|
}
|
|
if (e->type == SDL_MOUSEWHEEL) {
|
|
if (e->wheel.mouseX<midy*CHR_W && e->wheel.mouseY<20*CHR_H) {
|
|
if (e->wheel.y>0) {
|
|
z80debug::cursorback();
|
|
z80debug::refresh();
|
|
} else if (e->wheel.y<0) {
|
|
z80debug::cursorfwd();
|
|
z80debug::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) {
|
|
z80debug::history::gototop();
|
|
z80debug::refresh();
|
|
} else if (e->key.keysym.scancode==SDL_SCANCODE_F2) {
|
|
z80debug::history::goback();
|
|
z80debug::refresh();
|
|
} else if (e->key.keysym.scancode==SDL_SCANCODE_F3) {
|
|
z80debug::history::goforward();
|
|
z80debug::refresh();
|
|
/*} else if (e->key.keysym.scancode==SDL_SCANCODE_F6) {
|
|
z80debug::history::gototop();
|
|
const uint8_t dt = z80::step();
|
|
z80debug::refresh();
|
|
zxscreen::refresh(dt);*/
|
|
} else if (e->key.keysym.scancode==SDL_SCANCODE_UP) {
|
|
z80debug::cursorback();
|
|
z80debug::refresh();
|
|
} else if (e->key.keysym.scancode==SDL_SCANCODE_DOWN) {
|
|
z80debug::cursorfwd();
|
|
z80debug::refresh();
|
|
} else if (e->key.keysym.scancode==SDL_SCANCODE_RETURN) {
|
|
z80debug::executeConsole();
|
|
} else if (e->key.keysym.scancode==SDL_SCANCODE_BACKSPACE) {
|
|
z80debug::DeleteCharConsole();
|
|
}
|
|
}
|
|
if (e->type == SDL_TEXTINPUT) {
|
|
z80debug::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;
|
|
//show();
|
|
}
|
|
|
|
void show()
|
|
{
|
|
if (!win) {
|
|
win = SDL_CreateWindow("Z80 Debugger", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 83*CHR_W, 34*CHR_H, SDL_WINDOW_RESIZABLE);
|
|
ren = SDL_CreateRenderer(win, -1, 0);
|
|
ui::window::registerWindow(SDL_GetWindowID(win), eventHandler);
|
|
tex = ui::createtexture(ren);
|
|
}
|
|
focus();
|
|
}
|
|
|
|
void focus()
|
|
{
|
|
if (win) {
|
|
SDL_RaiseWindow(win);
|
|
z80debug::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[z80::getPC()] &= ~8;
|
|
}
|
|
|
|
void stop()
|
|
{
|
|
zxscreen::setTitle(" (stopped)");
|
|
pause();
|
|
is_debugging = true;
|
|
show();
|
|
/*refresh();*/
|
|
}
|
|
|
|
void cont() {
|
|
zxscreen::setTitle("");
|
|
is_debugging = is_paused = false;
|
|
//hide();
|
|
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--;
|
|
if (z80::getMemTag(pc)!=MEMTAG_CODE && z80::getMemTag(pc)!=MEMTAG_INST) return pc;
|
|
|
|
while (z80::getMemTag(pc)!=MEMTAG_INST) pc--;
|
|
|
|
return pc;
|
|
/*
|
|
pc-=4;
|
|
if (z80dis::getOpcodeSize(pc) == 4) return pc;
|
|
if (z80dis::getOpcodeSize(pc) == 3) return pc+3;
|
|
pc++;
|
|
if (z80dis::getOpcodeSize(pc) == 3) return pc;
|
|
if (z80dis::getOpcodeSize(pc) == 2) return pc+2;
|
|
pc++;
|
|
if (z80dis::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_GRAY, COLOR_WHITE};
|
|
if (z80::getMemTouched(address)!=MEMTAG_INST) colors[3]=COLOR_GRAY;
|
|
if (z80::getMemTouched(address)==MEMTAG_NONE) colors[1]=COLOR_GRAY;
|
|
|
|
if (is_debugging && (address == z80::getPC())) {
|
|
for (int i=0; i<4;++i) colors[i]=COLOR_YELLOW;
|
|
ui::printrect(0,line, midy-2,1, COLOR_BLUE);
|
|
}
|
|
|
|
if (breakpoints[address]&9) ui::printtxt(0,line,"*", colors[0]);
|
|
ui::printtxt(1,line,tohex(address,4), colors[1]);
|
|
|
|
if ( (z80::getMemTag(address)==MEMTAG_INST) || heuristics ) {
|
|
const char *sym = z80dis::getSymbol(address);
|
|
if (sym[0]!=0) ui::printtxt(7,line, sym, COLOR_YELLOW);
|
|
ui::printtxt(19,line, z80dis::getOpcode(address), colors[2]);
|
|
ui::printtxt(31,line, z80dis::getAsm(address), colors[3]);
|
|
} else {
|
|
ui::printtxt(19,line, tohex(z80::getMem()[address],2), COLOR_GRAY);
|
|
ui::printtxt(31,line, "?????????", COLOR_GRAY);
|
|
}
|
|
}
|
|
|
|
void refresh()
|
|
{
|
|
ui::setrenderer(ren, tex);
|
|
SDL_SetRenderDrawColor(ren, 30, 30, 30, 255);
|
|
SDL_RenderClear(ren);
|
|
|
|
// DISSASSEBLY
|
|
// ******************************************
|
|
ui::setoffset(0, 0);
|
|
|
|
ui::box(0,0,midy,20,COLOR_WHITE);
|
|
ui::printrect(2,0, 12,1, COLOR_DARK);
|
|
ui::printtxt(3,0, "ASSEMBLER:", COLOR_WHITE);
|
|
|
|
ui::setoffset(1, 1);
|
|
|
|
uint8_t *memory = z80::getMem();
|
|
|
|
uint16_t pc = cursor; //z80::getPC();
|
|
uint16_t pos = pc;
|
|
|
|
printDissasemblerLine(pc, 8, true);
|
|
|
|
for (int i=9;i<18;++i) {
|
|
pos += z80dis::getOpcodeSize(pos);
|
|
printDissasemblerLine(pos, i, true);
|
|
}
|
|
|
|
pos = pc;
|
|
for (int i=7;i>=0;--i) {
|
|
pos = find_previous_opcode(pos);
|
|
printDissasemblerLine(pos, i);
|
|
}
|
|
|
|
// REGISTERS
|
|
// ******************************************
|
|
|
|
ui::setoffset(0, 0);
|
|
ui::box(midy,0,25,8,COLOR_WHITE);
|
|
ui::printrect(midy+2,0, 12,1, COLOR_DARK);
|
|
ui::printtxt(midy+3,0, "REGISTERS:", COLOR_WHITE);
|
|
|
|
ui::setoffset(midy+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(z80::getAF(), 4), oAF != z80::getAF() ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(11,0, tohex(z80::getAF(true), 4), oAF2 != z80::getAF(true) ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(19,0, tohex(z80::getIX(), 4), oIX != z80::getIX() ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(3,1, tohex(z80::getBC(), 4), oBC != z80::getBC() ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(11,1, tohex(z80::getBC(true), 4), oBC2 != z80::getBC(true) ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(19,1, tohex(z80::getIY(), 4), oIY != z80::getIY() ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(3,2, tohex(z80::getDE(), 4), oDE != z80::getDE() ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(11,2, tohex(z80::getDE(true), 4), oDE2 != z80::getDE(true) ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(19,2, tohex(z80::getSP(), 4), oSP != z80::getSP() ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(3,3, tohex(z80::getHL(), 4), oHL != z80::getHL() ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(11,3, tohex(z80::getHL(true), 4), oHL2 != z80::getHL(true) ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(19,3, tohex(z80::getPC(), 4), oPC != z80::getPC() ? COLOR_RED : COLOR_GRAY);
|
|
|
|
ui::printtxt(16,5, tohex(z80::getI(), 2), oI != z80::getI() ? COLOR_RED : COLOR_GRAY);
|
|
ui::printtxt(21,5, tohex(z80::getR(), 2), oR != z80::getR() ? COLOR_RED : COLOR_GRAY);
|
|
|
|
ui::printtxt(5,4, tohex(memory[z80::getBC()], 2), COLOR_GRAY);
|
|
ui::printtxt(13,4, tohex(memory[z80::getDE()], 2), COLOR_GRAY);
|
|
ui::printtxt(21,4, tohex(memory[z80::getHL()], 2), COLOR_GRAY);
|
|
|
|
const uint8_t flags = (z80::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(midy,8,11,12,COLOR_WHITE);
|
|
ui::printrect(midy+2,8, 8,1, COLOR_DARK);
|
|
ui::printtxt(midy+3,8, "STACK:", COLOR_WHITE);
|
|
ui::setoffset(midy+1, 9);
|
|
uint16_t sp = z80::getSP()-8;
|
|
for (int i=0; i<10; ++i) {
|
|
uint8_t c1=COLOR_CYAN, c2=COLOR_GRAY;
|
|
if (sp == z80::getSP()) {
|
|
ui::printrect(0,i,9,1,COLOR_BLUE);
|
|
c1 = c2 = COLOR_YELLOW;
|
|
}
|
|
ui::printtxt(0,i, tohex(sp, 4), c1);
|
|
ui::printtxt(5,i, tohex(*((uint16_t*)&memory[sp]),4), c2);
|
|
sp+=2;
|
|
}
|
|
|
|
|
|
// BREAKPOINTS
|
|
// ******************************************
|
|
|
|
ui::setoffset(0, 0);
|
|
ui::box(midy+11,8,14,12,COLOR_WHITE);
|
|
ui::printrect(midy+13,8, 9,1, COLOR_DARK);
|
|
ui::printtxt(midy+14,8, "BREAKS:", COLOR_WHITE);
|
|
ui::setoffset(midy+12, 9);
|
|
|
|
int line=0;
|
|
for (int i=0; i<65536; ++i) {
|
|
if (breakpoints[i]&7) {
|
|
ui::printtxt(2,line, tohex(i,4), COLOR_WHITE);
|
|
ui::printtxt(7,line, breakpoints[i]&1?"x":"-", COLOR_GRAY);
|
|
ui::printtxt(8,line, breakpoints[i]&2?"r":"-", COLOR_GRAY);
|
|
ui::printtxt(9,line, breakpoints[i]&4?"w":"-", COLOR_GRAY);
|
|
line++;
|
|
if (line>9) break;
|
|
}
|
|
}
|
|
|
|
|
|
// MEMORY
|
|
// ******************************************
|
|
|
|
ui::setoffset(0, 0);
|
|
ui::box(0,20,83,8,COLOR_WHITE);
|
|
ui::printrect(2,20, 9,1, COLOR_DARK);
|
|
ui::printtxt(3,20, "MEMORY:", COLOR_WHITE);
|
|
|
|
ui::setoffset(1, 21);
|
|
|
|
uint16_t mem_viewer_cursor = mem_viewer_pos;
|
|
for (int i=0; i<6; ++i) {
|
|
ui::printtxt(1,i, tohex(mem_viewer_cursor, 4), COLOR_CYAN);
|
|
for (int j=0; j<16; ++j) {
|
|
ui::printtxt(6+j*3, i, tohex(memory[mem_viewer_cursor],2), mem_modified[mem_viewer_cursor] ? COLOR_RED : COLOR_WHITE);
|
|
ui::printchar(54+j, i, memory[mem_viewer_cursor], mem_modified[mem_viewer_cursor] ? COLOR_BROWN : COLOR_GRAY);
|
|
mem_viewer_cursor++;
|
|
}
|
|
//printtxt(5,0, "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", COLOR_WHITE);
|
|
//printtxt(53,0, "0123456789AB\tDEF", COLOR_GRAY);
|
|
}
|
|
|
|
|
|
// CONSOLE
|
|
// ******************************************
|
|
|
|
ui::setoffset(0, 0);
|
|
ui::box(0,28,83,6,COLOR_WHITE);
|
|
ui::printrect(2,28, 10,1, COLOR_DARK);
|
|
ui::printtxt(3,28, "CONSOLE:", COLOR_WHITE);
|
|
|
|
ui::setoffset(1, 29);
|
|
ui::printtxt(0,0, ">", COLOR_WHITE);
|
|
ui::printtxt(1,0, console, COLOR_WHITE);
|
|
ui::printtxt(strlen(console)+1,0, "\x7F", COLOR_WHITE);
|
|
ui::printtxt(1,1, console_error, COLOR_RED);
|
|
|
|
if (!is_debugging) {
|
|
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
|
|
SDL_SetRenderDrawColor(ren, 0, 0, 0, 128);
|
|
SDL_Rect rect {0,0,83*CHR_W, 34*CHR_H};
|
|
SDL_GetWindowSize(win, &rect.w, &rect.h);
|
|
SDL_RenderFillRect(ren, &rect);
|
|
}
|
|
|
|
SDL_RenderPresent(ren);
|
|
|
|
for (int i=0; i<65536; ++i) mem_modified[i] = false;
|
|
|
|
oAF = z80::getAF(); oBC = z80::getBC(); oDE = z80::getDE(); oHL = z80::getHL();
|
|
oAF2 = z80::getAF(true); oBC2 = z80::getBC(true); oDE2 = z80::getDE(true); oHL2 = z80::getHL(true);
|
|
oIX = z80::getIX(); oIY = z80::getIY(); oSP = z80::getSP(); oPC = z80::getPC();
|
|
oI = z80::getI(); oR = z80::getR();
|
|
}
|
|
|
|
void sendToConsole(const char* text)
|
|
{
|
|
if (strlen(console)+strlen(text)<256) strcat(console, text);
|
|
refresh();
|
|
}
|
|
|
|
void DeleteCharConsole()
|
|
{
|
|
const int len = strlen(console);
|
|
console[len-1] = 0;
|
|
refresh();
|
|
}
|
|
|
|
void executeConsole()
|
|
{
|
|
processCommand();
|
|
console[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()
|
|
{
|
|
console_error[0]=0;
|
|
char cmd[256];
|
|
int i=0;
|
|
char *console_ptr = console;
|
|
|
|
getcmd();
|
|
|
|
if (strcmp(cmd, "s")==0 || strcmp(cmd, "step")==0) {
|
|
z80::step();
|
|
} else if (strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) {
|
|
z80::step();
|
|
z80debug::cont();
|
|
} else if (strcmp(cmd, "r")==0 || strcmp(cmd, "reset")==0) {
|
|
uint8_t *mem = z80::getMem();
|
|
for (int i=0x4000; i<=0xffff; ++i) mem[i]=0;
|
|
z80::reset(mem);
|
|
z80::connect_port(0xfe, zx_ula::port_in, zx_ula::port_out);
|
|
//for (int i=0; i<65536; ++i) breakpoints[i]=0;
|
|
z80debug::refresh();
|
|
} else if (strcmp(cmd, "b")==0 || strcmp(cmd, "break")==0) {
|
|
getcmd();
|
|
if (cmd[0] == 0) { breakpoints[z80::getPC()]=1; return; }
|
|
int address = getnum(cmd);
|
|
if (address<0 || address>65536) { strcpy(console_error, "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 {
|
|
strcpy(console_error, "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[z80::getPC()]=0; return; }
|
|
int address = getnum(cmd);
|
|
if (address<0 || address>65536) { strcpy(console_error, "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 {
|
|
strcpy(console_error, "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) { strcpy(console_error, "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);
|
|
//getcmd();
|
|
//char address[256];
|
|
//strcpy(address, cmd);
|
|
//loadngo(filename, address);
|
|
loadstate(filename);
|
|
} 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);
|
|
uint8_t *mem = z80::getMem();
|
|
mem[address] = value;
|
|
} else if (strcmp(cmd, "peek")==0) {
|
|
getcmd();
|
|
int address = getnum(cmd);
|
|
uint8_t *mem = z80::getMem();
|
|
int value = mem[address];
|
|
SDL_itoa(value, console_error, 10);
|
|
} else if (strcmp(cmd, "reg")==0) {
|
|
getcmd();
|
|
if (strcmp(cmd, "f")==0) { getcmd(); int value = getnum(cmd); z80::getRegs()[0] = value; }
|
|
else if (strcmp(cmd, "a")==0) { getcmd(); int value = getnum(cmd); z80::getRegs()[1] = value; }
|
|
else if (strcmp(cmd, "c")==0) { getcmd(); int value = getnum(cmd); z80::getRegs()[2] = value; }
|
|
else if (strcmp(cmd, "b")==0) { getcmd(); int value = getnum(cmd); z80::getRegs()[3] = value; }
|
|
else if (strcmp(cmd, "e")==0) { getcmd(); int value = getnum(cmd); z80::getRegs()[4] = value; }
|
|
else if (strcmp(cmd, "d")==0) { getcmd(); int value = getnum(cmd); z80::getRegs()[5] = value; }
|
|
else if (strcmp(cmd, "l")==0) { getcmd(); int value = getnum(cmd); z80::getRegs()[6] = value; }
|
|
else if (strcmp(cmd, "h")==0) { getcmd(); int value = getnum(cmd); z80::getRegs()[7] = value; }
|
|
else { strcpy(console_error, "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) { strcpy(console_error, "Illegal address"); return; }
|
|
if (z80::getMemTag(address)!=MEMTAG_INST) address = find_previous_opcode(address);
|
|
z80debug::setcursor(address);
|
|
}
|
|
}
|
|
|
|
const bool isbreak(const uint16_t address, const uint8_t type)
|
|
{
|
|
return (breakpoints[address]&type);
|
|
}
|
|
|
|
uint32_t next()
|
|
{
|
|
breakpoints[z80::getPC()+z80dis::getOpcodeSize(z80::getPC())] |= 8;
|
|
const uint32_t t = z80::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) { strcpy(console_error, "Illegal offset"); return; }
|
|
|
|
FILE *f = fopen(filename, "rb");
|
|
fseek(f, 0, SEEK_END);
|
|
int size = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
uint8_t *memory = z80::getMem();
|
|
fread(memory+address, size, 1, f);
|
|
fclose(f);
|
|
z80::setPC(address);
|
|
is_debugging = is_paused = false;
|
|
}
|
|
|
|
void savestate(const char *filename)
|
|
{
|
|
uint8_t *regs = z80::getRegs();
|
|
uint8_t *memory = z80::getMem();
|
|
FILE *f = fopen(filename, "wb");
|
|
fwrite(regs, 31, 1, f);
|
|
fwrite(&memory[0x4000], 0xc000, 1, f);
|
|
fclose(f);
|
|
}
|
|
|
|
void loadstate(const char *filename)
|
|
{
|
|
uint8_t *regs = z80::getRegs();
|
|
uint8_t *memory = z80::getMem();
|
|
FILE *f = fopen(filename, "rb");
|
|
fread(regs, 31, 1, f);
|
|
fread(&memory[0x4000], 0xc000, 1, f);
|
|
fclose(f);
|
|
}
|
|
|
|
void setcursor(const uint16_t address)
|
|
{
|
|
cursor = address;
|
|
}
|
|
|
|
void cursorfwd()
|
|
{
|
|
cursor += z80dis::getOpcodeSize(cursor);
|
|
}
|
|
|
|
void cursorback()
|
|
{
|
|
cursor = find_previous_opcode(cursor);
|
|
}
|
|
|
|
|
|
namespace history
|
|
{
|
|
void store()
|
|
{
|
|
buffer[++top] = z80::getPC();
|
|
pos=top;
|
|
}
|
|
|
|
void gototop()
|
|
{
|
|
pos = top;
|
|
z80::setPC(buffer[pos]);
|
|
cursor = z80::getPC();
|
|
}
|
|
|
|
void goforward()
|
|
{
|
|
if (pos == top) return;
|
|
z80::setPC(buffer[++pos]);
|
|
cursor = z80::getPC();
|
|
}
|
|
|
|
void goback()
|
|
{
|
|
if (uint8_t(pos-1) == top) return;
|
|
z80::setPC(buffer[--pos]);
|
|
cursor = z80::getPC();
|
|
}
|
|
|
|
}
|
|
|
|
} |