mirror of https://github.com/bsnes-emu/bsnes.git
Update to v070r07 release.
byuu says: I'm happy enough with the debugger now. Not 100% up to par with the old one, but it also does some new things the old one didn't. - step into / step over are disabled unless they can be done safely - this means step over is usually grayed unless you hit step into first, due to bsnes not being opcode-based (you can't skip an opcode that is half-executed) - you can now trace console output to disk - stepping the CPU will print stepped SMP opcodes if the checkbox for it is on and vice versa - button added to clear the console log
This commit is contained in:
parent
7e8958b102
commit
26643a43de
|
@ -7,14 +7,16 @@ void CPUDebugger::op_step() {
|
|||
usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0);
|
||||
opcode_pc = regs.pc;
|
||||
|
||||
opcode_edge = true;
|
||||
if(debugger.step_cpu) {
|
||||
debugger.break_event = Debugger::BreakEvent::CPUStep;
|
||||
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
|
||||
} else {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
|
||||
}
|
||||
|
||||
if(step_event) step_event();
|
||||
opcode_edge = false;
|
||||
|
||||
CPU::op_step();
|
||||
synchronize_smp();
|
||||
}
|
||||
|
@ -36,6 +38,7 @@ void CPUDebugger::op_write(uint32 addr, uint8 data) {
|
|||
CPUDebugger::CPUDebugger() {
|
||||
usage = new uint8[1 << 24]();
|
||||
opcode_pc = 0x8000;
|
||||
opcode_edge = false;
|
||||
}
|
||||
|
||||
CPUDebugger::~CPUDebugger() {
|
||||
|
|
|
@ -12,7 +12,8 @@ public:
|
|||
UsageFlagX = 0x01,
|
||||
};
|
||||
uint8 *usage;
|
||||
uint32 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
|
||||
uint32 opcode_pc;
|
||||
bool opcode_edge;
|
||||
|
||||
void op_step();
|
||||
uint8 op_read(uint32 addr);
|
||||
|
|
|
@ -7,14 +7,16 @@ void CPUDebugger::op_step() {
|
|||
usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0);
|
||||
opcode_pc = regs.pc;
|
||||
|
||||
opcode_edge = true;
|
||||
if(debugger.step_cpu) {
|
||||
debugger.break_event = Debugger::BreakEvent::CPUStep;
|
||||
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
|
||||
} else {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
|
||||
}
|
||||
|
||||
if(step_event) step_event();
|
||||
opcode_edge = false;
|
||||
|
||||
CPU::op_step();
|
||||
synchronize_smp();
|
||||
}
|
||||
|
@ -36,6 +38,7 @@ void CPUDebugger::op_write(uint32 addr, uint8 data) {
|
|||
CPUDebugger::CPUDebugger() {
|
||||
usage = new uint8[1 << 24]();
|
||||
opcode_pc = 0x8000;
|
||||
opcode_edge = false;
|
||||
}
|
||||
|
||||
CPUDebugger::~CPUDebugger() {
|
||||
|
|
|
@ -12,7 +12,8 @@ public:
|
|||
UsageFlagX = 0x01,
|
||||
};
|
||||
uint8 *usage;
|
||||
uint32 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
|
||||
uint24 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
|
||||
bool opcode_edge; //true right before an opcode execues, used to skip over opcodes
|
||||
|
||||
void op_step();
|
||||
uint8 op_read(uint32 addr);
|
||||
|
|
|
@ -6,14 +6,16 @@ void SMPDebugger::op_step() {
|
|||
usage[regs.pc] |= UsageExec;
|
||||
opcode_pc = regs.pc;
|
||||
|
||||
opcode_edge = true;
|
||||
if(debugger.step_smp) {
|
||||
debugger.break_event = Debugger::BreakEvent::SMPStep;
|
||||
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
|
||||
} else {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
|
||||
}
|
||||
|
||||
if(step_event) step_event();
|
||||
opcode_edge = false;
|
||||
|
||||
SMP::op_step();
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
@ -35,6 +37,7 @@ void SMPDebugger::op_write(uint16 addr, uint8 data) {
|
|||
SMPDebugger::SMPDebugger() {
|
||||
usage = new uint8[1 << 16]();
|
||||
opcode_pc = 0xffc0;
|
||||
opcode_edge = false;
|
||||
}
|
||||
|
||||
SMPDebugger::~SMPDebugger() {
|
||||
|
|
|
@ -11,6 +11,7 @@ public:
|
|||
};
|
||||
uint8 *usage;
|
||||
uint16 opcode_pc;
|
||||
bool opcode_edge;
|
||||
|
||||
void op_step();
|
||||
uint8 op_read(uint16 addr);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "072.06";
|
||||
static const char Version[] = "072.07";
|
||||
static const unsigned SerializerVersion = 14;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,28 +11,54 @@ void Console::create() {
|
|||
|
||||
traceToConsole.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace to console"); y += Style::CheckBoxHeight;
|
||||
traceToConsole.setChecked(true);
|
||||
traceToDisk.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace to disk"); y += Style::CheckBoxHeight;
|
||||
traceToDisk.setEnabled(false);
|
||||
traceToFile.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace to file"); y += Style::CheckBoxHeight;
|
||||
traceCPU.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace S-CPU"); y += Style::CheckBoxHeight;
|
||||
traceCPU.setChecked(true);
|
||||
traceSMP.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace S-SMP"); y += Style::CheckBoxHeight;
|
||||
|
||||
setGeometry(0, 0, 775, 338);
|
||||
clearConsole.create(*this, x, 338 - Style::ButtonHeight - 5, 120, Style::ButtonHeight, "Clear console");
|
||||
|
||||
setGeometry(0, 0, 710, 338);
|
||||
|
||||
onClose = []() {
|
||||
debugger.showConsole.setChecked(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
traceToFile.onTick = []() { console.tracerEnable(console.traceToFile.checked()); };
|
||||
|
||||
clearConsole.onTick = []() {
|
||||
console.buffer = "";
|
||||
console.output.setText(console.buffer);
|
||||
};
|
||||
}
|
||||
|
||||
void Console::write(const string &text) {
|
||||
if(traceToConsole.checked()) {
|
||||
if(buffer != "") buffer.append("\n");
|
||||
buffer.append(text);
|
||||
output.setText(buffer);
|
||||
output.setCursorPosition(~0);
|
||||
}
|
||||
if(traceToFile.checked() && logfile.open()) {
|
||||
logfile.print(string(text, "\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void Console::tracerEnable(bool state) {
|
||||
if(state == true) {
|
||||
string filename = { cartridge.baseName, ".log" };
|
||||
logfile.open(filename, file::mode::write);
|
||||
} else {
|
||||
logfile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void Console::eventBreakpoint() {
|
||||
if(traceToConsole.checked() == false) return;
|
||||
|
||||
unsigned n = SNES::debugger.breakpoint_hit;
|
||||
string text = { "Breakpoint ", n + 1, " hit." };
|
||||
buffer.append(string(buffer == "" ? "" : "\n", text));
|
||||
output.setText(buffer);
|
||||
output.setCursorPosition(~0);
|
||||
write({ "Breakpoint ", n + 1, " hit." });
|
||||
|
||||
if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::Source::CPUBus) {
|
||||
eventTraceCPU();
|
||||
|
@ -43,22 +69,16 @@ void Console::eventBreakpoint() {
|
|||
|
||||
void Console::eventTraceCPU() {
|
||||
if(traceCPU.checked() == false) return;
|
||||
if(traceToConsole.checked() == false) return;
|
||||
|
||||
char text[256];
|
||||
SNES::cpu.disassemble_opcode(text, SNES::cpu.regs.pc);
|
||||
buffer.append(string(buffer == "" ? "" : "\n", text));
|
||||
output.setText(buffer);
|
||||
output.setCursorPosition(~0);
|
||||
write(text);
|
||||
}
|
||||
|
||||
void Console::eventTraceSMP() {
|
||||
if(traceSMP.checked() == false) return;
|
||||
if(traceToConsole.checked() == false) return;
|
||||
|
||||
char text[256];
|
||||
SNES::smp.disassemble_opcode(text, SNES::smp.regs.pc);
|
||||
buffer.append(string(buffer == "" ? "" : "\n", text));
|
||||
output.setText(buffer);
|
||||
output.setCursorPosition(~0);
|
||||
write(text);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
struct Console : TopLevelWindow {
|
||||
EditBox output;
|
||||
CheckBox traceToConsole;
|
||||
CheckBox traceToDisk;
|
||||
CheckBox traceToFile;
|
||||
CheckBox traceCPU;
|
||||
CheckBox traceSMP;
|
||||
Button clearConsole;
|
||||
|
||||
string buffer;
|
||||
file logfile;
|
||||
|
||||
void create();
|
||||
void write(const string &text);
|
||||
void tracerEnable(bool state);
|
||||
void eventBreakpoint();
|
||||
void eventTraceCPU();
|
||||
void eventTraceSMP();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
CPUdebugger cpuDebugger;
|
||||
CPUDebugger cpuDebugger;
|
||||
|
||||
void CPUdebugger::create() {
|
||||
void CPUDebugger::create() {
|
||||
Window::create(0, 0, 256, 256, "CPU Debugger");
|
||||
application.addWindow(this, "Debugger.CPUdebugger", "192,192");
|
||||
|
||||
|
@ -22,14 +22,18 @@ void CPUdebugger::create() {
|
|||
};
|
||||
|
||||
stepInto.onTick = []() {
|
||||
SNES::debugger.step_cpu = true;
|
||||
debugger.debugMode = Debugger::DebugMode::StepIntoCPU;
|
||||
};
|
||||
|
||||
stepOver.onTick = { &CPUdebugger::eventStepOver, this };
|
||||
stepOver.onTick = { &CPUDebugger::eventStepOver, this };
|
||||
}
|
||||
|
||||
void CPUdebugger::refreshDisassembly() {
|
||||
void CPUDebugger::synchronize() {
|
||||
stepInto.setEnabled(SNES::cartridge.loaded() && debugger.enableDebugger.checked());
|
||||
stepOver.setEnabled(stepInto.enabled() && SNES::cpu.opcode_edge);
|
||||
}
|
||||
|
||||
void CPUDebugger::refreshDisassembly() {
|
||||
unsigned addr = SNES::cpu.regs.pc;
|
||||
uint8_t *usage = SNES::cpu.usage;
|
||||
|
||||
|
@ -86,18 +90,18 @@ void CPUdebugger::refreshDisassembly() {
|
|||
output.setText(buffer);
|
||||
}
|
||||
|
||||
void CPUdebugger::eventStepInto() {
|
||||
SNES::debugger.step_cpu = false;
|
||||
void CPUDebugger::eventStepInto() {
|
||||
refreshDisassembly();
|
||||
}
|
||||
|
||||
void CPUdebugger::eventStepOver() {
|
||||
void CPUDebugger::eventStepOver() {
|
||||
uint8_t opcode = read(SNES::cpu.regs.pc);
|
||||
unsigned length = SNESCPU::getOpcodeLength(SNES::cpu.regs.p.m, SNES::cpu.regs.p.x, opcode);
|
||||
SNES::cpu.regs.pc += length;
|
||||
refreshDisassembly();
|
||||
console.eventTraceCPU();
|
||||
}
|
||||
|
||||
uint8_t CPUdebugger::read(unsigned addr) {
|
||||
uint8_t CPUDebugger::read(unsigned addr) {
|
||||
return SNES::debugger.read(SNES::Debugger::MemorySource::CPUBus, addr);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
struct CPUdebugger : TopLevelWindow {
|
||||
struct CPUDebugger : TopLevelWindow {
|
||||
EditBox output;
|
||||
Button stepInto;
|
||||
Button stepOver;
|
||||
Button proceed;
|
||||
|
||||
void create();
|
||||
void synchronize();
|
||||
void refreshDisassembly();
|
||||
void eventStepInto();
|
||||
void eventStepOver();
|
||||
|
@ -12,4 +13,4 @@ struct CPUdebugger : TopLevelWindow {
|
|||
uint8_t read(unsigned addr);
|
||||
};
|
||||
|
||||
extern CPUdebugger cpuDebugger;
|
||||
extern CPUDebugger cpuDebugger;
|
||||
|
|
|
@ -65,6 +65,13 @@ void Debugger::create() {
|
|||
debugger.enable(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
synchronize();
|
||||
}
|
||||
|
||||
void Debugger::synchronize() {
|
||||
cpuDebugger.synchronize();
|
||||
smpDebugger.synchronize();
|
||||
}
|
||||
|
||||
void Debugger::setVisible(bool visible) {
|
||||
|
@ -78,9 +85,13 @@ void Debugger::setVisible(bool visible) {
|
|||
|
||||
void Debugger::enable(bool state) {
|
||||
enableDebugger.setChecked(state);
|
||||
SNES::debugger.step_cpu = state;
|
||||
SNES::debugger.step_smp = state;
|
||||
}
|
||||
|
||||
void Debugger::run() {
|
||||
synchronize();
|
||||
|
||||
if(enableDebugger.checked() == false) {
|
||||
SNES::system.run();
|
||||
return;
|
||||
|
@ -101,20 +112,20 @@ void Debugger::run() {
|
|||
}
|
||||
}
|
||||
|
||||
if(debugMode == DebugMode::StepIntoCPU) {
|
||||
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::CPUStep) {
|
||||
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::CPUStep) {
|
||||
if(debugMode == DebugMode::StepIntoCPU) {
|
||||
debugMode = DebugMode::None;
|
||||
console.eventTraceCPU();
|
||||
cpuDebugger.eventStepInto();
|
||||
}
|
||||
console.eventTraceCPU();
|
||||
}
|
||||
|
||||
if(debugMode == DebugMode::StepIntoSMP) {
|
||||
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::SMPStep) {
|
||||
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::SMPStep) {
|
||||
if(debugMode == DebugMode::StepIntoSMP) {
|
||||
debugMode = DebugMode::None;
|
||||
console.eventTraceSMP();
|
||||
smpDebugger.eventStepInto();
|
||||
}
|
||||
console.eventTraceSMP();
|
||||
}
|
||||
|
||||
SNES::debugger.break_event = SNES::Debugger::BreakEvent::None;
|
||||
|
|
|
@ -20,6 +20,7 @@ struct Debugger : TopLevelWindow {
|
|||
CheckBox showMemoryEditor;
|
||||
|
||||
void create();
|
||||
void synchronize();
|
||||
void setVisible(bool visible = true);
|
||||
void enable(bool state);
|
||||
void run();
|
||||
|
|
|
@ -22,13 +22,17 @@ void SMPDebugger::create() {
|
|||
};
|
||||
|
||||
stepInto.onTick = []() {
|
||||
SNES::debugger.step_smp = true;
|
||||
debugger.debugMode = Debugger::DebugMode::StepIntoSMP;
|
||||
};
|
||||
|
||||
stepOver.onTick = { &SMPDebugger::eventStepOver, this };
|
||||
}
|
||||
|
||||
void SMPDebugger::synchronize() {
|
||||
stepInto.setEnabled(SNES::cartridge.loaded() && debugger.enableDebugger.checked());
|
||||
stepOver.setEnabled(stepInto.enabled() && SNES::smp.opcode_edge);
|
||||
}
|
||||
|
||||
void SMPDebugger::refreshDisassembly() {
|
||||
uint16_t addr = SNES::smp.regs.pc;
|
||||
uint8_t *usage = SNES::smp.usage;
|
||||
|
@ -86,7 +90,6 @@ void SMPDebugger::refreshDisassembly() {
|
|||
}
|
||||
|
||||
void SMPDebugger::eventStepInto() {
|
||||
SNES::debugger.step_smp = false;
|
||||
refreshDisassembly();
|
||||
}
|
||||
|
||||
|
@ -95,6 +98,7 @@ void SMPDebugger::eventStepOver() {
|
|||
unsigned length = SNESSMP::getOpcodeLength(opcode);
|
||||
SNES::smp.regs.pc += length;
|
||||
refreshDisassembly();
|
||||
console.eventTraceSMP();
|
||||
}
|
||||
|
||||
uint8_t SMPDebugger::read(uint16_t addr) {
|
||||
|
|
|
@ -5,6 +5,7 @@ struct SMPDebugger : TopLevelWindow {
|
|||
Button proceed;
|
||||
|
||||
void create();
|
||||
void synchronize();
|
||||
void refreshDisassembly();
|
||||
void eventStepInto();
|
||||
void eventStepOver();
|
||||
|
|
|
@ -6,7 +6,7 @@ void BreakpointEditor::create() {
|
|||
|
||||
unsigned x = 5, y = 5;
|
||||
|
||||
runToBreakpoint.create(*this, x, y, 295, Style::CheckBoxHeight, "Run To Breakpoint");
|
||||
runToBreakpoint.create(*this, x, y, 295, Style::CheckBoxHeight, "Run to breakpoint");
|
||||
y += Style::CheckBoxHeight + 5;
|
||||
|
||||
for(unsigned n = 0; n < Breakpoints; n++) {
|
||||
|
|
Loading…
Reference in New Issue