- [NEW] While debugging you can go back/forward in time

- [NEW] Step by step execution with F6
- [NEW] Memory is tagged as code or data while executing, so later it can be properly disassembled
- [NEW] "reg X value" to set the value of X register
- [FIX] IX opcode table had errors
- [FIX] opcodes with two parameters where printed incorrectly on the disassembler
- [FIX] opcodes can't be lager than 4 bytes
- [CHG] Berserk mode and fernando martin TAP by default, to help with debugging
This commit is contained in:
2024-12-05 17:28:10 +01:00
parent cce38449a5
commit c0f9fa9933
7 changed files with 129 additions and 17 deletions

View File

@@ -82,7 +82,7 @@ int main(int argc, char *argv[])
zx_ula::sound_init(); zx_ula::sound_init();
zx_tape::load("alien8.tap"); zx_tape::load("fernandomartin.tap");
if (argc==3) { z80debug::loadngo(argv[1], argv[2]); } if (argc==3) { z80debug::loadngo(argv[1], argv[2]); }
@@ -119,10 +119,25 @@ int main(int argc, char *argv[])
const uint8_t dt = z80debug::next(); const uint8_t dt = z80debug::next();
zxscreen::refresh(dt); zxscreen::refresh(dt);
zxscreen::redraw(); zxscreen::redraw();
} 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_F5) { } else if (e.key.keysym.scancode==SDL_SCANCODE_F5) {
z80debug::history::gototop();
const uint8_t dt = z80::step(); const uint8_t dt = z80::step();
z80debug::cont(); z80debug::cont();
zxscreen::refresh(dt); zxscreen::refresh(dt);
} 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_RETURN) { } else if (e.key.keysym.scancode==SDL_SCANCODE_RETURN) {
z80debug::executeConsole(); z80debug::executeConsole();
} else if (e.key.keysym.scancode==SDL_SCANCODE_BACKSPACE) { } else if (e.key.keysym.scancode==SDL_SCANCODE_BACKSPACE) {

15
z80.cpp
View File

@@ -6,6 +6,7 @@
namespace z80 namespace z80
{ {
static uint8_t *memory = nullptr; static uint8_t *memory = nullptr;
static uint8_t memtag[65536];
static uint32_t t = 0; static uint32_t t = 0;
static uint16_t current_opcode_address = 0; static uint16_t current_opcode_address = 0;
@@ -145,12 +146,15 @@ namespace z80
{ {
if (z80debug::isbreak(addr, 2)) z80debug::stop(); if (z80debug::isbreak(addr, 2)) z80debug::stop();
t+=3; t+=3;
memtag[addr] = MEMTAG_DATA;
return memory[addr]; return memory[addr];
} }
uint8_t READ_MEM_8() uint8_t READ_MEM_8()
{ {
return READ_MEM_8(rPC++); uint8_t data = READ_MEM_8(rPC);
memtag[rPC++] = MEMTAG_CODE;
return data;
} }
uint8_t READ_M1() uint8_t READ_M1()
@@ -178,6 +182,8 @@ namespace z80
if (z80debug::isbreak(addr, 4)) z80debug::stop(); if (z80debug::isbreak(addr, 4)) z80debug::stop();
//if (z80debug::debugging()) //if (z80debug::debugging())
z80debug::setmemmodified(addr); z80debug::setmemmodified(addr);
memtag[addr] = MEMTAG_DATA;
return value; return value;
} }
@@ -1033,6 +1039,7 @@ namespace z80
void reset(uint8_t* mem) void reset(uint8_t* mem)
{ {
memory = mem; memory = mem;
for (int i=0; i<65536; ++i) memtag[i] = MEMTAG_NONE;
rPC = iff1 = iff2 = im = 0; rPC = iff1 = iff2 = im = 0;
rAF = rAF2 = rBC = rBC2 = rDE = rDE2 = rHL = rHL2 = rIX = rIY = rSP = 0xffff; rAF = rAF2 = rBC = rBC2 = rDE = rDE2 = rHL = rHL2 = rIX = rIY = rSP = 0xffff;
t = 0; t = 0;
@@ -1061,6 +1068,7 @@ namespace z80
current_opcode_address = rPC; current_opcode_address = rPC;
t = 0; t = 0;
const uint8_t opcode = READ_M1(); const uint8_t opcode = READ_M1();
memtag[current_opcode_address] = MEMTAG_INST;
uint16_t tmp; uint16_t tmp;
switch (opcode) switch (opcode)
@@ -1340,6 +1348,8 @@ namespace z80
if (pending_ei==2) { pending_ei=0; actualEI(); } if (pending_ei==2) { pending_ei=0; actualEI(); }
if (pending_ei==1) pending_ei=2; if (pending_ei==1) pending_ei=2;
z80debug::history::store();
return t; return t;
} }
@@ -2720,4 +2730,7 @@ namespace z80
uint16_t getPC() { return rPC; } uint16_t getPC() { return rPC; }
void setPC(const uint16_t addr) { rPC = addr; } void setPC(const uint16_t addr) { rPC = addr; }
uint8_t getMemTag(const uint16_t addr) { return memtag[addr]; };
} }

6
z80.h
View File

@@ -4,6 +4,11 @@
namespace z80 namespace z80
{ {
#define MEMTAG_NONE 0
#define MEMTAG_INST 1
#define MEMTAG_CODE 2
#define MEMTAG_DATA 3
void reset(uint8_t* mem); void reset(uint8_t* mem);
void connect_port(int num, int (*in_ptr)(int), void (*out_ptr)(int,int)); void connect_port(int num, int (*in_ptr)(int), void (*out_ptr)(int,int));
void interrupt(); void interrupt();
@@ -24,4 +29,5 @@ namespace z80
uint16_t getPC(); uint16_t getPC();
void setPC(const uint16_t addr); void setPC(const uint16_t addr);
uint8_t getMemTag(const uint16_t addr);
} }

View File

@@ -7,6 +7,13 @@
#include "ui.h" #include "ui.h"
namespace z80debug namespace z80debug
{ {
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; uint16_t oAF, oBC, oDE, oHL, oAF2, oBC2, oDE2, oHL2, oIX, oIY, oSP, oPC;
bool mem_modified[65536]; bool mem_modified[65536];
@@ -84,17 +91,24 @@ namespace z80debug
uint16_t find_previous_opcode(uint16_t pc) uint16_t find_previous_opcode(uint16_t pc)
{ {
pc-=4; pc--;
if (z80dis::getOpcodeSize(pc) != 4) { if (z80::getMemTag(pc)!=MEMTAG_CODE && z80::getMemTag(pc)!=MEMTAG_INST) return pc;
pc++;
if (z80dis::getOpcodeSize(pc) != 3) { while (z80::getMemTag(pc)!=MEMTAG_INST) pc--;
pc++;
if (z80dis::getOpcodeSize(pc) != 2) {
pc++;
}
}
}
return 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 refresh() void refresh()
@@ -144,8 +158,13 @@ namespace z80debug
pos = find_previous_opcode(pos); pos = find_previous_opcode(pos);
if (breakpoints[pos]&9) ui::printtxt(0,i,"*", COLOR_RED); if (breakpoints[pos]&9) ui::printtxt(0,i,"*", COLOR_RED);
ui::printtxt(1,i,tohex(pos,4), COLOR_CYAN); ui::printtxt(1,i,tohex(pos,4), COLOR_CYAN);
ui::printtxt(7,i, z80dis::getOpcode(pos), COLOR_GRAY); if (z80::getMemTag(pos)==MEMTAG_INST) {
ui::printtxt(19,i, z80dis::getAsm(pos), COLOR_WHITE); ui::printtxt(7,i, z80dis::getOpcode(pos), COLOR_GRAY);
ui::printtxt(19,i, z80dis::getAsm(pos), COLOR_WHITE);
} else {
ui::printtxt(7,i, tohex(z80::getMem()[pos],2), COLOR_GRAY);
ui::printtxt(19,i, "?????????", COLOR_GRAY);
}
} }
//for (int i=0;i<20;++i) printtxt(1,i,tohex(pc,4), COLOR_CYAN); //for (int i=0;i<20;++i) printtxt(1,i,tohex(pc,4), COLOR_CYAN);
@@ -420,6 +439,17 @@ namespace z80debug
uint8_t *mem = z80::getMem(); uint8_t *mem = z80::getMem();
int value = mem[address]; int value = mem[address];
SDL_itoa(value, console_error, 10); 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; }
} }
} }
@@ -476,4 +506,33 @@ namespace z80debug
fread(&memory[16*1024], 48*1024, 1, f); fread(&memory[16*1024], 48*1024, 1, f);
fclose(f); fclose(f);
} }
namespace history
{
void store()
{
buffer[++top] = z80::getPC();
pos=top;
}
void gototop()
{
pos = top;
z80::setPC(buffer[pos]);
}
void goforward()
{
if (pos == top) return;
z80::setPC(buffer[++pos]);
}
void goback()
{
if (uint8_t(pos-1) == top) return;
z80::setPC(buffer[--pos]);
}
}
} }

View File

@@ -24,5 +24,14 @@ namespace z80debug
void savestate(const char *filename); void savestate(const char *filename);
void loadstate(const char *filename); void loadstate(const char *filename);
void loadngo(const char* filename, const char* addr); void loadngo(const char* filename, const char* addr);
namespace history
{
void store();
void gototop();
void goforward();
void goback();
}
} }

File diff suppressed because one or more lines are too long

View File

@@ -34,7 +34,7 @@ namespace zx_tape
bool playing = false; bool playing = false;
bool loaded = false; bool loaded = false;
bool berserk_mode = false; bool berserk_mode = true;
std::vector<block_t> blocks; std::vector<block_t> blocks;
uint8_t current_block = 0; uint8_t current_block = 0;