#include "../ui-base.hpp" #if defined(DEBUGGER) #include "debugger.moc" Debugger *debugger; #include "tracer.cpp" #include "tools/disassembler.cpp" #include "tools/breakpoint.cpp" #include "tools/memory.cpp" #include "tools/properties.cpp" #include "ppu/vram-viewer.cpp" #include "ppu/oam-viewer.cpp" #include "ppu/cgram-viewer.cpp" #include "misc/debugger-options.cpp" Debugger::Debugger() { setObjectName("debugger"); setWindowTitle("Debugger"); setGeometryString(&config().geometry.debugger); application.windowList.append(this); layout = new QHBoxLayout; layout->setMargin(Style::WindowMargin); layout->setSpacing(Style::WidgetSpacing); setLayout(layout); menu = new QMenuBar; layout->setMenuBar(menu); menu_tools = menu->addMenu("Tools"); menu_tools_disassembler = menu_tools->addAction("Disassembler ..."); menu_tools_breakpoint = menu_tools->addAction("Breakpoint Editor ..."); menu_tools_memory = menu_tools->addAction("Memory Editor ..."); menu_tools_propertiesViewer = menu_tools->addAction("Properties Viewer ..."); menu_ppu = menu->addMenu("S-PPU"); menu_ppu_vramViewer = menu_ppu->addAction("Video RAM Viewer ..."); menu_ppu_oamViewer = menu_ppu->addAction("Sprite Viewer ..."); menu_ppu_cgramViewer = menu_ppu->addAction("Palette Viewer ..."); menu_misc = menu->addMenu("Misc"); menu_misc_clear = menu_misc->addAction("Clear Console"); menu_misc_options = menu_misc->addAction("Options ..."); console = new QTextEdit; console->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); console->setReadOnly(true); console->setFont(QFont(Style::Monospace)); console->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); console->setMinimumWidth((92 + 4) * console->fontMetrics().width(' ')); console->setMinimumHeight((25 + 1) * console->fontMetrics().height()); layout->addWidget(console); controlLayout = new QVBoxLayout; controlLayout->setSpacing(0); layout->addLayout(controlLayout); commandLayout = new QHBoxLayout; controlLayout->addLayout(commandLayout); runBreak = new QPushButton("Break"); commandLayout->addWidget(runBreak); commandLayout->addSpacing(Style::WidgetSpacing); stepInstruction = new QPushButton("Step"); commandLayout->addWidget(stepInstruction); controlLayout->addSpacing(Style::WidgetSpacing); stepCPU = new QCheckBox("Step S-CPU"); controlLayout->addWidget(stepCPU); stepSMP = new QCheckBox("Step S-SMP"); controlLayout->addWidget(stepSMP); traceCPU = new QCheckBox("Trace S-CPU opcodes"); controlLayout->addWidget(traceCPU); traceSMP = new QCheckBox("Trace S-SMP opcodes"); controlLayout->addWidget(traceSMP); traceMask = new QCheckBox("Enable trace mask"); controlLayout->addWidget(traceMask); spacer = new QWidget; spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); controlLayout->addWidget(spacer); tracer = new Tracer; disassembler = new Disassembler; breakpointEditor = new BreakpointEditor; memoryEditor = new MemoryEditor; propertiesViewer = new PropertiesViewer; vramViewer = new VramViewer; oamViewer = new OamViewer; cgramViewer = new CgramViewer; debuggerOptions = new DebuggerOptions; connect(menu_tools_disassembler, SIGNAL(triggered()), disassembler, SLOT(show())); connect(menu_tools_breakpoint, SIGNAL(triggered()), breakpointEditor, SLOT(show())); connect(menu_tools_memory, SIGNAL(triggered()), memoryEditor, SLOT(show())); connect(menu_tools_propertiesViewer, SIGNAL(triggered()), propertiesViewer, SLOT(show())); connect(menu_ppu_vramViewer, SIGNAL(triggered()), vramViewer, SLOT(show())); connect(menu_ppu_oamViewer, SIGNAL(triggered()), oamViewer, SLOT(show())); connect(menu_ppu_cgramViewer, SIGNAL(triggered()), cgramViewer, SLOT(show())); connect(menu_misc_clear, SIGNAL(triggered()), this, SLOT(clear())); connect(menu_misc_options, SIGNAL(triggered()), debuggerOptions, SLOT(show())); connect(runBreak, SIGNAL(released()), this, SLOT(toggleRunStatus())); connect(stepInstruction, SIGNAL(released()), this, SLOT(stepAction())); connect(stepCPU, SIGNAL(released()), this, SLOT(synchronize())); connect(stepSMP, SIGNAL(released()), this, SLOT(synchronize())); connect(traceCPU, SIGNAL(stateChanged(int)), tracer, SLOT(setCpuTraceState(int))); connect(traceSMP, SIGNAL(stateChanged(int)), tracer, SLOT(setSmpTraceState(int))); connect(traceMask, SIGNAL(stateChanged(int)), tracer, SLOT(setTraceMaskState(int))); frameCounter = 0; synchronize(); resize(855, 425); } void Debugger::modifySystemState(unsigned state) { string usagefile = filepath(nall::basename(cartridge.fileName), config().path.data); usagefile << "-usage.bin"; file fp; if(state == Utility::LoadCartridge) { if(config().debugger.cacheUsageToDisk && fp.open(usagefile, file::mode::read)) { fp.read(SNES::cpu.usage, 1 << 24); fp.read(SNES::smp.usage, 1 << 16); fp.close(); } else { memset(SNES::cpu.usage, 0x00, 1 << 24); memset(SNES::smp.usage, 0x00, 1 << 16); } } if(state == Utility::UnloadCartridge) { if(config().debugger.cacheUsageToDisk && fp.open(usagefile, file::mode::write)) { fp.write(SNES::cpu.usage, 1 << 24); fp.write(SNES::smp.usage, 1 << 16); fp.close(); } } } void Debugger::synchronize() { runBreak->setText(application.debug ? "Run" : "Break"); stepInstruction->setEnabled(SNES::cartridge.loaded() && application.debug && (stepCPU->isChecked() || stepSMP->isChecked())); SNES::debugger.step_cpu = application.debug && stepCPU->isChecked(); SNES::debugger.step_smp = application.debug && stepSMP->isChecked(); memoryEditor->synchronize(); } void Debugger::echo(const char *message) { console->moveCursor(QTextCursor::End); console->insertHtml(message); } void Debugger::clear() { console->setHtml(""); } void Debugger::toggleRunStatus() { application.debug = !application.debug; if(!application.debug) application.debugrun = false; synchronize(); } void Debugger::stepAction() { application.debugrun = true; } void Debugger::event() { char t[256]; switch(SNES::debugger.break_event) { case SNES::Debugger::BreakEvent::BreakpointHit: { unsigned n = SNES::debugger.breakpoint_hit; echo(string() << "Breakpoint " << n << " hit (" << SNES::debugger.breakpoint[n].counter << ").
"); if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::Source::CPUBus) { SNES::debugger.step_cpu = true; SNES::cpu.disassemble_opcode(t, SNES::cpu.opcode_pc); string s = t; s.replace(" ", " "); echo(string() << "" << s << "
"); disassembler->refresh(Disassembler::CPU, SNES::cpu.opcode_pc); } if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::Source::APURAM) { SNES::debugger.step_smp = true; SNES::smp.disassemble_opcode(t, SNES::smp.opcode_pc); string s = t; s.replace(" ", " "); echo(string() << "" << t << "
"); disassembler->refresh(Disassembler::SMP, SNES::smp.opcode_pc); } } break; case SNES::Debugger::BreakEvent::CPUStep: { SNES::cpu.disassemble_opcode(t, SNES::cpu.regs.pc); string s = t; s.replace(" ", " "); echo(string() << "" << s << "
"); disassembler->refresh(Disassembler::CPU, SNES::cpu.regs.pc); } break; case SNES::Debugger::BreakEvent::SMPStep: { SNES::smp.disassemble_opcode(t, SNES::smp.regs.pc); string s = t; s.replace(" ", " "); echo(string() << "" << s << "
"); disassembler->refresh(Disassembler::SMP, SNES::smp.regs.pc); } break; } autoUpdate(); } //called once every time a video frame is rendered, used to update "auto refresh" tool windows void Debugger::frameTick() { if(++frameCounter >= (SNES::system.region() == SNES::System::Region::NTSC ? 60 : 50)) { frameCounter = 0; autoUpdate(); } } void Debugger::autoUpdate() { memoryEditor->autoUpdate(); propertiesViewer->autoUpdate(); vramViewer->autoUpdate(); oamViewer->autoUpdate(); cgramViewer->autoUpdate(); } #endif