From 8536fac912d9123919274ae2dab53640612bb2c0 Mon Sep 17 00:00:00 2001 From: slack Date: Sat, 14 Mar 2009 20:26:30 +0100 Subject: [PATCH] qtboi disassembly window is somewhat browseable now, addresses in disassembly can be tagged via GUI --- common/toString.h | 8 +++ qtboi/QtBoiDisassemblyWindow.cc | 91 ++++++++++++++++++++++++++++++--- qtboi/QtBoiDisassemblyWindow.h | 12 ++++- qtboi/QtBoiEmuThread.cc | 5 +- qtboi/QtBoiMainWindow.cc | 80 ++++++++++++++++++++++++++++- qtboi/QtBoiMainWindow.h | 10 ++++ qtboi/QtBoiStatusWindow.cc | 20 +++++++- 7 files changed, 211 insertions(+), 15 deletions(-) diff --git a/common/toString.h b/common/toString.h index bf47b03..df5692a 100644 --- a/common/toString.h +++ b/common/toString.h @@ -29,5 +29,13 @@ std::string toString(const T &object) return(os.str()); } +template +std::string toStringHex(const T &object, int width) +{ + std::ostringstream os; + os << "0x" << std::hex << std::setw(width) << std::setfill('0') << object; + return(os.str()); +} + #endif diff --git a/qtboi/QtBoiDisassemblyWindow.cc b/qtboi/QtBoiDisassemblyWindow.cc index def4c51..81592e5 100644 --- a/qtboi/QtBoiDisassemblyWindow.cc +++ b/qtboi/QtBoiDisassemblyWindow.cc @@ -3,18 +3,84 @@ #include #include "QtBoiDisassemblyWindow.h" +#include "../common/toString.h" -QtBoiDisassemblyWindow::QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb) - :gb(gb) +QtBoiDisassemblyWindow::QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb, QHash *tags) + :gb(gb), tags(tags) { setFocusPolicy(Qt::NoFocus); - setMinimumSize(350,500); + setMinimumSize(500,500); } QtBoiDisassemblyWindow::~QtBoiDisassemblyWindow() { } +std::string QtBoiDisassemblyWindow::htmlLinkMem(u32 addr) +{ + std::string result(""; + if (tags->value(addr) != "") + result += tags->value(addr).toStdString(); + else + result += toStringHex(addr, 4); + result += ""; + + return result; +} + +std::string QtBoiDisassemblyWindow::operandToHtml(const Instruction::Operand &op) +{ + std::string result; + switch(op.type) + { + case Instruction::MEM_DIRECT: + result += "("; + result += htmlLinkMem(op.val); + result += ")"; + break; + + case Instruction::INM16: + result += toStringHex(op.val,4); + break; + + default: + return op.str; + } + + return result; +} + + +std::string QtBoiDisassemblyWindow::insToHtml(const Instruction &ins) +{ + + std::string result(ins.str); + result += " "; + if (ins.str.substr(0,2)=="JR") + { + result += operandToHtml(ins.op1); + result += " ["; + result += htmlLinkMem(ins.op2.val); + result += "]"; + } + else if (ins.str.substr(0,2)=="JP" || ins.str.substr(0,4)=="CALL") + { + result += htmlLinkMem(ins.op1.val); + } + else + { + result += operandToHtml(ins.op1); + if (ins.op2.type != Instruction::NONE) + { + result += ", "; + result += operandToHtml(ins.op2); + } + } + return result; +} + void QtBoiDisassemblyWindow::gotoAddress(u16 addr) { int start = addr; @@ -26,22 +92,23 @@ void QtBoiDisassemblyWindow::gotoAddress(u16 addr) str << "Disassembly"; str << ""; - str << ""; + str << ""; bool hilightBG=true; while (pos < end) { Instruction ins(gb->disassemble_opcode(pos)); - str << "" << + "" << + ""; + str << insToHtml(ins) << ""; pos += ins.length; hilightBG = !hilightBG; @@ -50,6 +117,7 @@ void QtBoiDisassemblyWindow::gotoAddress(u16 addr) str << "
AddrOpcodesInstruction
LabelsAddrOpcodesInstruction
0x" << std::hex << std::setw(4) << std::setfill('0') << - pos << ""; + str << "
" << tags->value(pos).toStdString() << "0x" << std::hex << std::setw(4) << std::setfill('0') << + pos << ""; for (int i=0; imemory.read(pos+i)) << " "; str << ""; - str << ins.all << "
"; setHtml(QString(str.str().c_str())); + currentAddress=addr; } void QtBoiDisassemblyWindow::gotoPC() @@ -57,3 +125,10 @@ void QtBoiDisassemblyWindow::gotoPC() gotoAddress(gb->regs.PC); } +void QtBoiDisassemblyWindow::refresh() +{ + gotoAddress(currentAddress); +} + + + diff --git a/qtboi/QtBoiDisassemblyWindow.h b/qtboi/QtBoiDisassemblyWindow.h index e83c6d4..5b4c180 100644 --- a/qtboi/QtBoiDisassemblyWindow.h +++ b/qtboi/QtBoiDisassemblyWindow.h @@ -2,6 +2,8 @@ #define QTBOIDISASSEMBLYWINDOW_H #include +#include +#include #include "../core/GameBoy.h" class QtBoiDisassemblyWindow: public QTextBrowser @@ -9,14 +11,22 @@ class QtBoiDisassemblyWindow: public QTextBrowser Q_OBJECT public: - QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb); + QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb, QHash *tags); ~QtBoiDisassemblyWindow(); void gotoAddress(u16 addr); void gotoPC(); + void refresh(); private: + std::string insToHtml(const Instruction &ins); + std::string operandToHtml(const Instruction::Operand &ins); + std::string htmlLinkMem(u32 addr); GameBoy *gb; + QString romTitle; + QHash *tags; + + u16 currentAddress; }; diff --git a/qtboi/QtBoiEmuThread.cc b/qtboi/QtBoiEmuThread.cc index 5d9287b..92a4e89 100644 --- a/qtboi/QtBoiEmuThread.cc +++ b/qtboi/QtBoiEmuThread.cc @@ -59,8 +59,9 @@ QtBoiEmuThread::~QtBoiEmuThread() void QtBoiEmuThread::loadROM(QString name) { + pause(); romName=name; - reset(); + gb.load_ROM(romName.toStdString()); romLoaded=true; } @@ -117,7 +118,7 @@ void QtBoiEmuThread::run() if(resetRequested) { resetRequested = false; - gb.load_ROM(romName.toStdString()); + gb.reset(); if (isPaused) emit emulationPaused(); } diff --git a/qtboi/QtBoiMainWindow.cc b/qtboi/QtBoiMainWindow.cc index af44533..fd5c045 100644 --- a/qtboi/QtBoiMainWindow.cc +++ b/qtboi/QtBoiMainWindow.cc @@ -3,14 +3,20 @@ #include #include #include +#include #include #include #include #include #include +#include +#include + #include #include "QtBoiMainWindow.h" +#include "../core/GameBoy.h" +#include "../core/GBRom.h" QtBoiMainWindow::QtBoiMainWindow(QWidget *parent) :QMainWindow(parent), emuThread(0) @@ -48,6 +54,7 @@ QtBoiMainWindow::QtBoiMainWindow(QWidget *parent) loadROM->setShortcut(QKeySequence(tr("Ctrl+O", "File|Load ROM..."))); emulatorCont->setShortcut(QKeySequence(tr("F5", "Emulator|Go"))); + emulatorPause->setShortcut(QKeySequence(tr("F6", "Emulator|Pause"))); emulatorStep->setShortcut(QKeySequence(tr("F7", "Debug|Step"))); //emulatorCont->setIcon(QIcon("../icons/player_play.svg")); //emulatorPause->setIcon(QIcon("../icons/player_pause.svg")); @@ -95,9 +102,11 @@ QtBoiMainWindow::QtBoiMainWindow(QWidget *parent) leftVBoxLayout->addWidget(screen); leftVBoxLayout->addWidget(status); - disassembly = new QtBoiDisassemblyWindow(centralWindow, &emuThread->gb); + disassembly = new QtBoiDisassemblyWindow(centralWindow, &emuThread->gb, &tags); disassembly->setOpenLinks(false); disassembly->setFont(QFont("courier")); + + connect(disassembly, SIGNAL(anchorClicked(const QUrl&)), this, SLOT(onDisassemblyAnchorClicked(const QUrl&))); rightVBoxLayout->addWidget(disassembly); @@ -107,6 +116,9 @@ QtBoiMainWindow::QtBoiMainWindow(QWidget *parent) QtBoiMainWindow::~QtBoiMainWindow() { + if (romTitle != "") + saveTags(); + if (emuThread) { emuThread->stop(); emuThread->wait(); @@ -148,11 +160,37 @@ void QtBoiMainWindow::createToolbar() void QtBoiMainWindow::onLoadROM() { + saveTags(); + QString filename = QFileDialog::getOpenFileName(this, tr("Load ROM"), "../roms", tr("GameBoy ROMs (*.gb *.gbc)")); if (filename == "") return; emuThread->loadROM(filename); - statusbar->showMessage(tr("Loaded ROM ")+filename); + + char title[12]; + memcpy(title, emuThread->gb.rom->header.new_title, 11); + title[11]='\0'; + romTitle=QString(title); + loadTags(); + + statusbar->showMessage(tr("Loaded ROM ")+filename+" ["+romTitle+"]"); +} + +void QtBoiMainWindow::onDisassemblyAnchorClicked(const QUrl& url) +{ + std::cout << url.toString().toStdString() << std::endl; + if (url.scheme() == "gotoaddr") { + u32 addr = url.path().toUInt(); + disassembly->gotoAddress(addr); + } + else if (url.scheme() == "newtag") { + u32 addr = url.path().toUInt(); + QString tag = QInputDialog::getText(this, tr("Create new tag"), tr("Enter the tag for the selected address"), + QLineEdit::Normal, tags[addr]); + + tags[addr] = tag; + disassembly->refresh(); + } } void QtBoiMainWindow::onRedraw(const uchar *buffer) @@ -252,3 +290,41 @@ void QtBoiMainWindow::keyReleaseEvent(QKeyEvent *event) +void QtBoiMainWindow::loadTags() +{ + this->romTitle = romTitle; + tags.clear(); + QFile tagsfile(romTitle+".tags"); + if (!tagsfile.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QTextStream in(&tagsfile); + while(!in.atEnd()) + { + u32 addr; + QString tag; + + in >> addr; + in.skipWhiteSpace(); + tag = in.readLine(); + + tags[addr] = tag; + } +} + +void QtBoiMainWindow::saveTags() +{ + QFile tagsfile(romTitle+".tags"); + if (!tagsfile.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + + QTextStream out(&tagsfile); + QHashIterator i(tags); + while (i.hasNext()) + { + i.next(); + out << i.key() << " " << i.value() << "\n"; + } +} + + diff --git a/qtboi/QtBoiMainWindow.h b/qtboi/QtBoiMainWindow.h index 9314f86..e47f98a 100644 --- a/qtboi/QtBoiMainWindow.h +++ b/qtboi/QtBoiMainWindow.h @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include "QtBoiEmuThread.h" #include "QtBoiDisassemblyWindow.h" @@ -24,6 +27,7 @@ class QtBoiMainWindow: public QMainWindow public slots: void onLoadROM(); + void onDisassemblyAnchorClicked(const QUrl&); void onRedraw(const uchar *buffer); void onPause(); void onResume(); @@ -33,11 +37,17 @@ class QtBoiMainWindow: public QMainWindow void createMenu(); void createToolbar(); + void loadTags(); + void saveTags(); + // events void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); QtBoiEmuThread *emuThread; + + QString romTitle; + QHash tags; QWidget *centralWindow; QLabel *screen; diff --git a/qtboi/QtBoiStatusWindow.cc b/qtboi/QtBoiStatusWindow.cc index 25348dd..53f40c5 100644 --- a/qtboi/QtBoiStatusWindow.cc +++ b/qtboi/QtBoiStatusWindow.cc @@ -9,6 +9,7 @@ QtBoiStatusWindow::QtBoiStatusWindow(QWidget *parent, GameBoy *gb) { setFocusPolicy(Qt::NoFocus); setMinimumSize(200,200); + setMaximumWidth(320); } QtBoiStatusWindow::~QtBoiStatusWindow() @@ -54,8 +55,23 @@ void QtBoiStatusWindow::update() str << "H"; str << "C"; str << "IME = " << int(gb->IME) << ""; - str << "IE  = " << int(gb->memory.read(0xFFFF, GBMemory::DONT_WATCH)) << ""; - str << "IF  = " << int(gb->memory.read(0xFF0F, GBMemory::DONT_WATCH)) << ""; + int IE = int(gb->memory.read(0xFFFF, GBMemory::DONT_WATCH)); + str << "IE  ="; + if (IE & GameBoy::IRQ_VBLANK) str << " VBL"; + if (IE & GameBoy::IRQ_LCD_STAT) str << " LCD"; + if (IE & GameBoy::IRQ_TIMER) str << " TIM"; + if (IE & GameBoy::IRQ_SERIAL) str << " SER"; + if (IE & GameBoy::IRQ_JOYPAD) str << " JOYP"; + str << ""; + int IF = int(gb->memory.read(0xFF0F, GBMemory::DONT_WATCH)); + str << "IF  ="; + if (IF & GameBoy::IRQ_VBLANK) str << " VBL"; + if (IF & GameBoy::IRQ_LCD_STAT) str << " LCD"; + if (IF & GameBoy::IRQ_TIMER) str << " TIM"; + if (IF & GameBoy::IRQ_SERIAL) str << " SER"; + if (IF & GameBoy::IRQ_JOYPAD) str << " JOYP"; + str << ""; + str << ""; str << ""; str << ""; -- 2.34.1