diff --git a/bsnes/snes/alt/cpu/debugger/debugger.cpp b/bsnes/snes/alt/cpu/debugger/debugger.cpp index dae1b415..f1054ed7 100755 --- a/bsnes/snes/alt/cpu/debugger/debugger.cpp +++ b/bsnes/snes/alt/cpu/debugger/debugger.cpp @@ -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() { diff --git a/bsnes/snes/alt/cpu/debugger/debugger.hpp b/bsnes/snes/alt/cpu/debugger/debugger.hpp index a74f6015..e6d7327c 100755 --- a/bsnes/snes/alt/cpu/debugger/debugger.hpp +++ b/bsnes/snes/alt/cpu/debugger/debugger.hpp @@ -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); diff --git a/bsnes/snes/cpu/debugger/debugger.cpp b/bsnes/snes/cpu/debugger/debugger.cpp index b278d9ab..ccd55447 100755 --- a/bsnes/snes/cpu/debugger/debugger.cpp +++ b/bsnes/snes/cpu/debugger/debugger.cpp @@ -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() { diff --git a/bsnes/snes/cpu/debugger/debugger.hpp b/bsnes/snes/cpu/debugger/debugger.hpp index a74f6015..bbb48b6e 100755 --- a/bsnes/snes/cpu/debugger/debugger.hpp +++ b/bsnes/snes/cpu/debugger/debugger.hpp @@ -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); diff --git a/bsnes/snes/smp/debugger/debugger.cpp b/bsnes/snes/smp/debugger/debugger.cpp index 74bdbc1a..d7ef7f8a 100755 --- a/bsnes/snes/smp/debugger/debugger.cpp +++ b/bsnes/snes/smp/debugger/debugger.cpp @@ -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() { diff --git a/bsnes/snes/smp/debugger/debugger.hpp b/bsnes/snes/smp/debugger/debugger.hpp index 9c613497..3c8558db 100755 --- a/bsnes/snes/smp/debugger/debugger.hpp +++ b/bsnes/snes/smp/debugger/debugger.hpp @@ -11,6 +11,7 @@ public: }; uint8 *usage; uint16 opcode_pc; + bool opcode_edge; void op_step(); uint8 op_read(uint16 addr); diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 73540dab..3ed7467b 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -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; } } diff --git a/bsnes/ui-phoenix/debugger/console.cpp b/bsnes/ui-phoenix/debugger/console.cpp index 8a54f087..3945da1d 100755 --- a/bsnes/ui-phoenix/debugger/console.cpp +++ b/bsnes/ui-phoenix/debugger/console.cpp @@ -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); } diff --git a/bsnes/ui-phoenix/debugger/console.hpp b/bsnes/ui-phoenix/debugger/console.hpp index 3d95b93d..99f7a11e 100755 --- a/bsnes/ui-phoenix/debugger/console.hpp +++ b/bsnes/ui-phoenix/debugger/console.hpp @@ -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(); diff --git a/bsnes/ui-phoenix/debugger/cpu/debugger.cpp b/bsnes/ui-phoenix/debugger/cpu/debugger.cpp index 4167d2c1..601a4d99 100755 --- a/bsnes/ui-phoenix/debugger/cpu/debugger.cpp +++ b/bsnes/ui-phoenix/debugger/cpu/debugger.cpp @@ -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); } diff --git a/bsnes/ui-phoenix/debugger/cpu/debugger.hpp b/bsnes/ui-phoenix/debugger/cpu/debugger.hpp index a8bdcc2c..76bb90d1 100755 --- a/bsnes/ui-phoenix/debugger/cpu/debugger.hpp +++ b/bsnes/ui-phoenix/debugger/cpu/debugger.hpp @@ -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; diff --git a/bsnes/ui-phoenix/debugger/debugger.cpp b/bsnes/ui-phoenix/debugger/debugger.cpp index a029bd2b..fe1ca160 100755 --- a/bsnes/ui-phoenix/debugger/debugger.cpp +++ b/bsnes/ui-phoenix/debugger/debugger.cpp @@ -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; diff --git a/bsnes/ui-phoenix/debugger/debugger.hpp b/bsnes/ui-phoenix/debugger/debugger.hpp index b409a0bd..5c78d0ea 100755 --- a/bsnes/ui-phoenix/debugger/debugger.hpp +++ b/bsnes/ui-phoenix/debugger/debugger.hpp @@ -20,6 +20,7 @@ struct Debugger : TopLevelWindow { CheckBox showMemoryEditor; void create(); + void synchronize(); void setVisible(bool visible = true); void enable(bool state); void run(); diff --git a/bsnes/ui-phoenix/debugger/smp/debugger.cpp b/bsnes/ui-phoenix/debugger/smp/debugger.cpp index 875ca7bb..5f6241a6 100755 --- a/bsnes/ui-phoenix/debugger/smp/debugger.cpp +++ b/bsnes/ui-phoenix/debugger/smp/debugger.cpp @@ -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) { diff --git a/bsnes/ui-phoenix/debugger/smp/debugger.hpp b/bsnes/ui-phoenix/debugger/smp/debugger.hpp index ccd498cc..e141ec26 100755 --- a/bsnes/ui-phoenix/debugger/smp/debugger.hpp +++ b/bsnes/ui-phoenix/debugger/smp/debugger.hpp @@ -5,6 +5,7 @@ struct SMPDebugger : TopLevelWindow { Button proceed; void create(); + void synchronize(); void refreshDisassembly(); void eventStepInto(); void eventStepOver(); diff --git a/bsnes/ui-phoenix/debugger/tools/breakpoint-editor.cpp b/bsnes/ui-phoenix/debugger/tools/breakpoint-editor.cpp index 845aa9e9..071550d5 100755 --- a/bsnes/ui-phoenix/debugger/tools/breakpoint-editor.cpp +++ b/bsnes/ui-phoenix/debugger/tools/breakpoint-editor.cpp @@ -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++) {