From ba959b80c49e6a0c8160f6e013428c1219666502 Mon Sep 17 00:00:00 2001 From: slack Date: Fri, 13 Mar 2009 20:01:31 +0100 Subject: [PATCH] Disassembly and status display in qtboi --- core/MBC.h | 4 ++ core/MBC1.cc | 23 +++++++++ core/MBC1.h | 2 + core/NoMBC.h | 1 + qtboi/CMakeLists.txt | 4 ++ qtboi/QtBoiDisassemblyWindow.cc | 59 +++++++++++++++++++++++ qtboi/QtBoiDisassemblyWindow.h | 26 ++++++++++ qtboi/QtBoiEmuThread.cc | 2 +- qtboi/QtBoiMainWindow.cc | 84 ++++++++++++++++++++++----------- qtboi/QtBoiMainWindow.h | 12 ++++- qtboi/QtBoiStatusWindow.cc | 65 +++++++++++++++++++++++++ qtboi/QtBoiStatusWindow.h | 25 ++++++++++ 12 files changed, 277 insertions(+), 30 deletions(-) create mode 100644 qtboi/QtBoiDisassemblyWindow.cc create mode 100644 qtboi/QtBoiDisassemblyWindow.h create mode 100644 qtboi/QtBoiStatusWindow.cc create mode 100644 qtboi/QtBoiStatusWindow.h diff --git a/core/MBC.h b/core/MBC.h index c265589..2806be6 100644 --- a/core/MBC.h +++ b/core/MBC.h @@ -28,6 +28,10 @@ class MBC virtual u16 read16(u16 addr) const=0; virtual void write (u16 addr, u8 value)=0; virtual ~MBC() {}; + + // return a 32-bit value encoding + // the current ROM/RAM bank and the given address + virtual u32 getUniqueAddress(u16 addr) const=0; }; diff --git a/core/MBC1.cc b/core/MBC1.cc index f3a48b0..b445186 100644 --- a/core/MBC1.cc +++ b/core/MBC1.cc @@ -112,4 +112,27 @@ void MBC1::write(u16 addr, u8 value) } } +u32 MBC1::getUniqueAddress(u16 addr) const +{ + if (addr <= 0x3FFF) // ROM Bank 0 + return addr; + else if (addr <= 0x7FFF) // ROM (switchable) + { + u8 rom_bank = rom_bank_low; + if (mode == ROM_BANKING_MODE) rom_bank |= (ram_bank << 5); + + u32 base = 16384*rom_bank; + return base + (addr-0x4000); + } + else // if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF) + { + if (ram_enabled) + { + u32 base = (mode == RAM_BANKING_MODE ? 8192*ram_bank : 0); + return (base + (addr-0xA000)) | 0x80000000; + } + else return 0; + } + return 0; +} diff --git a/core/MBC1.h b/core/MBC1.h index 418a8c1..be99e1c 100644 --- a/core/MBC1.h +++ b/core/MBC1.h @@ -46,6 +46,8 @@ class MBC1: public MBC u8 read (u16 addr) const; u16 read16(u16 addr) const; void write (u16 addr, u8 value); + + u32 getUniqueAddress(u16 addr) const; }; #endif diff --git a/core/NoMBC.h b/core/NoMBC.h index 08557f9..e4cfc2e 100644 --- a/core/NoMBC.h +++ b/core/NoMBC.h @@ -32,6 +32,7 @@ class NoMBC: public MBC u16 read16(u16 addr) const; void write (u16 addr, u8 value); + u32 getUniqueAddress(u16 addr) const { return addr; } }; #endif diff --git a/qtboi/CMakeLists.txt b/qtboi/CMakeLists.txt index b6c045c..259bff4 100644 --- a/qtboi/CMakeLists.txt +++ b/qtboi/CMakeLists.txt @@ -4,12 +4,16 @@ INCLUDE( ${QT_USE_FILE} ) SET(QTBOI_MOC_HDRS QtBoiMainWindow.h QtBoiEmuThread.h + QtBoiDisassemblyWindow.h + QtBoiStatusWindow.h ) SET(QTBOI_SOURCES qtboi.cc QtBoiMainWindow.cc QtBoiEmuThread.cc + QtBoiDisassemblyWindow.cc + QtBoiStatusWindow.cc ) QT4_WRAP_CPP(QTBOI_MOC_SRCS ${QTBOI_MOC_HDRS}) diff --git a/qtboi/QtBoiDisassemblyWindow.cc b/qtboi/QtBoiDisassemblyWindow.cc new file mode 100644 index 0000000..def4c51 --- /dev/null +++ b/qtboi/QtBoiDisassemblyWindow.cc @@ -0,0 +1,59 @@ +#include +#include +#include + +#include "QtBoiDisassemblyWindow.h" + +QtBoiDisassemblyWindow::QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb) + :gb(gb) +{ + setFocusPolicy(Qt::NoFocus); + setMinimumSize(350,500); +} + +QtBoiDisassemblyWindow::~QtBoiDisassemblyWindow() +{ +} + +void QtBoiDisassemblyWindow::gotoAddress(u16 addr) +{ + int start = addr; + int end = start+200; + int pos = start; + + if (end > 0xFFFF) end = 0xFFFF; + std::ostringstream str; + + str << "Disassembly"; + str << ""; + str << ""; + + bool hilightBG=true; + + while (pos < end) + { + Instruction ins(gb->disassemble_opcode(pos)); + str << ""; + pos += ins.length; + + hilightBG = !hilightBG; + } + + str << "
AddrOpcodesInstruction
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())); +} + +void QtBoiDisassemblyWindow::gotoPC() +{ + gotoAddress(gb->regs.PC); +} + diff --git a/qtboi/QtBoiDisassemblyWindow.h b/qtboi/QtBoiDisassemblyWindow.h new file mode 100644 index 0000000..e83c6d4 --- /dev/null +++ b/qtboi/QtBoiDisassemblyWindow.h @@ -0,0 +1,26 @@ +#ifndef QTBOIDISASSEMBLYWINDOW_H +#define QTBOIDISASSEMBLYWINDOW_H + +#include +#include "../core/GameBoy.h" + +class QtBoiDisassemblyWindow: public QTextBrowser +{ + Q_OBJECT + + public: + QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb); + ~QtBoiDisassemblyWindow(); + + void gotoAddress(u16 addr); + void gotoPC(); + + private: + GameBoy *gb; + +}; + + +#endif + + diff --git a/qtboi/QtBoiEmuThread.cc b/qtboi/QtBoiEmuThread.cc index 37c4c67..5d9287b 100644 --- a/qtboi/QtBoiEmuThread.cc +++ b/qtboi/QtBoiEmuThread.cc @@ -118,7 +118,7 @@ void QtBoiEmuThread::run() { resetRequested = false; gb.load_ROM(romName.toStdString()); - cout << "Loaded ROM " << romName.toStdString() << endl; + if (isPaused) emit emulationPaused(); } if(isPaused) diff --git a/qtboi/QtBoiMainWindow.cc b/qtboi/QtBoiMainWindow.cc index 1e4c70f..af44533 100644 --- a/qtboi/QtBoiMainWindow.cc +++ b/qtboi/QtBoiMainWindow.cc @@ -1,5 +1,3 @@ -#include "QtBoiMainWindow.h" - #include #include #include @@ -7,31 +5,35 @@ #include #include #include +#include +#include #include #include +#include "QtBoiMainWindow.h" + QtBoiMainWindow::QtBoiMainWindow(QWidget *parent) :QMainWindow(parent), emuThread(0) { - screen_image = new QImage(160, 144, QImage::Format_Indexed8); - screen_image->setNumColors(7); + screenImage = new QImage(160, 144, QImage::Format_Indexed8); + screenImage->setNumColors(7); // gray palette - //screen_image->setColor(6, qRgb(0,0,0)); - //screen_image->setColor(5, qRgb(42,42,42)); - //screen_image->setColor(4, qRgb(85,85,85)); - //screen_image->setColor(3, qRgb(127,127,127)); - //screen_image->setColor(2, qRgb(170,170,170)); - //screen_image->setColor(1, qRgb(212,212,212)); - //screen_image->setColor(0, qRgb(255,255,255)); + //screenImage->setColor(6, qRgb(0,0,0)); + //screenImage->setColor(5, qRgb(42,42,42)); + //screenImage->setColor(4, qRgb(85,85,85)); + //screenImage->setColor(3, qRgb(127,127,127)); + //screenImage->setColor(2, qRgb(170,170,170)); + //screenImage->setColor(1, qRgb(212,212,212)); + //screenImage->setColor(0, qRgb(255,255,255)); // greenish palette - screen_image->setColor(6, qRgb(64,64,64)); - screen_image->setColor(5, qRgb(82,82,53)); - screen_image->setColor(4, qRgb(101,101,42)); - screen_image->setColor(3, qRgb(120,120,31)); - screen_image->setColor(2, qRgb(139,139,21)); - screen_image->setColor(1, qRgb(166,166,10)); - screen_image->setColor(0, qRgb(192,192,0)); + screenImage->setColor(6, qRgb(64,64,64)); + screenImage->setColor(5, qRgb(82,82,53)); + screenImage->setColor(4, qRgb(101,101,42)); + screenImage->setColor(3, qRgb(120,120,31)); + screenImage->setColor(2, qRgb(139,139,21)); + screenImage->setColor(1, qRgb(166,166,10)); + screenImage->setColor(0, qRgb(192,192,0)); emuThread = new QtBoiEmuThread(this); emuThread->start(); @@ -54,8 +56,11 @@ QtBoiMainWindow::QtBoiMainWindow(QWidget *parent) createMenu(); createToolbar(); + statusbar = statusBar(); + connect(emulatorCont, SIGNAL(triggered()), emuThread, SLOT(cont())); + connect(emulatorCont, SIGNAL(triggered()), this, SLOT(onResume())); connect(emulatorStop, SIGNAL(triggered()), emuThread, SLOT(stop())); connect(emulatorPause, SIGNAL(triggered()), emuThread, SLOT(pause())); connect(emulatorStep, SIGNAL(triggered()), emuThread, SLOT(step())); @@ -63,22 +68,40 @@ QtBoiMainWindow::QtBoiMainWindow(QWidget *parent) connect(emuThread, SIGNAL(redraw(const uchar*)), this, SLOT(onRedraw(const uchar*))); connect(emuThread, SIGNAL(emulationPaused()), this, SLOT(onPause())); - resize(640,480); + resize(800,600); centralWindow = new QWidget(this); setCentralWidget(centralWindow); - QVBoxLayout *vbox = new QVBoxLayout(centralWindow); + QHBoxLayout *topHBoxLayout = new QHBoxLayout; + + QWidget *leftVBox = new QWidget(centralWindow); + QWidget *rightVBox = new QWidget(centralWindow); + QVBoxLayout *leftVBoxLayout = new QVBoxLayout; + QVBoxLayout *rightVBoxLayout = new QVBoxLayout; + leftVBox->setLayout(leftVBoxLayout); + rightVBox->setLayout(rightVBoxLayout); screen = new QLabel(centralWindow); screen->resize(320,288); + uchar buf[160*144]; + memset(buf, 0, 160*144); + onRedraw(buf); - status = new QLabel; + status = new QtBoiStatusWindow(centralWindow, &emuThread->gb); status->setFont(QFont("courier")); - vbox->addWidget(screen); - vbox->addWidget(status); + topHBoxLayout->addWidget(leftVBox); + topHBoxLayout->addWidget(rightVBox); + leftVBoxLayout->addWidget(screen); + leftVBoxLayout->addWidget(status); + + disassembly = new QtBoiDisassemblyWindow(centralWindow, &emuThread->gb); + disassembly->setOpenLinks(false); + disassembly->setFont(QFont("courier")); + + rightVBoxLayout->addWidget(disassembly); - centralWindow->setLayout(vbox); + centralWindow->setLayout(topHBoxLayout); } @@ -129,21 +152,28 @@ void QtBoiMainWindow::onLoadROM() if (filename == "") return; emuThread->loadROM(filename); - + statusbar->showMessage(tr("Loaded ROM ")+filename); } void QtBoiMainWindow::onRedraw(const uchar *buffer) { - uchar *pixels = screen_image->bits(); + uchar *pixels = screenImage->bits(); memcpy(pixels, buffer, 160*144); - screen->setPixmap(QPixmap::fromImage(screen_image->scaled(320,288))); + screen->setPixmap(QPixmap::fromImage(screenImage->scaled(320,288))); } void QtBoiMainWindow::onPause() { status->setText(QString(emuThread->gb.status_string().c_str())); + disassembly->gotoPC(); + status->update(); + statusbar->showMessage(tr("Emulation paused", "Status bar emulation paused msg")); } +void QtBoiMainWindow::onResume() +{ + statusbar->showMessage(tr("Emulation running", "Status bar emulation running msg")); +} void QtBoiMainWindow::keyPressEvent(QKeyEvent *event) { diff --git a/qtboi/QtBoiMainWindow.h b/qtboi/QtBoiMainWindow.h index 29f3e16..9314f86 100644 --- a/qtboi/QtBoiMainWindow.h +++ b/qtboi/QtBoiMainWindow.h @@ -7,7 +7,12 @@ #include #include #include +#include +#include + #include "QtBoiEmuThread.h" +#include "QtBoiDisassemblyWindow.h" +#include "QtBoiStatusWindow.h" class QtBoiMainWindow: public QMainWindow { @@ -21,6 +26,7 @@ class QtBoiMainWindow: public QMainWindow void onLoadROM(); void onRedraw(const uchar *buffer); void onPause(); + void onResume(); private: // private functions @@ -35,8 +41,10 @@ class QtBoiMainWindow: public QMainWindow QWidget *centralWindow; QLabel *screen; - QImage *screen_image; - QLabel *status; + QImage *screenImage; + QStatusBar *statusbar; + QtBoiDisassemblyWindow *disassembly; + QtBoiStatusWindow *status; QAction *loadROM; QAction *quit; diff --git a/qtboi/QtBoiStatusWindow.cc b/qtboi/QtBoiStatusWindow.cc new file mode 100644 index 0000000..25348dd --- /dev/null +++ b/qtboi/QtBoiStatusWindow.cc @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "QtBoiStatusWindow.h" + +QtBoiStatusWindow::QtBoiStatusWindow(QWidget *parent, GameBoy *gb) + :gb(gb) +{ + setFocusPolicy(Qt::NoFocus); + setMinimumSize(200,200); +} + +QtBoiStatusWindow::~QtBoiStatusWindow() +{ +} + +void QtBoiStatusWindow::update() +{ + std::ostringstream str; + + str << "Status"; + + str << "
"; + // 8-bit regs table + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << "
8-bit
A = 0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.A) << "
B = 0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.B) << "
C = 0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.C) << "
D = 0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.D) << "
E = 0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.E) << "
H = 0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.H) << "
L = 0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.L) << "
"; + str << "
"; + // 16-bit regs table + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << "
16-bit
BC = 0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.BC) << "
DE = 0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.DE) << "
HL = 0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.HL) << "
SP = 0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.SP) << "
PC = 0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.PC) << "
"; + str << "
"; + // Flags & state table (TODO: Interpret IE and IF registers) + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << ""; + str << "
Flags
Z
N
H
C
IME = " << int(gb->IME) << "
IE  = " << int(gb->memory.read(0xFFFF, GBMemory::DONT_WATCH)) << "
IF  = " << int(gb->memory.read(0xFF0F, GBMemory::DONT_WATCH)) << "
"; + + setHtml(QString(str.str().c_str())); +} + + diff --git a/qtboi/QtBoiStatusWindow.h b/qtboi/QtBoiStatusWindow.h new file mode 100644 index 0000000..a1bda3f --- /dev/null +++ b/qtboi/QtBoiStatusWindow.h @@ -0,0 +1,25 @@ +#ifndef QTBOISTATUSWINDOW_H +#define QTBOISTATUSWINDOW_H + +#include +#include "../core/GameBoy.h" + +class QtBoiStatusWindow: public QTextBrowser +{ + Q_OBJECT + + public: + QtBoiStatusWindow(QWidget *parent, GameBoy *gb); + ~QtBoiStatusWindow(); + + void update(); + + private: + GameBoy *gb; + +}; + + +#endif + + -- 2.34.1