mirror of
https://github.com/devinacker/bsnes-plus.git
synced 2025-04-02 10:52:46 -04:00
558 lines
19 KiB
C++
558 lines
19 KiB
C++
#include "memory.moc"
|
|
#include "qhexedit.moc"
|
|
#include "commands.moc"
|
|
|
|
#include "qhexedit2/qhexedit.cpp"
|
|
#include "qhexedit2/commands.cpp"
|
|
|
|
QVector <MemoryEditor*> memoryEditors;
|
|
|
|
MemoryEditor::MemoryEditor() {
|
|
setObjectName("memory-editor");
|
|
setWindowTitle("Memory Editor");
|
|
setGeometryString(&config().geometry.memoryEditor);
|
|
application.windowList.append(this);
|
|
|
|
layout = new QGridLayout;
|
|
layout->setMargin(Style::WindowMargin);
|
|
layout->setSpacing(Style::WidgetSpacing);
|
|
setLayout(layout);
|
|
|
|
editor = new QHexEdit;
|
|
editor->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
editor->reader = { &MemoryEditor::reader, this };
|
|
editor->writer = { &MemoryEditor::writer, this };
|
|
editor->usage = { &MemoryEditor::usage, this };
|
|
memorySource = SNES::Debugger::MemorySource::CPUBus;
|
|
layout->addWidget(editor, 0, 0);
|
|
|
|
controlLayout = new QVBoxLayout;
|
|
controlLayout->setSpacing(0);
|
|
layout->addLayout(controlLayout, 0, 1);
|
|
layout->setColumnStretch(0, 1);
|
|
|
|
source = new QComboBox;
|
|
source->addItem("S-CPU bus");
|
|
source->addItem("S-APU bus");
|
|
source->addItem("S-DSP registers");
|
|
source->addItem("S-PPU VRAM");
|
|
source->addItem("S-PPU OAM");
|
|
source->addItem("S-PPU CGRAM");
|
|
source->addItem("Cartridge ROM");
|
|
source->addItem("Cartridge RAM");
|
|
source->addItem("SA-1 bus");
|
|
source->addItem("SuperFX bus");
|
|
source->addItem("Super GB bus");
|
|
source->addItem("Super GB cart ROM");
|
|
source->addItem("Super GB cart RAM");
|
|
controlLayout->addWidget(source);
|
|
controlLayout->addSpacing(2);
|
|
|
|
addr = new QLineEdit;
|
|
controlLayout->addWidget(addr);
|
|
|
|
autoUpdateBox = new QCheckBox("Auto update");
|
|
controlLayout->addWidget(autoUpdateBox);
|
|
|
|
refreshButton = new QPushButton("Refresh");
|
|
controlLayout->addWidget(refreshButton);
|
|
|
|
toolLayout = new QHBoxLayout;
|
|
controlLayout->addLayout(toolLayout);
|
|
#define tool(widget, icon, text, slot, accel) \
|
|
widget = new QToolButton; \
|
|
toolLayout->addWidget(widget); \
|
|
widget->setAutoRaise(true); \
|
|
widget->setDefaultAction(new QAction(this)); \
|
|
widget->defaultAction()->setIcon(QIcon(":16x16/mem-" icon ".png")); \
|
|
widget->defaultAction()->setToolTip(text); \
|
|
widget->defaultAction()->setShortcut(accel); \
|
|
connect(widget->defaultAction(), SIGNAL(triggered()), this, SLOT(slot()))
|
|
tool(prevCodeButton, "prev-code", "Previous Code", prevCode, 0);
|
|
tool(nextCodeButton, "next-code", "Next Code", nextCode, 0);
|
|
tool(prevDataButton, "prev-data", "Previous Data", prevData, 0);
|
|
tool(nextDataButton, "next-data", "Next Data", nextData, 0);
|
|
tool(prevUnkButton, "prev-unknown", "Previous Unknown", prevUnknown, 0);
|
|
tool(nextUnkButton, "next-unknown", "Next Unknown", nextUnknown, 0);
|
|
toolLayout->addStretch();
|
|
|
|
toolLayout = new QHBoxLayout;
|
|
controlLayout->addLayout(toolLayout);
|
|
tool(findButton, "find", "Find in Memory (Ctrl+F)", search, Qt::Key_F | Qt::CTRL);
|
|
// TODO: other icons for these maybe
|
|
tool(findPrevButton, "prev-unknown", "Find again up (Shift+F3)", searchPrev, Qt::Key_F3 | Qt::SHIFT);
|
|
tool(findNextButton, "next-unknown", "Find again down (F3)", searchNext, Qt::Key_F3);
|
|
toolLayout->addStretch();
|
|
#undef tool
|
|
|
|
spacer = new QWidget;
|
|
spacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
|
controlLayout->addWidget(spacer);
|
|
|
|
exportButton = new QPushButton("Export");
|
|
controlLayout->addWidget(exportButton);
|
|
|
|
importButton = new QPushButton("Import");
|
|
controlLayout->addWidget(importButton);
|
|
|
|
statusBar = new QLabel;
|
|
layout->addWidget(statusBar, 1, 0, 1, 2);
|
|
|
|
connect(editor, SIGNAL(currentAddressChanged(qint64)), this, SLOT(showAddress(qint64)));
|
|
connect(editor, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
|
|
connect(source, SIGNAL(currentIndexChanged(int)), this, SLOT(sourceChanged(int)));
|
|
connect(source, SIGNAL(currentIndexChanged(int)), this, SLOT(updateOffset()));
|
|
connect(addr, SIGNAL(textEdited(const QString&)), this, SLOT(updateOffset()));
|
|
connect(addr, SIGNAL(returnPressed()), this, SLOT(updateOffset()));
|
|
connect(refreshButton, SIGNAL(released()), this, SLOT(refresh()));
|
|
connect(exportButton, SIGNAL(released()), this, SLOT(exportMemory()));
|
|
connect(importButton, SIGNAL(released()), this, SLOT(importMemory()));
|
|
|
|
searchPos = -1;
|
|
breakpointPos = -1;
|
|
|
|
sourceChanged(0);
|
|
}
|
|
|
|
void MemoryEditor::autoUpdate() {
|
|
if(SNES::cartridge.loaded() && autoUpdateBox->isChecked()) {
|
|
editor->refresh(false);
|
|
}
|
|
}
|
|
|
|
void MemoryEditor::closeEvent(QCloseEvent *ev) {
|
|
memoryEditors.removeOne(this);
|
|
Window::closeEvent(ev);
|
|
}
|
|
|
|
void MemoryEditor::synchronize() {
|
|
if(SNES::cartridge.loaded() == false) {
|
|
source->setEnabled(false);
|
|
addr->setEnabled(false);
|
|
autoUpdateBox->setEnabled(false);
|
|
refreshButton->setEnabled(false);
|
|
exportButton->setEnabled(false);
|
|
importButton->setEnabled(false);
|
|
} else {
|
|
source->setEnabled(true);
|
|
addr->setEnabled(true);
|
|
autoUpdateBox->setEnabled(true);
|
|
refreshButton->setEnabled(true);
|
|
exportButton->setEnabled(true);
|
|
importButton->setEnabled(true);
|
|
}
|
|
|
|
sourceChanged(source->currentIndex());
|
|
}
|
|
|
|
void MemoryEditor::show() {
|
|
Window::show();
|
|
|
|
memoryEditors.push_back(this);
|
|
|
|
refresh();
|
|
}
|
|
|
|
void MemoryEditor::sourceChanged(int index) {
|
|
switch(index) { default:
|
|
case 0: memorySource = SNES::Debugger::MemorySource::CPUBus; editor->setEditorSize(16 * 1024 * 1024); break;
|
|
case 1: memorySource = SNES::Debugger::MemorySource::APUBus; editor->setEditorSize(64 * 1024); break;
|
|
case 2: memorySource = SNES::Debugger::MemorySource::DSP; editor->setEditorSize(128); break;
|
|
case 3: memorySource = SNES::Debugger::MemorySource::VRAM; editor->setEditorSize(SNES::memory::vram.size()); break;
|
|
case 4: memorySource = SNES::Debugger::MemorySource::OAM; editor->setEditorSize(544); break;
|
|
case 5: memorySource = SNES::Debugger::MemorySource::CGRAM; editor->setEditorSize(512); break;
|
|
case 6: memorySource = SNES::Debugger::MemorySource::CartROM; editor->setEditorSize(SNES::memory::cartrom.size()); break;
|
|
case 7: memorySource = SNES::Debugger::MemorySource::CartRAM; editor->setEditorSize(SNES::memory::cartram.size()); break;
|
|
case 8: memorySource = SNES::Debugger::MemorySource::SA1Bus; editor->setEditorSize(16 * 1024 * 1024); break;
|
|
case 9: memorySource = SNES::Debugger::MemorySource::SFXBus; editor->setEditorSize(8 * 1024 * 1024); break;
|
|
case 10: memorySource = SNES::Debugger::MemorySource::SGBBus; editor->setEditorSize(64 * 1024); break;
|
|
case 11: memorySource = SNES::Debugger::MemorySource::SGBROM; editor->setEditorSize(SNES::memory::gbrom.size()); break;
|
|
case 12: memorySource = SNES::Debugger::MemorySource::SGBRAM; editor->setEditorSize(SNES::memory::gbram.size()); break;
|
|
}
|
|
}
|
|
|
|
void MemoryEditor::refresh() {
|
|
editor->refresh();
|
|
}
|
|
|
|
void MemoryEditor::updateOffset() {
|
|
int offset = hex(addr->text().toUtf8().data());
|
|
|
|
editor->verticalScrollBar()->setValue(offset / BYTES_PER_LINE);
|
|
editor->setCursorPosition(2 * offset);
|
|
refresh();
|
|
}
|
|
|
|
void MemoryEditor::showAddress(qint64 address) {
|
|
if (address < 0) {
|
|
statusBar->setText("");
|
|
} else {
|
|
statusBar->setText(QString::asprintf("Address: 0x%06X", address));
|
|
}
|
|
}
|
|
|
|
void MemoryEditor::showContextMenu(const QPoint& pos) {
|
|
QMenu menu;
|
|
|
|
menu.addAction("Cut", editor, SLOT(cut()), QKeySequence::Cut);
|
|
menu.addAction("Copy", editor, SLOT(copy()), QKeySequence::Copy);
|
|
menu.addAction("Paste", editor, SLOT(paste()), QKeySequence::Paste);
|
|
|
|
menu.addSeparator();
|
|
|
|
menu.addAction("Undo", editor, SLOT(undo()), QKeySequence::Undo)
|
|
->setEnabled(editor->canUndo());
|
|
menu.addAction("Redo", editor, SLOT(redo()), QKeySequence::Redo)
|
|
->setEnabled(editor->canRedo());
|
|
|
|
if (memorySource != SNES::Debugger::MemorySource::CartROM
|
|
&& memorySource != SNES::Debugger::MemorySource::CartRAM
|
|
&& memorySource != SNES::Debugger::MemorySource::SGBROM
|
|
&& memorySource != SNES::Debugger::MemorySource::SGBRAM) {
|
|
menu.addSeparator();
|
|
|
|
breakpointPos = editor->cursorPosition(pos) / 2;
|
|
|
|
QMenu *menuBreakpoint = menu.addMenu(QString::asprintf("Add breakpoint at 0x%06X", breakpointPos));
|
|
menuBreakpoint->addAction("Read", this, SLOT(addBreakpointR()));
|
|
menuBreakpoint->addAction("Write", this, SLOT(addBreakpointW()));
|
|
menuBreakpoint->addAction("Execute", this, SLOT(addBreakpointX()));
|
|
menuBreakpoint->addAction("Read/Write", this, SLOT(addBreakpointRW()));
|
|
menuBreakpoint->addAction("Read/Write/Execute", this, SLOT(addBreakpointRWX()));
|
|
}
|
|
|
|
menu.exec(editor->mapToGlobal(pos));
|
|
}
|
|
|
|
void MemoryEditor::addBreakpoint(const string& mode) {
|
|
if (breakpointPos < 0) return;
|
|
string source;
|
|
|
|
switch (memorySource) {
|
|
case SNES::Debugger::MemorySource::CPUBus: source = "cpu"; break;
|
|
case SNES::Debugger::MemorySource::APUBus: source = "smp"; break;
|
|
case SNES::Debugger::MemorySource::DSP: source = "dsp"; break;
|
|
case SNES::Debugger::MemorySource::VRAM: source = "vram"; break;
|
|
case SNES::Debugger::MemorySource::OAM: source = "oam"; break;
|
|
case SNES::Debugger::MemorySource::CGRAM: source = "cgram"; break;
|
|
case SNES::Debugger::MemorySource::SA1Bus: source = "sa1"; break;
|
|
case SNES::Debugger::MemorySource::SFXBus: source = "sfx"; break;
|
|
case SNES::Debugger::MemorySource::SGBBus: source = "sgb"; break;
|
|
default: return; // cart ROM/RAM breakpoints not supported
|
|
}
|
|
|
|
breakpointEditor->addBreakpoint(hex<6>(breakpointPos), mode, source);
|
|
breakpointEditor->show();
|
|
}
|
|
|
|
void MemoryEditor::addBreakpointR() {
|
|
addBreakpoint("r");
|
|
}
|
|
|
|
void MemoryEditor::addBreakpointW() {
|
|
addBreakpoint("w");
|
|
}
|
|
|
|
void MemoryEditor::addBreakpointX() {
|
|
addBreakpoint("x");
|
|
}
|
|
|
|
void MemoryEditor::addBreakpointRW() {
|
|
addBreakpoint("rw");
|
|
}
|
|
|
|
void MemoryEditor::addBreakpointRWX() {
|
|
addBreakpoint("rwx");
|
|
}
|
|
|
|
void MemoryEditor::prevCode() {
|
|
gotoPrevious(QHexEdit::UsageExec);
|
|
}
|
|
|
|
void MemoryEditor::nextCode() {
|
|
gotoNext(QHexEdit::UsageExec);
|
|
}
|
|
|
|
void MemoryEditor::prevData() {
|
|
gotoPrevious(QHexEdit::UsageRead | QHexEdit::UsageWrite);
|
|
}
|
|
|
|
void MemoryEditor::nextData() {
|
|
gotoNext(QHexEdit::UsageRead | QHexEdit::UsageWrite);
|
|
}
|
|
|
|
void MemoryEditor::prevUnknown() {
|
|
gotoPrevious(0);
|
|
}
|
|
|
|
void MemoryEditor::nextUnknown() {
|
|
gotoNext(0);
|
|
}
|
|
|
|
void MemoryEditor::gotoPrevious(int type) {
|
|
int offset = (int)editor->cursorPosition() / 2;
|
|
bool found = false;
|
|
SNES::uint8 *usage;
|
|
|
|
if (memorySource == SNES::Debugger::MemorySource::CPUBus) {
|
|
usage = SNES::cpu.usage;
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::APUBus) {
|
|
usage = SNES::smp.usage;
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::CartROM) {
|
|
usage = SNES::cpu.cart_usage;
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::SA1Bus) {
|
|
usage = SNES::sa1.usage;
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::SFXBus) {
|
|
usage = SNES::superfx.usage;
|
|
} else if (memorySource == SNES::Debugger::MemorySource::SGBBus) {
|
|
usage = SNES::supergameboy.usage_;
|
|
} else return;
|
|
|
|
while (--offset >= 0) {
|
|
bool foundHere = ((type && usage[offset] & type) || (!type && (usage[offset] & 0xf0) == 0));
|
|
|
|
if (found && !foundHere) {
|
|
offset++; break;
|
|
} else if (!found && foundHere) {
|
|
found = foundHere;
|
|
}
|
|
}
|
|
|
|
if (offset < 0 && found) offset = 0;
|
|
|
|
if (offset >= 0) {
|
|
addr->setText(QString::number(offset, 16));
|
|
updateOffset();
|
|
} else {
|
|
QMessageBox::information(this, "Memory Editor", "Reached beginning of memory.", QMessageBox::Ok);
|
|
}
|
|
}
|
|
|
|
void MemoryEditor::gotoNext(int type) {
|
|
int offset = (int)editor->cursorPosition() / 2;
|
|
unsigned size = editor->editorSize();
|
|
bool found = true;
|
|
SNES::uint8 *usage;
|
|
|
|
if (memorySource == SNES::Debugger::MemorySource::CPUBus) {
|
|
usage = SNES::cpu.usage;
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::APUBus) {
|
|
usage = SNES::smp.usage;
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::CartROM) {
|
|
usage = SNES::cpu.cart_usage;
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::SA1Bus) {
|
|
usage = SNES::sa1.usage;
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::SFXBus) {
|
|
usage = SNES::superfx.usage;
|
|
} else if (memorySource == SNES::Debugger::MemorySource::SGBBus) {
|
|
usage = SNES::supergameboy.usage_;
|
|
} else return;
|
|
|
|
while (++offset < size) {
|
|
bool foundHere = ((type && usage[offset] & type) || (!type && (usage[offset] & 0xf0) == 0));
|
|
|
|
if (!found && foundHere) {
|
|
found = true; break;
|
|
} else if (found && !foundHere) {
|
|
found = foundHere;
|
|
}
|
|
}
|
|
|
|
if (offset < size) {
|
|
addr->setText(QString::number(offset, 16));
|
|
updateOffset();
|
|
} else {
|
|
QMessageBox::information(this, "Memory Editor", "Reached end of memory.", QMessageBox::Ok);
|
|
}
|
|
}
|
|
|
|
void MemoryEditor::search() {
|
|
QDialog dlg(this);
|
|
dlg.setWindowTitle("Search Memory");
|
|
|
|
QVBoxLayout *vbox = new QVBoxLayout;
|
|
dlg.setLayout(vbox);
|
|
|
|
vbox->addWidget(new QLabel("Enter a hex string, or \"ASCII text\" (in quotes)"));
|
|
|
|
QLineEdit *edit = new QLineEdit;
|
|
edit->setFont(QFont(Style::Monospace));
|
|
// TODO: put existing search string in box
|
|
vbox->addWidget(edit);
|
|
|
|
QGridLayout *grid = new QGridLayout;
|
|
vbox->addLayout(grid);
|
|
|
|
grid->addWidget(new QLabel("Search:"), 0, 0);
|
|
grid->addWidget(new QLabel("Start from:"), 1, 0);
|
|
QButtonGroup bgrpSearch, bgrpStart;
|
|
|
|
QRadioButton *searchDown = new QRadioButton("Down");
|
|
bgrpSearch.addButton(searchDown);
|
|
grid->addWidget(searchDown, 0, 1);
|
|
searchDown->setChecked(true);
|
|
QRadioButton *searchUp = new QRadioButton("Up");
|
|
bgrpSearch.addButton(searchUp);
|
|
grid->addWidget(searchUp, 0, 2);
|
|
|
|
QRadioButton *searchFromEnd = new QRadioButton("From start/end");
|
|
bgrpStart.addButton(searchFromEnd);
|
|
grid->addWidget(searchFromEnd, 1, 1);
|
|
searchFromEnd->setChecked(true);
|
|
QRadioButton *searchFromCur = new QRadioButton("From cursor");
|
|
bgrpStart.addButton(searchFromCur);
|
|
grid->addWidget(searchFromCur, 1, 2);
|
|
|
|
QDialogButtonBox *bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
|
connect(bbox, SIGNAL(accepted()), &dlg, SLOT(accept()));
|
|
connect(bbox, SIGNAL(rejected()), &dlg, SLOT(reject()));
|
|
grid->addWidget(bbox);
|
|
|
|
if (dlg.exec()) {
|
|
QString searchText = edit->text().trimmed();
|
|
|
|
// try quoted text
|
|
if (searchText.startsWith("\"") && searchText.endsWith("\"")) {
|
|
searchStr = searchText.mid(1, searchText.size() - 2).toUtf8();
|
|
} else {
|
|
searchStr = QByteArray::fromHex(edit->text().toUtf8());
|
|
}
|
|
|
|
int offset = (int)editor->cursorPosition() / 2;
|
|
|
|
if (searchDown->isChecked()) {
|
|
searchPos = searchFromEnd->isChecked() ? -1 : offset;
|
|
searchNext();
|
|
} else {
|
|
searchPos = searchFromEnd->isChecked() ? editor->editorSize() : offset;
|
|
searchPrev();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MemoryEditor::searchNext() {
|
|
if (searchStr.size() == 0) return;
|
|
|
|
if (searchPos >= editor->editorSize())
|
|
searchPos = (int)editor->cursorPosition() / 2;
|
|
searchPos = editor->indexOf(searchStr, searchPos + 1);
|
|
|
|
if (searchPos >= 0) {
|
|
addr->setText(QString::number(searchPos, 16));
|
|
updateOffset();
|
|
} else {
|
|
QMessageBox::information(this, "Memory Editor", "Reached end of memory.", QMessageBox::Ok);
|
|
searchPos = -1;
|
|
}
|
|
}
|
|
|
|
void MemoryEditor::searchPrev() {
|
|
if (searchStr.size() == 0) return;
|
|
|
|
if (searchPos < 0)
|
|
searchPos = (int)editor->cursorPosition() / 2;
|
|
searchPos = editor->lastIndexOf(searchStr, searchPos - 1);
|
|
|
|
if (searchPos >= 0) {
|
|
addr->setText(QString::number(searchPos, 16));
|
|
updateOffset();
|
|
} else {
|
|
QMessageBox::information(this, "Memory Editor", "Reached beginning of memory.", QMessageBox::Ok);
|
|
searchPos = editor->editorSize();
|
|
}
|
|
}
|
|
|
|
// TODO: export/import expansion chip memory and cartridge RAM/ROM
|
|
void MemoryEditor::exportMemory() {
|
|
string basename = filepath(nall::basename(cartridge.fileName), config().path.data);
|
|
|
|
if(SNES::memory::cartram.size() != 0) {
|
|
exportMemory(SNES::memory::cartram, string() << basename << "-sram.bin");
|
|
}
|
|
exportMemory(SNES::memory::wram, string() << basename << "-wram.bin");
|
|
exportMemory(SNES::memory::apuram, string() << basename << "-apuram.bin");
|
|
exportMemory(SNES::memory::vram, string() << basename << "-vram.bin");
|
|
exportMemory(SNES::memory::oam, string() << basename << "-oam.bin");
|
|
exportMemory(SNES::memory::cgram, string() << basename << "-cgram.bin");
|
|
}
|
|
|
|
void MemoryEditor::importMemory() {
|
|
string basename = filepath(nall::basename(cartridge.fileName), config().path.data);
|
|
|
|
if(SNES::memory::cartram.size() != 0) {
|
|
importMemory(SNES::memory::cartram, string() << basename << "-sram.bin");
|
|
}
|
|
importMemory(SNES::memory::wram, string() << basename << "-wram.bin");
|
|
importMemory(SNES::memory::apuram, string() << basename << "-apuram.bin");
|
|
importMemory(SNES::memory::vram, string() << basename << "-vram.bin");
|
|
importMemory(SNES::memory::oam, string() << basename << "-oam.bin");
|
|
importMemory(SNES::memory::cgram, string() << basename << "-cgram.bin");
|
|
refresh(); //in case import changed values that are currently being displayed ...
|
|
}
|
|
|
|
void MemoryEditor::exportMemory(SNES::Memory &memory, const string &filename) const {
|
|
file fp;
|
|
if(fp.open(filename, file::mode::write)) {
|
|
for(unsigned i = 0; i < memory.size(); i++) fp.write(memory.read(i));
|
|
fp.close();
|
|
}
|
|
}
|
|
|
|
void MemoryEditor::importMemory(SNES::Memory &memory, const string &filename) const {
|
|
file fp;
|
|
if(fp.open(filename, file::mode::read)) {
|
|
unsigned filesize = fp.size();
|
|
for(unsigned i = 0; i < memory.size() && i < filesize; i++) memory.write(i, fp.read());
|
|
fp.close();
|
|
}
|
|
}
|
|
|
|
uint8_t MemoryEditor::reader(unsigned addr) {
|
|
if (SNES::cartridge.loaded()) {
|
|
SNES::debugger.bus_access = true;
|
|
uint8_t data = SNES::debugger.read(memorySource, addr);
|
|
SNES::debugger.bus_access = false;
|
|
return data;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void MemoryEditor::writer(unsigned addr, uint8_t data) {
|
|
if (SNES::cartridge.loaded()) {
|
|
SNES::debugger.bus_access = true;
|
|
SNES::debugger.write(memorySource, addr, data);
|
|
SNES::debugger.bus_access = false;
|
|
}
|
|
}
|
|
|
|
uint8_t MemoryEditor::usage(unsigned addr) {
|
|
if (memorySource == SNES::Debugger::MemorySource::CPUBus && addr < 1 << 24) {
|
|
return SNES::cpu.usage[addr];
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::APUBus && addr < 1 << 16) {
|
|
return SNES::smp.usage[addr];
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::CartROM && addr < 1 << 24) {
|
|
return SNES::cpu.cart_usage[addr];
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::SA1Bus && addr < 1 << 24) {
|
|
return SNES::sa1.usage[addr];
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::SFXBus && addr < 1 << 23) {
|
|
return SNES::superfx.usage[addr];
|
|
}
|
|
else if (memorySource == SNES::Debugger::MemorySource::SGBBus && addr < 1 << 16) {
|
|
return SNES::supergameboy.usage(addr);
|
|
}
|
|
|
|
return 0;
|
|
}
|