Qt window for emulation control.
authorslack <slack@codemaniacs.com>
Thu, 12 Mar 2009 23:21:59 +0000 (00:21 +0100)
committerslack <slack@codemaniacs.com>
Thu, 12 Mar 2009 23:21:59 +0000 (00:21 +0100)
Coming soon: Debug GUI :)

12 files changed:
CMakeLists.txt
common/Logger.h
core/GBMemory.h
core/GBVideo.cc
core/GBVideo.h
core/GameBoy.cc
core/GameBoy.h
qtboi/QtBoiEmuThread.cc
qtboi/QtBoiEmuThread.h
qtboi/QtBoiMainWindow.cc
qtboi/QtBoiMainWindow.h
wendi/wendi.cc

index 201bfd28b1191197513e04f252f544fbc491eff6..2640704b11e8ec86693199d7031831df63ede0ce 100644 (file)
@@ -3,3 +3,5 @@ PROJECT(wenboi)
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0)
 
 ADD_SUBDIRECTORY(core)
+ADD_SUBDIRECTORY(qtboi)
+ADD_SUBDIRECTORY(wendi)
index f40261920d4b4d49e241c66d17e2780ad5261a7a..c1fc48da3d52e8183bb0e213f4e4387a6e33f675 100644 (file)
@@ -19,6 +19,7 @@
 #define LOGGER_H
 
 #include <string>
+#include <fstream>
 #include <iostream>
 #include <sstream>
 #include <ctime>
@@ -46,8 +47,6 @@ class Logger: public Singleton<Logger>
                        out << "Starting log at " << static_cast<long>(log_start_time) << std::endl;
                }
 
-               //void setOutput(std::ostream os) { out = os; }
-
                void log(log_level level, std::string str)
                {
                        if (level <= current_log_level)
@@ -104,7 +103,7 @@ class Logger: public Singleton<Logger>
 
                void set_log_level (log_level level) { current_log_level = level; }
        private:
-               std::ostreamout;
+               std::ostream &out;
                log_level current_log_level;
                time_t log_start_time;
 };
index 10a959269bf47276cdccc4beeb453c20633b42b3..37a7cdb80f357be845ae7f3a3d4c4391716b2d47 100644 (file)
@@ -88,9 +88,12 @@ class GBMemory
                                                        watchpoint_oldvalue(0),
                                                        watchpoint_newvalue(0)
                                                        {}
+
+
        void init(MBC *mbc) { this->mbc = mbc; }
 
 
+
        enum WatchpointControl
        {
                WATCH=0,
index f4e112b61d399761106cfd63f22abf64b50b0c19..1aa19ed7d9d45df14b5ade43830c7b2f77c0c1b6 100644 (file)
@@ -18,6 +18,7 @@
 #include <iostream>
 #include <algorithm>
 #include <vector>
+#include <cstring>
 
 #include "GBVideo.h"
 #include "GameBoy.h"
index 0d0c0d5ea7296c3f29e30c1fa9300231fc94e7cd..34197b9853ee20a177e8a5dfa7b7e4ee8c9fcfcd 100644 (file)
@@ -103,7 +103,7 @@ class GBVideo
        void set_display_mode(DisplayMode mode) { display_mode = mode; }
 
        // status queries
-       u32 get_frames_rendered() { return frames_rendered; }
+       u32 get_frames_rendered() const { return frames_rendered; }
        
        // prevent object copying
        private:
index ad53ce1864048de18abe643710d224d9cd1d622b..d634d13f416c5450b6c64c15e3090523b34e726f 100644 (file)
@@ -30,7 +30,7 @@
 
 bool GameBoy::is_pad[NUM_CONTROLS]={false, false, false, false, true, true, true, true};
 
-GameBoy::GameBoy(std::string rom_name, GameBoyType type):
+GameBoy::GameBoy(GameBoyType type):
        gameboy_type(type),
        memory(this),
        video(this),
@@ -46,6 +46,16 @@ GameBoy::GameBoy(std::string rom_name, GameBoyType type):
        breakpoints(),
        last_breakpoint_id(0)
 {
+}
+
+GameBoy::~GameBoy()
+{
+       free_ROM();
+}
+
+void GameBoy::load_ROM(std::string rom_name)
+{
+       free_ROM();
        logger.info("GameBoy init");
        rom = read_gbrom(rom_name);
 
@@ -55,6 +65,13 @@ GameBoy::GameBoy(std::string rom_name, GameBoyType type):
        reset();
 }
 
+
+void GameBoy::free_ROM()
+{
+       ::operator delete(reinterpret_cast<void*>(rom));
+       ::operator delete(reinterpret_cast<void*>(memory.mbc));
+}
+       
 void GameBoy::reset()
 {
        logger.info("GameBoy reset");
@@ -62,6 +79,9 @@ void GameBoy::reset()
        HALT = 0;
        cycle_count = 0;
        cycles_until_next_instruction = 0;
+       
+       for (int i=0; i<NUM_CONTROLS; i++)
+               controls[i]=false;
 
        video.reset();
 
@@ -127,8 +147,6 @@ void GameBoy::reset()
        memory.write(0xFF4B, 0x00);   // WX
        memory.write(0xFFFF, 0x00);   // IE
 
-       for (int i=0; i<NUM_CONTROLS; i++)
-               controls[i]=false;
 }
 
 int GameBoy::set_breakpoint(u16 addr)
index e96217d715aa4fd08ca2f96d0990072b027a1276..cef00d51cc2bd82dc409c8a0ec905b47a22f0d18 100644 (file)
@@ -54,6 +54,7 @@ class GameBoy
                        BREAKPOINT,
                        WATCHPOINT,
                        TRACEPOINT,
+                       STEP,
                        PAUSED,
                        QUIT,
                        WAIT,
@@ -67,8 +68,11 @@ class GameBoy
                        IRQ_JOYPAD   = 0x10,
                };
 
-               // Constructors
-               GameBoy(std::string rom_name, GameBoyType type=GAMEBOY);
+               // Constructors / destructors
+               GameBoy(GameBoyType type=GAMEBOY);
+               ~GameBoy();
+
+               void load_ROM(std::string rom_name);
 
                // running control methods
                void irq(InterruptRequest i) { memory.write(0xFF0F, memory.read(0xFF0F) | i); }
@@ -93,7 +97,6 @@ class GameBoy
                Instruction disassemble_opcode(u16 addr);
                static std::string get_port_name(int port);
        
-       private:
                friend class GBMemory;
                friend class GBVideo;
                GBMemory memory;
@@ -140,6 +143,10 @@ class GameBoy
 
                } regs;
 
+               void set_flag  (Flag f) { regs.flags |= f; }
+               void reset_flag(Flag f) { regs.flags &= (~f); }
+               int check_flag(Flag f) const { return ((regs.flags & f) != 0 ? 1 : 0); }
+               
 
                u8 IME; // Interrupt master enable flag
                u8 HALT; // Is the CPU halted waiting for an interrupt?
@@ -150,7 +157,8 @@ class GameBoy
                u8  divider_count; // resets every 256 cycles, so we don't need a cmp
                u32 timer_count;
                static const u32 CYCLE_STEP = 4;
-               
+       
+        private:
                inline void do_call(u16 addr)
                {
                        logger.debug("do_call(0x", std::hex, std::setw(4), std::setfill('0'), addr, ")");
@@ -160,16 +168,15 @@ class GameBoy
                        regs.PC = addr; 
                }
 
-               void set_flag  (Flag f) { regs.flags |= f; }
-               void reset_flag(Flag f) { regs.flags &= (~f); }
-               int check_flag(Flag f) const { return ((regs.flags & f) != 0 ? 1 : 0); }
-               
                // prevent object copying
                GameBoy(const GameBoy&);
                GameBoy operator=(const GameBoy&);
 
                // update JOYP register when controls are pushed/released
                void update_JOYP();
+
+               // free ROM (used in destructor and load_rom)
+               void free_ROM();
                
                // debug things
                struct Breakpoint {
index 260ba91b63d83618dc7b17c4aaa4cae0e40ec96d..d6a26a7f3c9f70624ff919569841794dc0ce36b4 100644 (file)
@@ -40,25 +40,38 @@ void print_run_result(GameBoy &gb, int status)
 }
 
 
-QtBoiEmuThread::QtBoiEmuThread(QObject *parent, QString romName)
-       :QThread(parent)
+QtBoiEmuThread::QtBoiEmuThread(QObject *parent)
+       :QThread(parent),
+       status(GameBoy::NORMAL),
+       isPaused(true),
+       frameCount(0),
+       romName(),
+       runningMode(RUN),
+       quitRequested(false),
+       resetRequested(false),
+       romLoaded(false)
 {
-       gb = new GameBoy(romName.toStdString());
-       isPaused = true;
-       quitRequested = false;
-       frameCount = 0;
 }
 
 QtBoiEmuThread::~QtBoiEmuThread()
 {
-       stop();
-       wait();
-       delete gb;
 }
 
-void QtBoiEmuThread::toggle_paused()
+void QtBoiEmuThread::loadROM(QString name)
+{
+       romName=name;
+       reset();
+       romLoaded=true;
+}
+
+void QtBoiEmuThread::reset()
 {
-       isPaused = !isPaused;
+       resetRequested=true;
+}
+
+void QtBoiEmuThread::pause()
+{
+       isPaused = true;
 }
 
 void QtBoiEmuThread::cont()
@@ -82,45 +95,65 @@ void QtBoiEmuThread::step()
 
 void QtBoiEmuThread::run()
 {
-       cout << "Running! \\o/" << endl;
+       GameBoy gb;
+       cout << "GB created, emu thread running" << endl;
+       
+       // wait until ROM is loaded
+       while(!romLoaded)
+               msleep(500);
+
        while(!quitRequested)
        {
+               if(resetRequested)
+               {
+                       resetRequested = false;
+                       gb.load_ROM(romName.toStdString());
+                       cout << "Loaded ROM " << romName.toStdString() << endl;
+               }
+
                if(isPaused)
-                       usleep(100);
-               else {
+                       msleep(10);
+               else 
+               {
                        switch (runningMode)
                        {
                                case RUN:
-                                       while (!isPaused && 
-                                                       (status == GameBoy::NORMAL || status == GameBoy::WAIT))
+                                       while (!isPaused && !resetRequested &&
+                                               (status == GameBoy::NORMAL || status == GameBoy::WAIT))
                                        {
-                                               status = gb->run_cycle();
-                                               if (gb->video.get_frames_rendered() > frameCount)
+                                               status = gb.run_cycle();
+                                               if (gb.video.get_frames_rendered() > frameCount)
                                                {
-                                                       frameCount = gb->video.get_frames_rendered();
-                                                       emit redraw(gb->video.get_screen_buffer());
+                                                       frameCount = gb.video.get_frames_rendered();
+                                                       emit redraw(gb.video.get_screen_buffer());
                                                }
                                        }
                                        break;
                                case STEP:
                                        do
                                        {
-                                               status = gb->run_cycle();
-                                               if (gb->video.get_frames_rendered() > frameCount)
+                                               status = gb.run_cycle();
+                                               if (gb.video.get_frames_rendered() > frameCount)
                                                {
-                                                       frameCount = gb->video.get_frames_rendered();
-                                                       emit redraw(gb->video.get_screen_buffer());
+                                                       frameCount = gb.video.get_frames_rendered();
+                                                       emit redraw(gb.video.get_screen_buffer());
                                                }
                                        } while(status == GameBoy::WAIT); // do nothing
+                                       isPaused = true;
                                        
                                        break;
                        }
 
-                       print_run_result(*gb, status);
-                       isPaused=true;
-                       emit emulationPaused(); 
+                       print_run_result(gb, status);
+                       if (isPaused)
+                       {
+                               emit emulationPaused(); 
+                       }
                }
        }
+       
+       cout << "Exiting emulation thread" << endl;
+
 }
 
 
index cb5e80474c833610b2f9242ae5f1c510b4cb4589..bb9b85494d17f567f3911fcf2e6bba09eb6aab29 100644 (file)
@@ -13,13 +13,17 @@ class QtBoiEmuThread: public QThread
     GameBoy::run_status status;
     bool isPaused;
     int frameCount;
-    QtBoiEmuThread(QObject *parent, QString romName);
+
+    QtBoiEmuThread(QObject *parent);
     ~QtBoiEmuThread();
+
+    void loadROM(QString romName);
  
   public slots:
+    void reset();
     void run();
     void stop();
-    void toggle_paused();
+    void pause();
     void cont();
     void step();
   
@@ -28,10 +32,12 @@ class QtBoiEmuThread: public QThread
     void redraw(const uchar *buffer);
 
   private:
+    QString romName;
     enum RunningMode { RUN, STEP };
-    GameBoy *gb;
     RunningMode runningMode;
     bool quitRequested;
+    bool resetRequested;
+    bool romLoaded;
 };
 
 
index d54e07545401e48c5925b668f8b634bbc5075f3e..71820dacdb90e3f548bff6040c7905c1c429eb0c 100644 (file)
 #include <iostream>
 
 QtBoiMainWindow::QtBoiMainWindow(QWidget *parent)
-  :QMainWindow(parent), emuThread(0)
+       :QMainWindow(parent), emuThread(0)
 {
-  screen = new QImage(160, 144, QImage::Format_Indexed8);
-  screen->setNumColors(8);
-  screen->setColor(7, qRgb(0,0,0));
-  screen->setColor(6, qRgb(36,36,36));
-  screen->setColor(5, qRgb(73,73,73));
-  screen->setColor(4, qRgb(109,109,109));
-  screen->setColor(3, qRgb(146,146,146));
-  screen->setColor(2, qRgb(182,182,182));
-  screen->setColor(1, qRgb(219,219,219));
-  screen->setColor(0, qRgb(255,255,255));
-
-  createMenu();
-  resize(640,480);
-  centralWindow = new QLabel(this);
-  setCentralWidget(centralWindow);
-
+       screen = new QImage(160, 144, QImage::Format_Indexed8);
+       screen->setNumColors(7);
+       screen->setColor(6, qRgb(0,0,0));
+       screen->setColor(5, qRgb(42,42,42));
+       screen->setColor(4, qRgb(85,85,85));
+       screen->setColor(3, qRgb(127,127,127));
+       screen->setColor(2, qRgb(170,170,170));
+       screen->setColor(1, qRgb(212,212,212));
+       screen->setColor(0, qRgb(255,255,255));
+
+       createMenu();
+       resize(640,480);
+       centralWindow = new QLabel(this);
+       setCentralWidget(centralWindow);
+
+       emuThread = new QtBoiEmuThread(this);
+       emuThread->start();
+
+       connect(emulatorCont, SIGNAL(triggered()), emuThread, SLOT(cont()));
+       connect(emulatorStop, SIGNAL(triggered()), emuThread, SLOT(stop()));
+       connect(emulatorPause, SIGNAL(triggered()), emuThread, SLOT(pause()));
+       connect(emulatorStep, SIGNAL(triggered()), emuThread, SLOT(step()));
+       connect(emulatorReset, SIGNAL(triggered()), emuThread, SLOT(reset()));
+       connect(emuThread, SIGNAL(redraw(const uchar*)), this, SLOT(onRedraw(const uchar*)));
 
 }
 
 QtBoiMainWindow::~QtBoiMainWindow()
 {
-  if (emuThread) {
-    emuThread->stop();
-    delete emuThread;
-  }
+       if (emuThread) {
+               emuThread->stop();
+               emuThread->wait();
+               delete emuThread;
+       }
 }
 
 void QtBoiMainWindow::createMenu()
 {
-  loadROM       = new QAction("&Load ROM...", this);
-  quit          = new QAction("&Quit", this);
-  emulatorPause = new QAction("&Toggle pause", this);
-  emulatorCont  = new QAction("&Go", this);
-  emulatorStop  = new QAction("&Stop", this);
-  emulatorStep  = new QAction("St&ep", this);
-
-  QMenu *file;
-  file = menuBar()->addMenu("&File");
-  file->addAction(loadROM);
-  file->addAction(quit);
-
-  QMenu *emulator;
-  emulator = menuBar()->addMenu("&Emulator");
-  emulator->addAction(emulatorCont);
-  emulator->addAction(emulatorPause);
-  emulator->addAction(emulatorStop);
-
-  QMenu *debug;
-  debug = menuBar()->addMenu("&Debug");
-  debug->addAction(emulatorStep);
-
-  connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
-  connect(loadROM, SIGNAL(triggered()), this, SLOT(onLoadROM()));
+       loadROM       = new QAction("&Load ROM...", this);
+       quit          = new QAction("&Quit", this);
+       emulatorPause = new QAction("&Pause", this);
+       emulatorCont  = new QAction("&Go", this);
+       emulatorStop  = new QAction("&Stop", this);
+       emulatorStep  = new QAction("St&ep", this);
+       emulatorReset = new QAction("&Reset", this);
+
+
+       QMenu *file;
+       file = menuBar()->addMenu("&File");
+       file->addAction(loadROM);
+       file->addAction(quit);
+
+       QMenu *emulator;
+       emulator = menuBar()->addMenu("&Emulator");
+       emulator->addAction(emulatorCont);
+       emulator->addAction(emulatorPause);
+       emulator->addAction(emulatorStop);
+       emulator->addAction(emulatorReset);
+
+       QMenu *debug;
+       debug = menuBar()->addMenu("&Debug");
+       debug->addAction(emulatorStep);
+
+       connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
+       connect(loadROM, SIGNAL(triggered()), this, SLOT(onLoadROM()));
 }
 
 void QtBoiMainWindow::onLoadROM()
 {
-  QString filename = QFileDialog::getOpenFileName(this, tr("Load ROM"), "../roms", tr("GameBoy ROMs (*.gb *.gbc)"));
-  if (filename == "") return;
-
-  std::cout << filename.toStdString() << std::endl;
-  
-  if (emuThread) {
-    emuThread->stop();
-    emuThread->wait();
-    delete emuThread;
-  }
-
-  emuThread = new QtBoiEmuThread(0, filename);
-  
-  connect(emulatorCont, SIGNAL(triggered()), emuThread, SLOT(cont()), Qt::DirectConnection);
-  connect(emulatorStop, SIGNAL(triggered()), emuThread, SLOT(stop()), Qt::DirectConnection);
-  connect(emulatorPause, SIGNAL(triggered()), emuThread, SLOT(toggle_paused()), Qt::DirectConnection);
-  connect(emulatorStep, SIGNAL(triggered()), emuThread, SLOT(step()), Qt::DirectConnection);
-  connect(emuThread, SIGNAL(redraw(const uchar*)), this, SLOT(onRedraw(const uchar*)));
-
-  emuThread->start();
+       QString filename = QFileDialog::getOpenFileName(this, tr("Load ROM"), "../roms", tr("GameBoy ROMs (*.gb *.gbc)"));
+       if (filename == "") return;
+
+       emuThread->loadROM(filename);
+
 }
 
 void QtBoiMainWindow::onRedraw(const uchar *buffer)
 {
-  uchar *pixels = screen->bits();
-  memcpy(pixels, buffer, 160*144);
-  //centralWindow->setPixmap(QPixmap::fromImage(screen->scaled(320,288)));
-  centralWindow->setPixmap(QPixmap::fromImage(*screen));
+       uchar *pixels = screen->bits();
+       memcpy(pixels, buffer, 160*144);
+       centralWindow->setPixmap(QPixmap::fromImage(screen->scaled(320,288)));
 }
 
 
index 8794aeaf7fec5becf5e285c0962ae2fa2abdef19..13823395fe640a295c7a0534854ea4d4a438f39c 100644 (file)
 
 class QtBoiMainWindow: public QMainWindow
 {
-  Q_OBJECT
-
-  public:
-    QtBoiMainWindow(QWidget *parent=0);
-    ~QtBoiMainWindow();
-
-  public slots:
-    void onLoadROM();
-    void onRedraw(const uchar *buffer);
-
-  private:
-    void createMenu();
-    QtBoiEmuThread *emuThread;
-
-    QLabel *centralWindow;
-    QImage *screen;
-
-    QAction *loadROM;
-    QAction *quit;
-    QAction *emulatorPause;
-    QAction *emulatorCont;
-    QAction *emulatorStop;
-    QAction *emulatorStep;
+       Q_OBJECT
+
+       public:
+               QtBoiMainWindow(QWidget *parent=0);
+               ~QtBoiMainWindow();
+
+               public slots:
+                       void onLoadROM();
+               void onRedraw(const uchar *buffer);
+
+       private:
+               void createMenu();
+               QtBoiEmuThread *emuThread;
+
+               QLabel *centralWindow;
+               QImage *screen;
+
+               QAction *loadROM;
+               QAction *quit;
+               QAction *emulatorPause;
+               QAction *emulatorCont;
+               QAction *emulatorStop;
+               QAction *emulatorStep;
+               QAction *emulatorReset;
 };
 
 
index fc425826ae7b2898c5959210ff8cdbcce771a39d..2b82c42f5169b5bd9b10cdf25f6a39e946772dbc 100644 (file)
@@ -256,7 +256,8 @@ void new_block_start(address dst, address src, Instruction::InstructionType type
 int main(int argc, char **argv)
 {
        logger.set_log_level(Logger::TRACE);
-       GameBoy gb(argv[1]);
+       GameBoy gb;
+       gb.load_ROM(argv[1]);
 
        list<CodeBlock> pending;
        // pending holds empty CodeBlocks