qtboi disassembly window is somewhat browseable now, addresses in disassembly can...
authorslack <slack@codemaniacs.com>
Sat, 14 Mar 2009 19:26:30 +0000 (20:26 +0100)
committerslack <slack@codemaniacs.com>
Sat, 14 Mar 2009 19:26:30 +0000 (20:26 +0100)
common/toString.h
qtboi/QtBoiDisassemblyWindow.cc
qtboi/QtBoiDisassemblyWindow.h
qtboi/QtBoiEmuThread.cc
qtboi/QtBoiMainWindow.cc
qtboi/QtBoiMainWindow.h
qtboi/QtBoiStatusWindow.cc

index bf47b03aecfc57ac8433e8d449473669569b1891..df5692ab3bef2eaa3ae5ff72c041054cd2d0847c 100644 (file)
@@ -29,5 +29,13 @@ std::string toString(const T &object)
        return(os.str());
 }
 
+template <class T> 
+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
 
index def4c517ca36f2f25d496534203c936443e9f0ed..81592e5e81f8c6055a048dda2c12c666bd36fa36 100644 (file)
@@ -3,18 +3,84 @@
 #include <iomanip>
 
 #include "QtBoiDisassemblyWindow.h"
+#include "../common/toString.h"
 
-QtBoiDisassemblyWindow::QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb)
-        :gb(gb)
+QtBoiDisassemblyWindow::QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb, QHash<u32,QString> *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("<a href=\"gotoaddr:");
+       result += toString(addr);
+       result += "\">";
+       if (tags->value(addr) != "")
+               result += tags->value(addr).toStdString();
+       else
+               result += toStringHex(addr, 4);
+       result += "</a>";
+
+       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 << "<html><head><title>Disassembly</title></head><body>";
         str << "<table cellpadding=0 cellspacing=0>";
-        str << "<tr bgcolor=#c0ffc0><td width=25%>Addr</td><td width=25%>Opcodes</td><td>Instruction</td></tr>";
+        str << "<tr bgcolor=#c0ffc0><td width=25%>Labels</td><td width=15%>Addr</td><td width=15%>Opcodes</td><td>Instruction</td></tr>";
 
         bool hilightBG=true;
 
         while (pos < end)
         {
                 Instruction ins(gb->disassemble_opcode(pos));
-                str << "<tr bgcolor=" << (pos == gb->regs.PC ? "#ffc0c0" : (hilightBG ? "#d0d0d0" : "#ffffff")) << 
-                        "><td>0x" << std::hex << std::setw(4) << std::setfill('0') << 
-                        pos << "</td><td>";
+                str << "<tr bgcolor=" << (pos == gb->regs.PC ? "#ffc0c0" : (hilightBG ? "#d0d0d0" : "#ffffff")) << ">" <<
+                       "<td>" << tags->value(pos).toStdString() << "</td>" <<
+                       "<td><a href=\"newtag:" << std::dec << pos << "\">0x" << std::hex << std::setw(4) << std::setfill('0') << 
+                        pos << "</a></td><td>";
                 for (int i=0; i<ins.length; i++)
                         str << std::setw(2) << int(gb->memory.read(pos+i)) << " ";
 
                 str << "</td><td>";
 
-                str << ins.all << "</td></tr>";
+                str << insToHtml(ins) << "</td></tr>";
                 pos += ins.length;
 
                 hilightBG = !hilightBG;
@@ -50,6 +117,7 @@ void QtBoiDisassemblyWindow::gotoAddress(u16 addr)
         str << "</table></body></html>";
 
         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);
+}
+
+
+
index e83c6d454135eda78a9241d0e2f71ff042e34924..5b4c180251e52df08f1c6ff706bb1a7b4226e3d0 100644 (file)
@@ -2,6 +2,8 @@
 #define QTBOIDISASSEMBLYWINDOW_H
 
 #include <QTextBrowser>
+#include <QString>
+#include <QHash>
 #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<u32, QString> *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<u32, QString> *tags;
+
+               u16 currentAddress;
 
 };
 
index 5d9287bef89da800bca25337d9717864596487f8..92a4e89fbf647742a3c6ccf7c9feeb6fda5256b9 100644 (file)
@@ -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();
                }
 
index af44533ebc3742c5a54b7d4792214a902fb65c91..fd5c0457271efd77fe06882fb9b37d40639c4358 100644 (file)
@@ -3,14 +3,20 @@
 #include <QToolBar>
 #include <QString>
 #include <QFileDialog>
+#include <QInputDialog>
 #include <QPushButton>
 #include <QColor>
 #include <QGroupBox>
 #include <QHBoxLayout>
 #include <QVBoxLayout>
+#include <QFile>
+#include <QTextStream>
+
 #include <iostream>
 
 #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<u32,QString> i(tags);
+       while (i.hasNext())
+       {
+               i.next();
+               out << i.key() << " " << i.value() << "\n";
+       }
+}
+
+
index 9314f86a28ef56fe93473261db1d8022d84d57cd..e47f98a7d2c2f4f980ede8d83f4ba52f62711a27 100644 (file)
@@ -9,6 +9,9 @@
 #include <QLabel>
 #include <QStatusBar>
 #include <QTextBrowser>
+#include <QString>
+#include <QUrl>
+#include <QHash>
 
 #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<u32, QString> tags;
 
                QWidget *centralWindow;
                QLabel  *screen;
index 25348ddb63efbda696e2c3de421210cef038485c..53f40c5b11ac8fec6d43883cf186673a5fc47304 100644 (file)
@@ -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 << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::HALF_CARRY_FLAG)? "#FF0000" : "#FFFFFF") << ">H</td></tr>";
         str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::CARRY_FLAG)? "#FF0000" : "#FFFFFF") << ">C</td></tr>";
        str << "<tr><td>IME&nbsp;=&nbsp;" << int(gb->IME) << "</td></tr>";
-       str << "<tr><td>IE&nbsp;&nbsp;=&nbsp;" << int(gb->memory.read(0xFFFF, GBMemory::DONT_WATCH)) << "</td></tr>";
-       str << "<tr><td>IF&nbsp;&nbsp;=&nbsp;" << int(gb->memory.read(0xFF0F, GBMemory::DONT_WATCH)) << "</td></tr>";
+       int IE = int(gb->memory.read(0xFFFF, GBMemory::DONT_WATCH));
+       str << "<tr><td>IE&nbsp;&nbsp;=";
+       if (IE & GameBoy::IRQ_VBLANK)   str << "&nbsp;VBL";
+       if (IE & GameBoy::IRQ_LCD_STAT) str << "&nbsp;LCD";
+       if (IE & GameBoy::IRQ_TIMER)    str << "&nbsp;TIM";
+       if (IE & GameBoy::IRQ_SERIAL)   str << "&nbsp;SER";
+       if (IE & GameBoy::IRQ_JOYPAD)   str << "&nbsp;JOYP";
+       str << "</td></tr>";
+       int IF = int(gb->memory.read(0xFF0F, GBMemory::DONT_WATCH));
+       str << "<tr><td>IF&nbsp;&nbsp;=";
+       if (IF & GameBoy::IRQ_VBLANK)   str << "&nbsp;VBL";
+       if (IF & GameBoy::IRQ_LCD_STAT) str << "&nbsp;LCD";
+       if (IF & GameBoy::IRQ_TIMER)    str << "&nbsp;TIM";
+       if (IF & GameBoy::IRQ_SERIAL)   str << "&nbsp;SER";
+       if (IF & GameBoy::IRQ_JOYPAD)   str << "&nbsp;JOYP";
+       str << "</td></tr>";
+       str << "</table>";
         str << "</td></tr>";
         str << "</table></body></html>";