Update to v085r07 release.

byuu says:

Changelog:
- stuff

[Editor's note - pretty much just more debugger implementation]
This commit is contained in:
Tim Allen 2012-02-12 16:05:43 +11:00
parent 4bc5f66aa5
commit ad3eafd735
20 changed files with 435 additions and 110 deletions

View File

@ -1,7 +1,7 @@
#ifndef BASE_HPP
#define BASE_HPP
const char Version[] = "085.06";
const char Version[] = "085.07";
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>

View File

@ -433,51 +433,4 @@ void CPUcore::disassemble_opcode(char *output, uint32 addr) {
strcat(s, t);
}
//opcode_length() retrieves the length of the next opcode
//to be executed. It is used by the debugger to step over,
//disable and proceed cpu opcodes.
//
//5 and 6 are special cases, 5 is used for #consts based on
//the A register size, 6 for the X/Y register size. the
//rest are literal sizes. There's no need to test for
//emulation mode, as regs.p.m/regs.p.x should *always* be
//set in emulation mode.
uint8 CPUcore::opcode_length() {
uint8 op, len;
static uint8 op_len_tbl[256] = {
//0,1,2,3, 4,5,6,7, 8,9,a,b, c,d,e,f
2,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x0n
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x1n
3,2,4,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x2n
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x3n
1,2,2,2, 3,2,2,2, 1,5,1,1, 3,3,3,4, //0x4n
2,2,2,2, 3,2,2,2, 1,3,1,1, 4,3,3,4, //0x5n
1,2,3,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x6n
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x7n
2,2,3,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x8n
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x9n
6,2,6,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xan
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0xbn
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xcn
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0xdn
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xen
2,2,2,2, 3,2,2,2, 1,3,1,1, 3,3,3,4 //0xfn
};
if(false /* in_opcode() == true */) {
return 0;
}
op = dreadb(regs.pc.d);
len = op_len_tbl[op];
if(len == 5) return (regs.e || regs.p.m) ? 2 : 3;
if(len == 6) return (regs.e || regs.p.x) ? 2 : 3;
return len;
}
#endif

View File

@ -27,4 +27,3 @@ uint8 dreadb(uint32 addr);
uint16 dreadw(uint32 addr);
uint32 dreadl(uint32 addr);
uint32 decode(uint8 offset_type, uint32 addr);
uint8 opcode_length();

View File

@ -4,7 +4,7 @@ include $(snes)/Makefile
name := laevateinn
ui_objects := ui-main ui-interface ui-debugger ui-console
ui_objects += ui-video ui-memory ui-breakpoint
ui_objects += ui-video ui-cpu ui-memory ui-breakpoint
ui_objects += phoenix ruby
ui_objects += $(if $(call streq,$(platform),win),resource)
@ -33,6 +33,7 @@ obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/)
obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/*)
obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/*)
obj/ui-console.o: $(ui)/console/console.cpp $(call rwildcard,$(ui)/*)
obj/ui-cpu.o: $(ui)/cpu/cpu.cpp $(call rwildcard,$(ui)/*)
obj/ui-video.o: $(ui)/video/video.cpp $(call rwildcard,$(ui)/*)
obj/ui-memory.o: $(ui)/memory/memory.cpp $(call rwildcard,$(ui)/*)
obj/ui-breakpoint.o: $(ui)/breakpoint/breakpoint.cpp $(call rwildcard,$(ui)/*)

View File

@ -22,6 +22,7 @@ using namespace ruby;
#include "debugger/debugger.hpp"
#include "console/console.hpp"
#include "video/video.hpp"
#include "cpu/cpu.hpp"
#include "memory/memory.hpp"
#include "breakpoint/breakpoint.hpp"
extern uint8_t laevateinnLogo[121905];

View File

@ -2,7 +2,8 @@
BreakpointEditor *breakpointEditor = nullptr;
BreakpointEntry::BreakpointEntry() {
enable.setText("Enable");
static unsigned id = 1;
enable.setText({ id++, ". Enable" });
addr.setFont(application->monospaceFont);
data.setFont(application->monospaceFont);
type.append("Read", "Write", "Exec");
@ -13,14 +14,83 @@ BreakpointEntry::BreakpointEntry() {
append(data, {25, 0}, 5);
append(type, {0, 0}, 5);
append(source, {0, 0});
enable.onToggle = [&] {
bool flag = !enable.checked();
addr.setEnabled(flag);
data.setEnabled(flag);
type.setEnabled(flag);
source.setEnabled(flag);
breakpointEditor->synchronize();
};
}
BreakpointEditor::BreakpointEditor() {
setTitle("Breakpoint Editor");
layout.setMargin(5);
for(auto &bp : breakpoint) layout.append(bp, {0, 0}, 5);
for(auto &bp : breakpointEntry) layout.append(bp, {0, 0}, 5);
append(layout);
setGeometry({800, 600, layout.minimumGeometry().width, layout.minimumGeometry().height - 5});
synchronize();
}
//enable checkbox toggled on one of the five BreakpointEntry items:
//cache settings to decrease testing overhead whilst debugging
void BreakpointEditor::synchronize() {
breakpoint.reset();
unsigned id = 0;
for(auto &entry : breakpointEntry) {
id++;
if(entry.enable.checked() == false) continue;
Breakpoint bp;
bp.id = id;
bp.compare = !entry.data.text().empty();
bp.addr = hex(entry.addr.text());
bp.data = hex(entry.data.text());
bp.type = entry.type.selection();
bp.source = entry.source.selection();
breakpoint.append(bp);
}
breakpointReadCPU.reset();
breakpointWriteCPU.reset();
breakpointExecCPU.reset();
for(auto &bp : breakpoint) if(bp.type == Breakpoint::Read && bp.source == Breakpoint::CPU) breakpointReadCPU.append(bp);
for(auto &bp : breakpoint) if(bp.type == Breakpoint::Write && bp.source == Breakpoint::CPU) breakpointWriteCPU.append(bp);
for(auto &bp : breakpoint) if(bp.type == Breakpoint::Exec && bp.source == Breakpoint::CPU) breakpointExecCPU.append(bp);
}
bool BreakpointEditor::testReadCPU(uint24 addr) {
for(auto &bp : breakpointReadCPU) {
if(bp.addr == addr) {
if(bp.compare && bp.data != SNES::bus.read(addr)) continue;
debugger->print("Breakpoint #", bp.id, " hit\n");
return true;
}
}
return false;
}
bool BreakpointEditor::testWriteCPU(uint24 addr, uint8 data) {
for(auto &bp : breakpointWriteCPU) {
if(bp.addr == addr) {
if(bp.compare && bp.data != data) continue;
debugger->print("Breakpoint #", bp.id, " hit\n");
return true;
}
}
return false;
}
bool BreakpointEditor::testExecCPU(uint24 addr) {
for(auto &bp : breakpointExecCPU) {
if(bp.addr == addr) {
debugger->print("Breapoint #", bp.id, " hit\n");
return true;
}
}
return false;
}

View File

@ -10,7 +10,27 @@ struct BreakpointEntry : HorizontalLayout {
struct BreakpointEditor : Window {
VerticalLayout layout;
BreakpointEntry breakpoint[5];
BreakpointEntry breakpointEntry[8];
struct Breakpoint {
enum : unsigned { Read, Write, Exec };
enum : unsigned { CPU, APU, VRAM, OAM, CGRAM };
unsigned id;
bool compare;
unsigned addr;
unsigned data;
unsigned type;
unsigned source;
};
vector<Breakpoint> breakpoint;
vector<Breakpoint> breakpointReadCPU;
vector<Breakpoint> breakpointWriteCPU;
vector<Breakpoint> breakpointExecCPU;
void synchronize();
bool testReadCPU(uint24 addr);
bool testWriteCPU(uint24 addr, uint8 data);
bool testExecCPU(uint24 addr);
BreakpointEditor();
};

View File

@ -6,6 +6,7 @@ AboutWindow::AboutWindow() {
setResizable(false);
layout.setMargin(10);
layout.setAlignment(0.5);
canvas.setSize({288, 360});
title.setFont("Sans, 16, Bold");
title.setText("Laevateinn");
@ -13,14 +14,8 @@ AboutWindow::AboutWindow() {
version.setText({"bsnes/debugger v", Version});
layout.append(canvas, {288, 360});
layout.append(titleLayout, {~0, 0});
titleLayout.append(titleL, {~0, 0});
titleLayout.append(title, {0, 0});
titleLayout.append(titleR, {~0, 0});
layout.append(versionLayout, {~0, 0});
versionLayout.append(versionL, {~0, 0});
versionLayout.append(version, {0, 0});
versionLayout.append(versionR, {~0, 0});
layout.append(title, {0, 0});
layout.append(version, {0, 0});
append(layout);
}

View File

@ -21,9 +21,9 @@ ConsoleWindow::ConsoleWindow() {
menuDebug.setText("&Debug");
menuDebugCPU.setText("CPU");
menuDebugCPU.setChecked(debugger->flags.debugCPU);
menuDebugCPU.setChecked(debugger->debug.cpu);
menuDebugSMP.setText("SMP");
menuDebugSMP.setChecked(debugger->flags.debugSMP);
menuDebugSMP.setChecked(debugger->debug.smp);
menuDebugSMP.setEnabled(false);
menuDebug.append(menuDebugCPU, menuDebugSMP);
append(menuDebug);
@ -39,9 +39,11 @@ ConsoleWindow::ConsoleWindow() {
menuWindows.setText("&Windows");
menuWindowsVideoWindow.setText("Video");
menuWindowsCPUDebugger.setText("CPU Debugger");
menuWindowsMemoryEditor.setText("Memory Editor");
menuWindowsBreakpointEditor.setText("Breakpoint Editor");
menuWindows.append(menuWindowsVideoWindow, menuWindowsMemoryEditor, menuWindowsBreakpointEditor);
menuWindows.append(menuWindowsVideoWindow, menuWindowsCPUDebugger, menuWindowsMemoryEditor,
menuWindowsBreakpointEditor);
append(menuWindows);
menuHelp.setText("&Help");
@ -83,8 +85,8 @@ ConsoleWindow::ConsoleWindow() {
audio.set(Audio::Synchronize, menuEmulationSynchronizeAudio.checked());
};
menuDebugCPU.onToggle = [&] { debugger->flags.debugCPU = menuDebugCPU.checked(); };
menuDebugSMP.onToggle = [&] { debugger->flags.debugSMP = menuDebugSMP.checked(); };
menuDebugCPU.onToggle = [&] { debugger->debug.cpu = menuDebugCPU.checked(); };
menuDebugSMP.onToggle = [&] { debugger->debug.smp = menuDebugSMP.checked(); };
menuTracerEnable.onToggle = [&] { debugger->tracerEnable(menuTracerEnable.checked()); };
@ -93,6 +95,11 @@ ConsoleWindow::ConsoleWindow() {
videoWindow->setFocused();
};
menuWindowsCPUDebugger.onActivate = [&] {
cpuDebugger->setVisible();
cpuDebugger->setFocused();
};
menuWindowsMemoryEditor.onActivate = [&] {
memoryEditor->update();
memoryEditor->setVisible();
@ -107,7 +114,7 @@ ConsoleWindow::ConsoleWindow() {
menuHelpAbout.onActivate = [&] { aboutWindow->show(); };
runButton.onActivate = [&] {
if(debugger->flags.paused == true) debugger->resume();
if(debugger->paused) debugger->resume();
else debugger->suspend();
};

View File

@ -18,6 +18,7 @@ struct ConsoleWindow : Window {
Menu menuWindows;
Item menuWindowsVideoWindow;
Item menuWindowsCPUDebugger;
Item menuWindowsMemoryEditor;
Item menuWindowsBreakpointEditor;
@ -40,14 +41,8 @@ struct ConsoleWindow : Window {
struct AboutWindow : Window {
VerticalLayout layout;
Canvas canvas;
HorizontalLayout titleLayout;
Widget titleL;
Label title;
Widget titleR;
HorizontalLayout versionLayout;
Widget versionL;
Label version;
Widget versionR;
Label title;
Label version;
void show();
AboutWindow();

128
bsnes/ui-debugger/cpu/cpu.cpp Executable file
View File

@ -0,0 +1,128 @@
#include "../base.hpp"
CPUDebugger *cpuDebugger = nullptr;
unsigned CPUDebugger::opcodeLength(uint24 addr) const {
#define M 5
#define X 6
static unsigned lengthTable[256] = {
2, 2, 2, 2, 2, 2, 2, 2, 1, M, 1, 1, 3, 3, 3, 4,
2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4,
3, 2, 4, 2, 2, 2, 2, 2, 1, M, 1, 1, 3, 3, 3, 4,
2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4,
1, 2, 2, 2, 3, 2, 2, 2, 1, M, 1, 1, 3, 3, 3, 4,
2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4,
1, 2, 3, 2, 2, 2, 2, 2, 1, M, 1, 1, 3, 3, 3, 4,
2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4,
2, 2, 3, 2, 2, 2, 2, 2, 1, M, 1, 1, 3, 3, 3, 4,
2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4,
X, 2, X, 2, 2, 2, 2, 2, 1, M, 1, 1, 3, 3, 3, 4,
2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4,
X, 2, 2, 2, 2, 2, 2, 2, 1, M, 1, 1, 3, 3, 3, 4,
2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4,
X, 2, 2, 2, 2, 2, 2, 2, 1, M, 1, 1, 3, 3, 3, 4,
2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4,
};
unsigned length = lengthTable[SNES::bus.read(addr)];
if(length == M) return 3 - (SNES::cpu.regs.e | SNES::cpu.regs.p.m);
if(length == X) return 3 - (SNES::cpu.regs.e | SNES::cpu.regs.p.x);
return length;
#undef M
#undef X
}
void CPUDebugger::updateDisassembly() {
string line[15];
char text[512];
SNES::cpu.disassemble_opcode(text, opcodePC);
text[29] = 0;
line[7] = { "> ", text };
signed addr = opcodePC;
for(signed o = 6; o >= 0; o--) {
for(signed b = 1; b <= 4; b++) {
if(addr - b >= 0 && (debugger->cpuUsage.data[addr - b] & Usage::Exec)) {
addr -= b;
SNES::cpu.disassemble_opcode(text, addr);
text[29] = 0;
line[o] = { " ", text };
break;
}
}
}
addr = opcodePC;
for(signed o = 8; o <= 14; o++) {
for(signed b = 1; b <= 4; b++) {
if(addr + b <= 0xffffff && (debugger->cpuUsage.data[addr + b] & Usage::Exec)) {
addr += b;
SNES::cpu.disassemble_opcode(text, addr);
text[29] = 0;
line[o] = { " ", text };
break;
}
}
}
string output;
for(auto &n : line) {
if(n.empty()) output.append(" ...\n");
else output.append(n, "\n");
}
output.rtrim<1>("\n");
disassembly.setText(output);
registers.setText({
"A:", hex<4>(SNES::cpu.regs.a), " X:", hex<4>(SNES::cpu.regs.x), " Y:", hex<4>(SNES::cpu.regs.y),
" S:", hex<4>(SNES::cpu.regs.s), " D:", hex<4>(SNES::cpu.regs.d), " DB:", hex<2>(SNES::cpu.regs.db), " ",
SNES::cpu.regs.e ? "E" : "R", ":",
SNES::cpu.regs.p.n ? "N" : "n", SNES::cpu.regs.p.v ? "V" : "v",
SNES::cpu.regs.p.m ? "M" : "m", SNES::cpu.regs.p.x ? "X" : "x",
SNES::cpu.regs.p.d ? "D" : "d", SNES::cpu.regs.p.i ? "I" : "i",
SNES::cpu.regs.p.z ? "Z" : "z", SNES::cpu.regs.p.c ? "C" : "c",
});
}
CPUDebugger::CPUDebugger() {
opcodePC = 0x008000;
setTitle("CPU Debugger");
setGeometry({800, 64, 500, 255});
layout.setMargin(5);
stepInto.setText("Step Into");
stepOver.setText("Step Over");
stepOver.setEnabled(false);
stepOut.setText("Step Out");
stepOut.setEnabled(false);
skipOver.setText("Skip Over");
skipOver.setEnabled(false);
autoRefresh.setText("Auto");
update.setText("Update");
disassembly.setFont(application->monospaceFont);
registers.setFont(application->monospaceFont);
registers.setText(" ");
layout.append(controlLayout, {~0, 0}, 5);
controlLayout.append(stepInto, {80, 0}, 5);
controlLayout.append(stepOver, {80, 0}, 5);
controlLayout.append(stepOut, {80, 0}, 5);
controlLayout.append(skipOver, {80, 0});
controlLayout.append(spacer, {~0, 0});
controlLayout.append(autoRefresh, {0, 0}, 5);
controlLayout.append(update, {80, 0});
layout.append(disassembly, {~0, ~0}, 5);
layout.append(registers, {~0, 0});
append(layout);
stepInto.onActivate = [&] {
debugger->flags.cpu.stepInto = true;
debugger->resume();
};
update.onActivate = { &CPUDebugger::updateDisassembly, this };
}

21
bsnes/ui-debugger/cpu/cpu.hpp Executable file
View File

@ -0,0 +1,21 @@
struct CPUDebugger : Window {
uint24 opcodePC;
VerticalLayout layout;
HorizontalLayout controlLayout;
Button stepInto;
Button stepOver;
Button stepOut;
Button skipOver;
Widget spacer;
CheckBox autoRefresh;
Button update;
TextEdit disassembly;
Label registers;
unsigned opcodeLength(uint24 addr) const;
void updateDisassembly();
CPUDebugger();
};
extern CPUDebugger *cpuDebugger;

View File

@ -2,15 +2,17 @@
Debugger *debugger = nullptr;
#include "hook.cpp"
#include "usage.cpp"
void Debugger::run() {
if(flags.paused == true) {
if(paused == true) {
usleep(2000);
return;
}
if(memoryEditor->autoRefresh.checked()) memoryEditor->update();
SNES::system.run();
if(cpuDebugger->autoRefresh.checked()) cpuDebugger->updateDisassembly();
if(memoryEditor->autoRefresh.checked()) memoryEditor->update();
}
void Debugger::echo(const string &text) {
@ -18,15 +20,17 @@ void Debugger::echo(const string &text) {
}
void Debugger::resume() {
flags.paused = false;
if(paused == false) return;
paused = false;
consoleWindow->runButton.setText("Stop");
consoleWindow->stepButton.setEnabled(false);
}
void Debugger::suspend() {
flags.paused = true;
if(paused == true) return;
paused = true;
flags.step = false;
flags.cpu.stepInto = false;
consoleWindow->runButton.setText("Run");
consoleWindow->stepButton.setEnabled(true);
}
void Debugger::tracerEnable(bool state) {
@ -40,22 +44,31 @@ void Debugger::tracerEnable(bool state) {
//if all files exist, use 000, even if it overwrites another log.
unsigned n = 1;
do {
if(file::exists({ interface->baseName, "-", decimal<3, '0'>(n), ".log" }) == false) break;
if(file::exists({ interface->pathName, "debug/trace-", decimal<3, '0'>(n), ".log" }) == false) break;
} while(++n <= 999);
string filename = { interface->baseName, "-", decimal<3, '0'>(n), ".log" };
string filename = { interface->pathName, "debug/trace-", decimal<3, '0'>(n), ".log" };
if(fpTracer.open(filename, file::mode::write) == false) return;
print("Tracing to ", filename, "\n");
}
Debugger::Debugger() {
flags.paused = true;
flags.step = false;
paused = true;
flags.debugCPU = true;
flags.debugSMP = false;
flags.step = false;
flags.cpu.stepInto = false;
debug.cpu = true;
debug.smp = false;
cpuUsage.allocate(16 * 1024 * 1024);
apuUsage.allocate(64 * 1024);
SNES::cpu.debugger.op_exec = { &Debugger::cpu_op_exec, this };
SNES::cpu.debugger.op_read = { &Debugger::cpu_op_read, this };
SNES::cpu.debugger.op_write = { &Debugger::cpu_op_write, this };
SNES::smp.debugger.op_exec = { &Debugger::smp_op_exec, this };
SNES::smp.debugger.op_read = { &Debugger::smp_op_read, this };
SNES::smp.debugger.op_write = { &Debugger::smp_op_write, this };
}

View File

@ -1,12 +1,35 @@
struct Debugger {
struct Flags {
bool paused; //do not run emulation when true; set when breakpoint is hit
bool step; //break on the next instruction from any processor
struct Usage {
enum : unsigned { Read = 4, Write = 2, Exec = 1 };
uint8_t *data;
unsigned size;
bool debugCPU;
bool debugSMP;
void allocate(unsigned size);
void reset();
Usage();
~Usage();
};
struct Debugger {
bool paused;
struct Flags {
bool step;
struct CPU {
bool stepInto;
} cpu;
} flags;
struct Debug {
bool cpu;
bool smp;
} debug;
Usage cpuUsage;
Usage apuUsage;
void loadUsage();
void saveUsage();
void resetUsage();
void run();
void echo(const string &text);
void resume(); //start running until breakpoint is reached
@ -18,6 +41,11 @@ struct Debugger {
void cpu_op_read(uint24 addr);
void cpu_op_write(uint24 addr, uint8 data);
//S-SMP
void smp_op_exec(uint16 addr);
void smp_op_read(uint16 addr);
void smp_op_write(uint16 addr, uint8 data);
Debugger();
file fpTracer;

View File

@ -1,26 +1,70 @@
//S-CPU
//=====
void Debugger::cpu_op_exec(uint24 addr) {
if(flags.debugCPU == false) return;
cpuUsage.data[addr] |= Usage::Exec;
cpuDebugger->opcodePC = addr;
bool breakpointHit = breakpointEditor->testExecCPU(addr);
char text[512];
if(fpTracer.open() || flags.step) {
if(fpTracer.open() || (debug.cpu && flags.step) || flags.cpu.stepInto || breakpointHit) {
char text[512];
SNES::cpu.disassemble_opcode(text, addr);
}
if(fpTracer.open()) {
fpTracer.print(text, "\n");
}
if(flags.step) {
flags.step = false;
print(text, "\n");
suspend();
consoleWindow->stepButton.setFocused();
SNES::scheduler.debug();
if(fpTracer.open()) fpTracer.print(text, "\n");
if((debug.cpu && flags.step) || flags.cpu.stepInto || breakpointHit) {
print(text, "\n");
if(debug.cpu && flags.step) {
consoleWindow->stepButton.setFocused();
}
if(flags.cpu.stepInto) {
cpuDebugger->stepInto.setFocused();
cpuDebugger->updateDisassembly();
}
suspend();
SNES::scheduler.debug();
}
}
}
void Debugger::cpu_op_read(uint24 addr) {
cpuUsage.data[addr] |= Usage::Read;
bool breakpointHit = breakpointEditor->testReadCPU(addr);
if(breakpointHit) {
char text[512];
SNES::cpu.disassemble_opcode(text, cpuDebugger->opcodePC);
print(text, "\n");
suspend();
SNES::scheduler.debug();
}
}
void Debugger::cpu_op_write(uint24 addr, uint8 data) {
cpuUsage.data[addr] |= Usage::Write;
bool breakpointHit = breakpointEditor->testWriteCPU(addr, data);
if(breakpointHit) {
char text[512];
SNES::cpu.disassemble_opcode(text, cpuDebugger->opcodePC);
print(text, "\n");
suspend();
SNES::scheduler.debug();
}
}
//S-SMP
//=====
void Debugger::smp_op_exec(uint16 addr) {
apuUsage.data[addr] |= Usage::Exec;
}
void Debugger::smp_op_read(uint16 addr) {
apuUsage.data[addr] |= Usage::Read;
}
void Debugger::smp_op_write(uint16 addr, uint8 data) {
apuUsage.data[addr] |= Usage::Write;
}

View File

@ -0,0 +1,39 @@
void Usage::allocate(unsigned size_) {
if(data) delete[] data;
size = size_;
data = new uint8_t[size]();
}
Usage::Usage() {
data = nullptr;
size = 0;
}
Usage::~Usage() {
if(data) delete[] data;
}
void Debugger::loadUsage() {
file fp;
if(fp.open({ interface->pathName, "debug/usage.cpu" }, file::mode::read)) {
fp.read(cpuUsage.data, min(cpuUsage.size, fp.size()));
fp.close();
}
if(fp.open({ interface->pathName, "debug/usage.apu" }, file::mode::read)) {
fp.read(apuUsage.data, min(apuUsage.size, fp.size()));
fp.close();
}
}
void Debugger::saveUsage() {
string filename;
filename = { interface->pathName, "debug/usage.cpu" };
file::write(filename, cpuUsage.data, cpuUsage.size);
filename = { interface->pathName, "debug/usage.apu" };
file::write(filename, apuUsage.data, apuUsage.size);
}
void Debugger::resetUsage() {
if(cpuUsage.data) memset(cpuUsage.data, 0, cpuUsage.size);
if(apuUsage.data) memset(apuUsage.data, 0, apuUsage.size);
}

View File

@ -14,6 +14,8 @@ bool Interface::loadCartridge(const string &filename) {
fileName = filename;
baseName = nall::basename(fileName);
pathName = dir(baseName);
mkdir(string{pathName, "debug/"}, 0755);
string markup;
markup.readfile({ baseName, ".xml" });
@ -44,6 +46,8 @@ void Interface::loadMemory() {
delete[] data;
}
}
debugger->loadUsage();
}
void Interface::saveMemory() {
@ -54,6 +58,8 @@ void Interface::saveMemory() {
debugger->print("Saved ", filename, "\n");
}
}
debugger->saveUsage();
}
//hires is always true for accuracy core

View File

@ -1,6 +1,7 @@
struct Interface : SNES::Interface {
string fileName;
string baseName;
string pathName;
bool loadCartridge(const string &filename);
void loadMemory();

View File

@ -41,11 +41,13 @@ Application::Application(int argc, char **argv) {
consoleWindow = new ConsoleWindow;
aboutWindow = new AboutWindow;
videoWindow = new VideoWindow;
cpuDebugger = new CPUDebugger;
memoryEditor = new MemoryEditor;
breakpointEditor = new BreakpointEditor;
videoWindow->setVisible();
consoleWindow->setVisible();
videoWindow->setVisible();
consoleWindow->setFocused();
if(audio.init() == false) {
audio.driver("None");
@ -55,6 +57,8 @@ Application::Application(int argc, char **argv) {
audio.set(Audio::Frequency, 32000u);
if(interface->loadCartridge(filename) == false) return;
cpuDebugger->updateDisassembly();
memoryEditor->selectSource();
while(quit == false) {
OS::processEvents();
@ -65,8 +69,10 @@ Application::Application(int argc, char **argv) {
}
Application::~Application() {
exit(0);
delete breakpointEditor;
delete memoryEditor;
delete cpuDebugger;
delete videoWindow;
delete aboutWindow;
delete consoleWindow;

View File

@ -35,8 +35,6 @@ MemoryEditor::MemoryEditor() {
source.onChange = { &MemoryEditor::selectSource, this };
editor.onRead = { &MemoryEditor::read, this };
editor.onWrite = { &MemoryEditor::write, this };
selectSource();
}
uint8_t MemoryEditor::read(unsigned addr) {