WIP
authorslack <slack@codemaniacs.com>
Wed, 11 Mar 2009 01:50:46 +0000 (02:50 +0100)
committerjgorbe <jgorbe@starbuck.(none)>
Wed, 11 Mar 2009 11:46:05 +0000 (12:46 +0100)
CMakeLists.txt
core/CMakeLists.txt
core/GBVideo.cc
core/GBVideo.h
core/GameBoy.cc
core/GameBoy.h
wenboi/wenboi.cc

index fd3c3e76d34d5e424c2c718efc43e209a5d1b0e7..201bfd28b1191197513e04f252f544fbc491eff6 100644 (file)
@@ -1,8 +1,5 @@
 PROJECT(wenboi)
 
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0)
-FIND_PACKAGE(SDL REQUIRED)
 
 ADD_SUBDIRECTORY(core)
-ADD_SUBDIRECTORY(wenboi)
-ADD_SUBDIRECTORY(wendi)
index 982988b4efee3e9037bf67397088e2bb7865d50f..67a6f57a8bcfd17965f5f2f0a5230188ec065c19 100644 (file)
@@ -1,6 +1,2 @@
-FIND_PACKAGE(SDL REQUIRED)
-
-ADD_LIBRARY(wenboicore STATIC GameBoy.cc GBMemory.cc GBRom.cc GBVideo.cc MBC.cc NoMBC.cc MBC1.cc util.cc) 
-TARGET_LINK_LIBRARIES(wenboicore ${SDL_LIBRARY})
-INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR})
+ADD_LIBRARY(wenboicore SHARED GameBoy.cc GBMemory.cc GBRom.cc GBVideo.cc MBC.cc NoMBC.cc MBC1.cc util.cc) 
 
index 2fb2793824d492aa7b9e9038c02cfa370568c7fb..f4e112b61d399761106cfd63f22abf64b50b0c19 100644 (file)
     You should have received a copy of the GNU General Public License
     along with wenboi.  If not, see <http://www.gnu.org/licenses/>.
 */ 
+#include <iostream>
+#include <algorithm>
+#include <vector>
+
 #include "GBVideo.h"
 #include "GameBoy.h"
 #include "../common/Logger.h"
 #include "util.h"
-#include <iostream>
-#include <algorithm>
-#include <vector>
 
 
 GBVideo::GBVideo(GameBoy *core):
        OAM(),
-       display(0),
        core(core),
        cur_window_line(0),
        mode(2),
        OAM_BUSY(false),
        VRAM_BUSY(false),
        frames_rendered(0),
-       t0(0),
-       t_last_frame(0),
+       screen(0),
        oldscreen(0), newscreen(0),
        display_mode(NORMAL),
        cycles_until_next_update(0)
 {
-       SDL_Init(SDL_INIT_VIDEO);
-       display=SDL_SetVideoMode(320,288,32,SDL_SWSURFACE | SDL_DOUBLEBUF);
-
-       t0 = SDL_GetTicks();
        oldscreen = new u8[160*144];
        newscreen = new u8[160*144];
-
-       colors[0] = SDL_MapRGB(display->format, 192,192,0);
-       colors[1] = SDL_MapRGB(display->format, 139,139,21);
-       colors[2] = SDL_MapRGB(display->format, 101,101,42);
-       colors[3] = SDL_MapRGB(display->format, 64,64,64);
-       // colors[0] = SDL_MapRGB(display->format, 0xFF, 0xFF, 0xFF);
-       // colors[1] = SDL_MapRGB(display->format, 0xAA, 0xAA, 0xAA);
-       // colors[2] = SDL_MapRGB(display->format, 0x55, 0x55, 0x55);
-       // colors[3] = SDL_MapRGB(display->format, 0x00, 0x00, 0x00);
+       screen    = new u8[160*144]; // sum of old and new, 8 possible "colors" per pixel
 }
 
 GBVideo::~GBVideo()
 {
-       SDL_Quit();
        delete [] oldscreen;
        delete [] newscreen;
+       delete [] screen;
 }
 
 void GBVideo::reset()
@@ -177,42 +164,16 @@ u32 GBVideo::update()
                                        core->irq(GameBoy::IRQ_LCD_STAT);
                                }
 
-                               if (display_mode == NORMAL)
-                               {
-                                       
-                                       u32 *pixels = static_cast<u32*>(display->pixels);
-                                       u32 pixels_per_line = display->pitch/display->format->BytesPerPixel;
-                                       for (int y=0; y<144; y++)
-                                               for (int x=0; x<160; x++)
-                                               {
-                                                       u32 offset = 160*y+x;
-                                                       u32 dst_offset = 2*y*pixels_per_line+2*x;
-                                                       u32 avg = colors[(newscreen[offset] + oldscreen[offset])>>1];
-                                                       pixels[dst_offset]                   = avg;
-                                                       pixels[dst_offset+1]                 = avg;
-                                                       pixels[dst_offset+pixels_per_line]   = avg;
-                                                       pixels[dst_offset+pixels_per_line+1] = avg;
-                                               }
-                               }
+                               for (int i=0; i<144*160; i++)
+                                       screen[i]=oldscreen[i]+newscreen[i];
+
+                               // do_vblank_callback
 
+                               // replace oldscreen
                                memcpy(oldscreen, newscreen, 160*144);
 
-                               SDL_Flip(display);
                                frames_rendered++;
-                               u32 t1 = SDL_GetTicks();
-                               if (t1-t0 > 1000)
-                               {
-                                       char buf[50];
-                                       sprintf(buf, "%f FPS", frames_rendered/(0.001f*(t1-t0)));
-                                       SDL_WM_SetCaption(buf, 0);
-                                       t0=t1;
-                                       frames_rendered=0;
-                               }
-                       
-                               //u32 delay = t1 - t_last_frame < 6 ? 16-(t1-t_last_frame) : 0;
-                               //SDL_Delay(16-delay);
-                               //t_last_frame = t1;
-
+                               
                                // reset window Y
                                cur_window_line=0;
 
@@ -478,6 +439,9 @@ void GBVideo::draw()
                }
 
        }
+
+       // The code below should be moved to the emulator GUI
+#if 0
        else if (display_mode == BG_MAP)
        {
                if (LY==0)
@@ -593,10 +557,6 @@ void GBVideo::draw()
                        }
                }
        }
-}
-
-int GBVideo::poll_event(SDL_Event *ev)
-{
-       return SDL_PollEvent(ev);
+#endif
 }
 
index e1d2ef74ee61444ae107e7b9ffb19e4a87e16546..0d0c0d5ea7296c3f29e30c1fa9300231fc94e7cd 100644 (file)
@@ -19,7 +19,6 @@
 #define GBVIDEO_H
 
 #include "GBMemory.h"
-#include "SDL.h"
 #include "util.h"
 
 class GameBoy;
@@ -53,7 +52,6 @@ class GBVideo
        };
        
        
-       SDL_Surface *display;
        GameBoy *core;
        
        u8  cur_window_line;
@@ -63,9 +61,7 @@ class GBVideo
 
        u32 colors[4];
        u32 frames_rendered;
-       u32 t0;
-       u32 t_last_frame;
-       u8 *oldscreen, *newscreen;
+       u8 *oldscreen, *newscreen, *screen;
 
        public:
        enum DisplayMode {
@@ -88,6 +84,8 @@ class GBVideo
 
        void reset();
 
+       const u8 *get_screen_buffer() { return screen; }
+
        // VRAM/OAM access
        u8   read_VRAM (int addr) const;
        u8   read_OAM  (int addr) const;
@@ -104,9 +102,6 @@ class GBVideo
        u32 update();
        void set_display_mode(DisplayMode mode) { display_mode = mode; }
 
-       // event processing
-       int poll_event(SDL_Event *ev);
-       
        // status queries
        u32 get_frames_rendered() { return frames_rendered; }
        
index 5d1d401f7377761d86154699276d577eb9f26391..ad53ce1864048de18abe643710d224d9cd1d622b 100644 (file)
@@ -28,6 +28,8 @@
 #include <string>
 #include <cstring>
 
+bool GameBoy::is_pad[NUM_CONTROLS]={false, false, false, false, true, true, true, true};
+
 GameBoy::GameBoy(std::string rom_name, GameBoyType type):
        gameboy_type(type),
        memory(this),
@@ -1426,122 +1428,31 @@ GameBoy::run_status GameBoy::run_cycle()
        }
 }
 
-GameBoy::run_status GameBoy::run() 
+void GameBoy::push_control(Control b)
 {
-       static const int CYCLES_PER_INPUT_CHECK = 40000;
-       static int c=0;
+       controls[b]=true;
+       bool direction_pressed = is_pad[b];
+       bool button_pressed = !is_pad[b];
 
-       bool must_update_JOYP  = false; // has any button changed state?
+       update_JOYP();
 
-       // needed for firing joypad interrupt
-       bool button_pressed    = false;
-       bool direction_pressed = false;
+       // fire IRQ if needed
+       u8 JOYP = memory.read(GBMemory::JOYP, GBMemory::DONT_WATCH);
+       if ((check_bit(JOYP,5)==false && button_pressed) ||
+                       (check_bit(JOYP,4)==false && direction_pressed))
+               irq(IRQ_JOYPAD);
+}
 
-       SDL_Event ev;
+void GameBoy::release_control(Control b)
+{
+       controls[b]=false;
+}
 
+GameBoy::run_status GameBoy::run() 
+{
        run_status status=NORMAL;
        while (status == NORMAL || status == WAIT)
        {
-               ++c;
-               if (c==CYCLES_PER_INPUT_CHECK)
-               {
-                       c=0;
-                       while (video.poll_event(&ev))
-                       {
-                               switch(ev.type)
-                               {
-                                       case SDL_KEYDOWN:
-                                               switch(ev.key.keysym.sym)
-                                               {
-                                                       case SDLK_ESCAPE:
-                                                               return PAUSED;
-                                                       case SDLK_q:
-                                                               return QUIT;
-                                                       case SDLK_UP:
-                                                               controls[PAD_UP]=true;
-                                                               direction_pressed=true;
-                                                               break;
-                                                       case SDLK_DOWN:
-                                                               controls[PAD_DOWN]=true;
-                                                               direction_pressed=true;
-                                                               break;
-                                                       case SDLK_LEFT:
-                                                               controls[PAD_LEFT]=true;
-                                                               direction_pressed=true;
-                                                               break;
-                                                       case SDLK_RIGHT:
-                                                               controls[PAD_RIGHT]=true;
-                                                               direction_pressed=true;
-                                                               break;
-                                                       case SDLK_z:
-                                                               controls[BUTTON_A]=true;
-                                                               button_pressed=true;
-                                                               break;
-                                                       case SDLK_x:
-                                                               controls[BUTTON_B]=true;
-                                                               button_pressed=true;
-                                                               break;
-                                                       case SDLK_SPACE:
-                                                               controls[BUTTON_START]=true;
-                                                               button_pressed=true;
-                                                               break;
-                                                       case SDLK_RETURN:
-                                                               controls[BUTTON_SELECT]=true;
-                                                               button_pressed=true;
-                                                               break;
-                                                       default:
-                                                               break;
-                                               }
-                                               must_update_JOYP=true;
-                                               break;
-                                       case SDL_KEYUP:
-                                               switch(ev.key.keysym.sym)
-                                               {
-                                                       case SDLK_UP:
-                                                               controls[PAD_UP]=false;
-                                                               break;
-                                                       case SDLK_DOWN:
-                                                               controls[PAD_DOWN]=false;
-                                                               break;
-                                                       case SDLK_LEFT:
-                                                               controls[PAD_LEFT]=false;
-                                                               break;
-                                                       case SDLK_RIGHT:
-                                                               controls[PAD_RIGHT]=false;
-                                                               break;
-                                                       case SDLK_z:
-                                                               controls[BUTTON_A]=false;
-                                                               break;
-                                                       case SDLK_x:
-                                                               controls[BUTTON_B]=false;
-                                                               break;
-                                                       case SDLK_SPACE:
-                                                               controls[BUTTON_START]=false;
-                                                               break;
-                                                       case SDLK_RETURN:
-                                                               controls[BUTTON_SELECT]=false;
-                                                               break;
-                                                       default:
-                                                               break;
-                                               }
-                                               must_update_JOYP=true;
-                                               break;
-                                       case SDL_QUIT:
-                                               return QUIT;
-                               }
-                       }
-
-                       if (must_update_JOYP)
-                               update_JOYP();
-
-                       if (button_pressed || direction_pressed)
-                       {
-                               u8 JOYP = memory.read(GBMemory::JOYP, GBMemory::DONT_WATCH);
-                               if ((check_bit(JOYP,5)==false && button_pressed) ||
-                                               (check_bit(JOYP,4)==false && direction_pressed))
-                                       irq(IRQ_JOYPAD);
-                       }
-               }
                status = run_cycle();
        }
        
index 27381e238d2b02177cc50b8b64635fd9fe6e0e98..e96217d715aa4fd08ca2f96d0990072b027a1276 100644 (file)
 
 union GBRom;
 
+/* A GameBoy with debugging facilities :) */
 class GameBoy
 {
        public:
-       enum GameBoyType { GAMEBOY, GAMEBOYCOLOR, SUPERGAMEBOY } gameboy_type;
-       enum InterruptRequest { 
-               IRQ_VBLANK   = 0x01, 
-               IRQ_LCD_STAT = 0x02,
-               IRQ_TIMER    = 0x04, 
-               IRQ_SERIAL   = 0x08,
-               IRQ_JOYPAD   = 0x10,
-       };
-       
-       enum Flag
-       {
-               ZERO_FLAG       = 0x80,
-               ADD_SUB_FLAG    = 0x40,
-               HALF_CARRY_FLAG = 0x20,
-               CARRY_FLAG      = 0x10,
-       };
-
-       enum Controls
-       {
-               BUTTON_A=0,
-               BUTTON_B,
-               BUTTON_START,
-               BUTTON_SELECT,
-               PAD_UP,
-               PAD_DOWN,
-               PAD_LEFT,
-               PAD_RIGHT,
-               NUM_CONTROLS
-       };
-
-
-       friend class GBMemory;
-       friend class GBVideo;
-       GBMemory memory;
-       GBVideo video;
-       GBRom *rom;
-       bool controls[NUM_CONTROLS];
-
-       // CPU Registers
-       // ENDIANNESS WARNING!
-       struct RegisterSet
-       {
-               union 
-               {
-                       u16 AF;
-                       struct { u8 flags; u8 A; };
-               };
-               union 
+               enum GameBoyType { GAMEBOY, GAMEBOYCOLOR, SUPERGAMEBOY } gameboy_type;
+               enum Control
                {
-                       u16 BC;
-                       struct { u8 C; u8 B; };
+                       BUTTON_A=0,
+                       BUTTON_B,
+                       BUTTON_START,
+                       BUTTON_SELECT,
+                       PAD_UP,
+                       PAD_DOWN,
+                       PAD_LEFT,
+                       PAD_RIGHT,
+                       NUM_CONTROLS
                };
-               union 
+
+               enum run_status 
                {
-                       u16 DE;
-                       struct { u8 E; u8 D; };
+                       NORMAL = 0,
+                       BREAKPOINT,
+                       WATCHPOINT,
+                       TRACEPOINT,
+                       PAUSED,
+                       QUIT,
+                       WAIT,
                };
-               union 
-               {
-                       u16 HL;
-                       struct { u8 L; u8 H; };
+
+               enum InterruptRequest { 
+                       IRQ_VBLANK   = 0x01, 
+                       IRQ_LCD_STAT = 0x02,
+                       IRQ_TIMER    = 0x04, 
+                       IRQ_SERIAL   = 0x08,
+                       IRQ_JOYPAD   = 0x10,
                };
-               u16 SP;
-               u16 PC;
 
-       } __attribute__((packed)) regs;
+               // Constructors
+               GameBoy(std::string rom_name, GameBoyType type=GAMEBOY);
+
+               // running control methods
+               void irq(InterruptRequest i) { memory.write(0xFF0F, memory.read(0xFF0F) | i); }
+               void reset();
+               run_status run_cycle();
+               run_status run();
+
+               // button control methods
+               void push_control(Control b);
+               void release_control(Control b);
 
+               // video output
+               const u8 *get_screen_buffer(){ return video.get_screen_buffer(); }
 
-       u8 IME; // Interrupt master enable flag
-       u8 HALT; // Is the CPU halted waiting for an interrupt?
-       u8 STOP; // Is the CPU & LCD halted waiting for a keypress?
+               // debug methods
+               int  set_breakpoint    (u16 addr);
+               void delete_breakpoint (int id);
+               void enable_breakpoint (int id);
+               void disable_breakpoint(int id);
 
-       u32 cycle_count;
-       u32 cycles_until_next_instruction;
-       u8  divider_count; // resets every 256 cycles, so we don't need a cmp
-       u32 timer_count;
-       static const u32 CYCLE_STEP = 4;
+               std::string status_string();
+               Instruction disassemble_opcode(u16 addr);
+               static std::string get_port_name(int port);
        
-       inline void do_call(u16 addr)
-       {
-               logger.debug("do_call(0x", std::hex, std::setw(4), std::setfill('0'), addr, ")");
-               memory.write(regs.SP-1, regs.PC >> 8); 
-               memory.write(regs.SP-2, regs.PC & 0xFF); 
-               regs.SP -= 2; 
-               regs.PC = addr; 
-       }
-
-       void set_flag  (Flag f) { regs.flags |= f; }
-       void reset_flag(Flag f) { regs.flags &= (~f); }
-       bool check_flag(Flag f) const { return ((regs.flags & f) != 0); }
-
-       enum run_status 
-       {
-               NORMAL = 0,
-               BREAKPOINT,
-               WATCHPOINT,
-               TRACEPOINT,
-               PAUSED,
-               QUIT,
-               WAIT,
-       };
-
-       // Constructors
-       GameBoy(std::string rom_name, GameBoyType type=GAMEBOY);
-
-
-       void irq(InterruptRequest i) { memory.write(0xFF0F, memory.read(0xFF0F) | i); }
-       void reset();
-       run_status run_cycle();
-       run_status run();
-
-       // debug methods
-       int  set_breakpoint    (u16 addr);
-       void delete_breakpoint (int id);
-       void enable_breakpoint (int id);
-       void disable_breakpoint(int id);
-
-       std::string status_string();
-       Instruction disassemble_opcode(u16 addr);
-       static std::string get_port_name(int port);
-
-       // prevent object copying
        private:
-       GameBoy(const GameBoy&);
-       GameBoy operator=(const GameBoy&);
+               friend class GBMemory;
+               friend class GBVideo;
+               GBMemory memory;
+               GBVideo video;
+               GBRom *rom;
+               
+               bool controls[NUM_CONTROLS];
+               static bool is_pad[NUM_CONTROLS];
+               enum Flag
+               {
+                       ZERO_FLAG       = 0x80,
+                       ADD_SUB_FLAG    = 0x40,
+                       HALF_CARRY_FLAG = 0x20,
+                       CARRY_FLAG      = 0x10,
+               };
 
-       void update_JOYP();
-       
-       // debug things
-       struct Breakpoint {
-               int addr;
-               bool enabled;
 
-               Breakpoint(int a, bool e): addr(a), enabled(e) {}
-               Breakpoint(): addr(-1), enabled(false) {}
-       };
+               // CPU Registers
+               // ENDIANNESS WARNING!
+               struct RegisterSet
+               {
+                       union 
+                       {
+                               u16 AF;
+                               struct { u8 flags; u8 A; };
+                       };
+                       union 
+                       {
+                               u16 BC;
+                               struct { u8 C; u8 B; };
+                       };
+                       union 
+                       {
+                               u16 DE;
+                               struct { u8 E; u8 D; };
+                       };
+                       union 
+                       {
+                               u16 HL;
+                               struct { u8 L; u8 H; };
+                       };
+                       u16 SP;
+                       u16 PC;
+
+               } regs;
+
+
+               u8 IME; // Interrupt master enable flag
+               u8 HALT; // Is the CPU halted waiting for an interrupt?
+               u8 STOP; // Is the CPU & LCD halted waiting for a keypress?
+
+               u32 cycle_count;
+               u32 cycles_until_next_instruction;
+               u8  divider_count; // resets every 256 cycles, so we don't need a cmp
+               u32 timer_count;
+               static const u32 CYCLE_STEP = 4;
+               
+               inline void do_call(u16 addr)
+               {
+                       logger.debug("do_call(0x", std::hex, std::setw(4), std::setfill('0'), addr, ")");
+                       memory.write(regs.SP-1, regs.PC >> 8); 
+                       memory.write(regs.SP-2, regs.PC & 0xFF); 
+                       regs.SP -= 2; 
+                       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();
+               
+               // debug things
+               struct Breakpoint {
+                       int addr;
+                       bool enabled;
+
+                       Breakpoint(int a, bool e): addr(a), enabled(e) {}
+                       Breakpoint(): addr(-1), enabled(false) {}
+               };
 
-       typedef std::map<int, Breakpoint> BreakpointMap;
-       
-       BreakpointMap breakpoints;
-       int last_breakpoint_id;
+               typedef std::map<int, Breakpoint> BreakpointMap;
+               
+               BreakpointMap breakpoints;
+               int last_breakpoint_id;
 
 };
 
index e6c979b799b1a9d91f516bf7e70100c1d2d407d4..1c2541038b487db18fa54b3a53211124d0482933 100644 (file)
@@ -15,8 +15,6 @@
     You should have received a copy of the GNU General Public License
     along with wenboi.  If not, see <http://www.gnu.org/licenses/>.
 */
-#include "../core/GameBoy.h"
-#include "../common/Logger.h"
 #include <iostream>
 #include <iomanip>
 #include <sstream>
 #include <cstdlib>
 #include <vector>
 
+#include "SDL.h"
+
+#include "../core/GameBoy.h"
+#include "../common/Logger.h"
+
 using std::cin;
 using std::cout;
 using std::cerr;
@@ -47,13 +50,17 @@ void print_run_result(GameBoy &gb, int status)
 {
        if (status == GameBoy::BREAKPOINT)
        {
-               cout << "Breakpoint hit at " << gb.regs.PC << endl;
+               cout << "Breakpoint reached " << endl;
                cout << gb.status_string() << endl;
        }
        else if (status == GameBoy::WATCHPOINT)
        {
+               cout << "Watchpoint reached" << endl;
+               /*
                cout << "Watchpoint 0x" << std::hex << std::setw(4) << std::setfill('0') <<
                        int(gb.memory.watchpoint_addr) << " hit at 0x" << gb.regs.PC;
+               */
+               // FIXME: Move/expose this things somewhere
                if (gb.memory.watchpoint_newvalue == 0xFFFF)
                {
                        cout << " (READ)" << endl << 
@@ -79,6 +86,10 @@ int main(int argc, char **argv)
                exit(EXIT_FAILURE);
        }
        GameBoy gb(argv[1]);
+       
+       SDL_Init(SDL_INIT_VIDEO);
+       SDL_Surface *display=SDL_SetVideoMode(320,288,32,SDL_SWSURFACE | SDL_DOUBLEBUF);
+
                        
        cout << gb.status_string() << endl;