- Cambiados accesos a memoria de operator[] a read() y write()
authorslack <slack@0666ae3d-8926-0410-aeff-ae84559ff337>
Mon, 20 Aug 2007 03:32:10 +0000 (03:32 +0000)
committerslack <slack@0666ae3d-8926-0410-aeff-ae84559ff337>
Mon, 20 Aug 2007 03:32:10 +0000 (03:32 +0000)
- Nuevos opcodes: saltos, DI/EI, calls
- Corregido bug en check_flag
- Creado test_core. Lanza el emulador en plan "a ver que pasa"
  Primera "ejecucion" de opcodes de gameboy! \o/

git-svn-id: http://slack.codemaniacs.com/wenboi@12 0666ae3d-8926-0410-aeff-ae84559ff337

GBMemory.cc
GBMemory.h
GBRom.cc
MBC.cc
MBC.h
Makefile
gbcore.cc
gbcore.h
opcodes.h
tests/test_core.cc [new file with mode: 0644]

index a5786b3348d6cc872f307d95cd91284595c223d2..8538c4e338b135ef5fbc8cb4bdb489718682e27b 100644 (file)
@@ -2,40 +2,50 @@
 #include "MBC.h"
 #include "gbcore.h"
 #include "Logger.h"
+#include <iostream>
+#include <sstream>
+#include <iomanip>
 
-u8& GBMemory::operator[](unsigned int addr)
+void GBMemory::write(int addr, u8 value)
 {
-       if (addr < 0x8000)      return (*mbc)[addr];
-       else if (addr < 0xA000) return VRAM[addr-0x8000];
-       else if (addr < 0xC000) return (*mbc)[addr];
-       else if (addr < 0xD000) return WRAM0[addr-0xC000];
-       else if (addr < 0xE000) return WRAM1[addr-0xD000];
-       else if (addr < 0xFDFF) return (*mbc)[addr-0x2000];
-       else if (addr < 0xFEA0) return OAM[addr-0xFDFF];
-       else if (addr >= 0xFF00 && addr <= 0xFF7F) 
-               return core->IO.addr[addr-0xFF00];
-       else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr-0xFF80];
+       if (addr < 0x8000)      mbc->write(addr, value);
+       else if (addr < 0xA000) VRAM [addr - VRAM_BASE] = value;
+       else if (addr < 0xC000) mbc->write(addr, value);
+       else if (addr < 0xD000) WRAM0[addr - WRAM0_BASE] = value;
+       else if (addr < 0xE000) WRAM1[addr - WRAM1_BASE] = value;
+       else if (addr < 0xFDFF) write(addr-0x2000, value);
+       else if (addr < 0xFEA0) OAM  [addr - OAM_BASE] = value;
+       else if (addr >= 0xFF00 && addr <= 0xFF7F) {
+               IO.write(addr,value);
+       }
+       else if (addr >= 0xFF80 && addr <= 0xFFFE) HRAM[addr - HRAM_BASE]=value;
        else {
-               logger.error("Invalid write address");
-               return *(static_cast<u8*>(0));
+               std::ostringstream errmsg;
+               errmsg << "Invalid write address 0x" << 
+                       std::hex << std::setw(4) << std::setfill('0') << addr;
+               logger.error(errmsg.str());
+               std::cout << *(static_cast<u8*>(0));
        }
 }
 
 
-u8  GBMemory::operator[](unsigned int addr) const
+u8  GBMemory::read(int addr) const
 {
-       if (addr < 0x8000)      return (*mbc)[addr];
-       else if (addr < 0xA000) return VRAM[addr-0x8000];
-       else if (addr < 0xC000) return (*mbc)[addr];
-       else if (addr < 0xD000) return WRAM0[addr-0xC000];
-       else if (addr < 0xE000) return WRAM1[addr-0xD000];
-       else if (addr < 0xFDFF) return (*mbc)[addr-0x2000];
-       else if (addr < 0xFEA0) return OAM[addr-0xFDFF];
+       if (addr < 0x8000)      return mbc->read(addr);
+       else if (addr < 0xA000) return VRAM [addr - VRAM_BASE];
+       else if (addr < 0xC000) return mbc->read(addr);
+       else if (addr < 0xD000) return WRAM0[addr - WRAM0_BASE];
+       else if (addr < 0xE000) return WRAM1[addr - WRAM1_BASE];
+       else if (addr < 0xFDFF) return read(addr-0x2000);
+       else if (addr < 0xFEA0) return OAM  [addr - OAM_BASE];
        else if (addr >= 0xFF00 && addr <= 0xFF7F) 
-               return core->IO.addr[addr-0xFF00];
-       else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr-0xFF80];
+               return IO.read(addr);
+       else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr - HRAM_BASE];
        else {
-               logger.error("Invalid write address");
+               std::ostringstream errmsg;
+               errmsg << "Invalid read address 0x" << 
+                       std::hex << std::setw(4) << std::setfill('0') << addr;
+               logger.error(errmsg.str());
                return *(static_cast<u8*>(0));
        }
 }
index 6e02479deedd771d15fd1aaf11b74e207d99e235..f1f979f617c61be8fa9f380c6bbe51895ca9882c 100644 (file)
@@ -6,6 +6,18 @@
 class GameBoy;
 class MBC;
 
+class GBIO
+{
+       u8 ports[128];
+
+       public:
+       static const u16 IO_BASE = 0xFF00;
+
+       u8   read(int addr) const { return ports[addr-IO_BASE]; }
+       void write(int addr, u8 value) { ports[addr-IO_BASE] = value; }
+
+};
+
 class GBMemory
 {
        GameBoy *core;
@@ -18,15 +30,26 @@ class GBMemory
        u8 WRAM1[4096]; // D000-DFFF: Work RAM Bank 1 (TODO: In GBC mode switchable bank 1-7)
                        // E000-FDFF: ECHO: Same as C000-DDFF
        u8 OAM[160];    // FE00-FE9F: Sprite Attribute Table
+       GBIO IO;        // FF00-FF7F: IO ports
+
        u8 HRAM[126];   // FF80-FFFE: High RAM
 
        public:
-       GBMemory(GameBoy *core): core(core), mbc(0) {}
+
+       static const u16 VRAM_BASE  = 0x8000;
+       static const u16 EXTERNAL_RAM_BASE = 0xA000;
+       static const u16 WRAM0_BASE = 0xC000;
+       static const u16 WRAM1_BASE = 0xD000;
+       static const u16 OAM_BASE   = 0xFE00;
+       static const u16 IO_BASE    = 0xFF00;
+       static const u16 HRAM_BASE  = 0xFF80;
+
+       GBMemory(GameBoy *core): core(core), mbc(0), IO() {}
        void init(MBC *mbc) { this->mbc = mbc; }
 
 
-       u8& operator[](unsigned int addr);
-       u8  operator[](unsigned int addr) const;
+       u8   read(int addr) const;
+       void write(int addr, u8 value);
 
 };
 
index 7ebd8da066fcc8625c852a92912dadbd3df067b0..a0d7e9d5961ed4a539adb150ccedd44780393a57 100644 (file)
--- a/GBRom.cc
+++ b/GBRom.cc
@@ -18,7 +18,8 @@ void log_rom_header(GBRom *rom, Logger::log_level level)
        out << "Logging ROM header data:" << endl;
 
        out << std::hex << std::right << std::setfill('0');
-       out << "Entrypoint: 0x" << rom->header.entry_point << endl;
+       out << "Entrypoint: 0x" << std::setw(8) << 
+               rom->header.entry_point << endl;
 
        out << "SGB flag: "       << int(rom->header.sgb_flag) << endl;
        out << "Cartridge type: " << int(rom->header.cartridge_type) << endl;
diff --git a/MBC.cc b/MBC.cc
index f208f73eca498d2e4b0e3567d3a0b362043bc6b9..6b49b4528f56464a1707f3174eaa1daf183523a8 100644 (file)
--- a/MBC.cc
+++ b/MBC.cc
@@ -1,6 +1,9 @@
 #include "MBC.h"
 #include "Logger.h"
 #include <cstring>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
 
 using namespace cartridge_types;
 
@@ -16,7 +19,7 @@ MBC *create_MBC(GBRom *rom)
        }
 }
 
-u8 NoMBC::operator[](unsigned int addr) const
+u8 NoMBC::read(int addr) const
 {
        if (addr <= 0x7FFF)
                return ROM[addr];
@@ -27,12 +30,19 @@ u8 NoMBC::operator[](unsigned int addr) const
        return 0;
 }
 
-u8& NoMBC::operator[](unsigned int addr) 
+void NoMBC::write(int addr, u8 value)
 {
-       if ((addr&0xE000) == 0xA000)   //(addr >= 0xA000 && addr <= 0xBFFF)
-               return RAM[addr-0xA000];
-       else
-               logger.error("NoMBC: trying to write in ROM");
-       return *(static_cast<u8*>(0)); // Shouldn't happen
+       if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF)
+       {
+               RAM[addr-0xA000]=value;
+               return;
+       }
+       else 
+       {
+               std::ostringstream errmsg;
+               errmsg <<"NoMBC: trying to write in ROM, addr=0x"<<std::hex<<addr;
+               logger.error(errmsg.str());
+               std::cout << *(static_cast<u8*>(0)); // Shouldn't happen
+       }
 }
 
diff --git a/MBC.h b/MBC.h
index 81fd79f313d9d57b165806dac60e673fb27c0070..3284538571ba4a00930d6b4f1d4e5c0e328fb029 100644 (file)
--- a/MBC.h
+++ b/MBC.h
@@ -7,9 +7,9 @@
 class MBC
 {
        public:
-       virtual u8  operator[](unsigned int addr) const=0;
-       virtual u8& operator[](unsigned int addr)=0;
-       virtual ~MBC();
+       virtual u8   read(int addr) const=0;
+       virtual void write(int addr, u8 value)=0;
+       virtual ~MBC() {};
 };
 
 class NoMBC: public MBC
@@ -19,8 +19,8 @@ class NoMBC: public MBC
        
        public:
        NoMBC(GBRom *rom) { memcpy(ROM, rom->data, 32768); }
-       u8  operator[](unsigned int addr) const;
-       u8& operator[](unsigned int addr);
+       u8   read (int addr) const;
+       void write(int addr, u8 value);
 
 };
 
index 63c4f3993f0cebda098c81582b4580f38235963c..09ed32e7fed5c7f5f9876dbbe9868c04a382add1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
 CXXFLAGS=-g -Wall -Weffc++ -Wstrict-null-sentinel -Wold-style-cast \
         -Woverloaded-virtual 
+LDFLAGS=-g
 
 all: gbcore.o MBC.o GBMemory.o Logger.o GBRom.o tests
 
index bbed7e7a88069db4f3547569e0f1fefdfb07590c..b02caf81c41cd3bbf0e83a2c3c9617d0174be183 100644 (file)
--- a/gbcore.cc
+++ b/gbcore.cc
@@ -3,11 +3,18 @@
 #include "GBRom.h"
 #include "MBC.h"
 #include "Logger.h"
+#include <sstream>
+#include <iomanip>
 #include <string>
 #include <cstring>
 
 GameBoy::GameBoy(std::string rom_name):
-       memory(this),rom(0), regs(), IO(), IME(1), HALT(0)
+       memory(this),
+       rom(0),
+       regs(),
+       IME(1),
+       HALT(0),
+       cycle_count(0)
 {
        logger.info("GameBoy init");
        rom = read_gbrom(rom_name);
@@ -30,11 +37,11 @@ void GameBoy::run_cycle()
 {
        int prefix;
        int opcode;
-       opcode = memory[regs.PC++];
+       opcode = memory.read(regs.PC++);
        if (opcode == 0xCB)
        {
                prefix=opcode;
-               opcode=memory[regs.PC++];
+               opcode=memory.read(regs.PC++);
        }
 
        switch(opcode)
@@ -58,86 +65,86 @@ void GameBoy::run_cycle()
                for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, LD__HL__reg)
                
                case 0x36: // LD (HL), n
-                       memory[regs.HL] = memory[regs.PC++];
+                       memory.write(regs.HL, memory.read(regs.PC++));
                        break;
                
                // LD A, mem
                case 0x0A: // LD A, (BC)
-                       regs.A = memory[regs.BC];
+                       regs.A = memory.read(regs.BC);
                        break;
                case 0x1A: // LD A, (DE)
-                       regs.A = memory[regs.DE];
+                       regs.A = memory.read(regs.DE);
                        break;
                case 0xFA: // LD A, (nn)
-                       regs.A = memory[memory[regs.PC] + memory[regs.PC+1]<<8];
+                       regs.A = memory.read(memory.read(regs.PC) + memory.read(regs.PC+1)<<8);
                        regs.PC+=2;
                        break;
                
                // LD mem, A
                case 0x02: // LD (BC), A
-                       memory[regs.BC] = regs.A;
+                       memory.write(regs.BC, regs.A);
                        break;
                case 0x12: // LD (DE), A
-                       memory[regs.DE] = regs.A;
+                       memory.write(regs.DE, regs.A);
                        break;
                case 0xEA: // LD (nn), A
-                       memory[memory[regs.PC] + memory[regs.PC+1]<<8] = regs.A;
+                       memory.write(memory.read(regs.PC) + memory.read(regs.PC+1)<<8, regs.A);
                        break;
 
                // LD A, (C)
                case 0xF2:
-                       regs.A = memory[0xFF00 + regs.C];
+                       regs.A = memory.read(0xFF00 + regs.C);
                        break;
                // LD (C), A
                case 0xE2:
-                       memory[0xFF00 + regs.C] = regs.A;
+                       memory.write(0xFF00 + regs.C, regs.A);
                        break;
 
                // LD A, (HLD); LD A, (HL-); LDD A,(HL);
                case 0x3A:
-                       regs.A = memory[regs.HL];
+                       regs.A = memory.read(regs.HL);
                        --regs.HL;
                        break;
                // LD (HLD), A; LD (HL-), A; LDD (HL), A;
                case 0x32:
-                       memory[regs.HL] = regs.A;
+                       memory.write(regs.HL, regs.A);
                        --regs.HL;
                        break;
                // LD A, (HLI); LD A, (HL+); LDI A, (HL);
                case 0x2A:
-                       regs.A = memory[regs.HL];
+                       regs.A = memory.read(regs.HL);
                        ++regs.HL;
                        break;
                // LD (HLI), A; LD (HL+), A; LDI (HL), A;
                case 0x22:
-                       memory[regs.HL] = regs.A;
+                       memory.write(regs.HL, regs.A);
                        ++regs.HL;
                        break;
 
                // LDH (n), A
                case 0xE0:
-                       memory[0xFF00 + regs.PC++] = regs.A;
+                       memory.write(0xFF00 + regs.PC++, regs.A);
                        break;
                // LDH A, (n)
                case 0xF0:
-                       regs.A = memory[0xFF00 + regs.PC++];
+                       regs.A = memory.read(0xFF00 + regs.PC++);
                        break;
 
                // LD n, nn
                case 0x01: // LD BC, nn
-                       regs.BC = memory[regs.PC]+(memory[regs.PC+1] << 8);
+                       regs.BC = memory.read(regs.PC)+(memory.read(regs.PC+1) << 8);
                        regs.PC +=2;
                        break;
                case 0x11: // LD DE, nn
-                       regs.DE = memory[regs.PC]+(memory[regs.PC+1] << 8);
+                       regs.DE = memory.read(regs.PC)+(memory.read(regs.PC+1) << 8);
                        regs.PC +=2;
                        break;
                case 0x21: // LD HL, nn
-                       regs.HL = memory[regs.PC]+(memory[regs.PC+1] << 8);
+                       regs.HL = memory.read(regs.PC)+(memory.read(regs.PC+1) << 8);
                        regs.PC +=2;
                        break;
                case 0x31: // LD SP, nn
-                       regs.SP = memory[regs.PC]+(memory[regs.PC+1] << 8);
+                       regs.SP = memory.read(regs.PC)+(memory.read(regs.PC+1) << 8);
                        regs.PC +=2;
                        break;
                
@@ -149,7 +156,7 @@ void GameBoy::run_cycle()
                // LD HL, SP+n
                // LDHL SP, n
                case 0xF8: {
-                       s8 offset = memory[regs.PC++];
+                       s8 offset = memory.read(regs.PC++);
                        int res = regs.SP + offset;
                        
                        // TODO: Verificar si los flags van asi
@@ -165,9 +172,9 @@ void GameBoy::run_cycle()
 
                // LD (nn), SP
                case 0x08: {
-                       int addr = memory[regs.PC] + memory[regs.PC+1] << 8;
+                       int addr = memory.read(regs.PC) + memory.read(regs.PC+1) << 8;
                        regs.PC += 2;
-                       memory[addr] = regs.SP;
+                       memory.write(addr, regs.SP);
                        break;
                        }
 
@@ -188,8 +195,8 @@ void GameBoy::run_cycle()
                for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ADD_A_reg)
                
                case 0x86: {// ADD A, (HL)
-                       int res = regs.A + memory[regs.HL];
-                       int half_res = (regs.A & 0x0F) + (memory[regs.HL] & 0x0F);
+                       int res = regs.A + memory.read(regs.HL);
+                       int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F);
                        regs.A = static_cast<u8>(res);
                        
                        reset_flag(ADD_SUB_FLAG);
@@ -199,7 +206,7 @@ void GameBoy::run_cycle()
                        break;
                        }
                case 0xC6: {//ADD A, #
-                       int inm = memory[regs.PC++];
+                       int inm = memory.read(regs.PC++);
                        int res = regs.A + inm;
                        int half_res = (regs.A & 0x0F) + (inm & 0x0F);
                        regs.A = static_cast<u8>(res);
@@ -216,8 +223,8 @@ void GameBoy::run_cycle()
 
                case 0x8E: {// ADC A, (HL)
                        int carry = (check_flag(CARRY_FLAG)? 1 : 0);
-                       int res = regs.A + memory[regs.HL] + carry;
-                       int half_res = (regs.A & 0x0F) + (memory[regs.HL] & 0x0F) + carry;
+                       int res = regs.A + memory.read(regs.HL) + carry;
+                       int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F) + carry;
                        regs.A = static_cast<u8>(res);
                        
                        reset_flag(ADD_SUB_FLAG);
@@ -228,7 +235,7 @@ void GameBoy::run_cycle()
                        }
                case 0xCE: {//ADC A, #
                        int carry = (check_flag(CARRY_FLAG)? 1 : 0);
-                       int inm = memory[regs.PC++];
+                       int inm = memory.read(regs.PC++);
                        int res = regs.A + inm + carry;
                        int half_res = (regs.A & 0x0F) + (inm & 0x0F) + carry;
                        regs.A = static_cast<u8>(res);
@@ -244,8 +251,8 @@ void GameBoy::run_cycle()
                for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg)
 
                case 0x96: {//SUB (HL)
-                       int res = regs.A - memory[regs.HL];
-                       int half_res = (regs.A & 0x0F) - (memory[regs.HL] & 0x0F);
+                       int res = regs.A - memory.read(regs.HL);
+                       int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
                        regs.A = static_cast<u8>(res);
 
                        set_flag(ADD_SUB_FLAG);
@@ -256,7 +263,7 @@ void GameBoy::run_cycle()
                        }
                
                case 0xD6: {//SUB #
-                       int inm = memory[regs.PC++];
+                       int inm = memory.read(regs.PC++);
                        int res = regs.A - inm;
                        int half_res = (regs.A & 0x0F) - (inm & 0x0F);
                        regs.A = static_cast<u8>(res);
@@ -273,8 +280,8 @@ void GameBoy::run_cycle()
 
                case 0x9E: {//SBC (HL)
                        int carry = (check_flag(CARRY_FLAG)? 1 : 0);
-                       int res = regs.A - memory[regs.HL] - carry;
-                       int half_res = (regs.A & 0x0F) - (memory[regs.HL] & 0x0F) - carry;
+                       int res = regs.A - memory.read(regs.HL) - carry;
+                       int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F) - carry;
                        regs.A = static_cast<u8>(res);
 
                        set_flag(ADD_SUB_FLAG);
@@ -290,7 +297,7 @@ void GameBoy::run_cycle()
                for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg)
 
                case 0xA6: //AND (HL)
-                       regs.A &= memory[regs.HL];
+                       regs.A &= memory.read(regs.HL);
                        if (regs.A == 0) set_flag(ZERO_FLAG);
                        reset_flag(ADD_SUB_FLAG);
                        set_flag(HALF_CARRY_FLAG);
@@ -298,7 +305,7 @@ void GameBoy::run_cycle()
                        break;
 
                case 0xE6: //AND inm
-                       regs.A &= memory[regs.PC++];
+                       regs.A &= memory.read(regs.PC++);
                        if (regs.A == 0) set_flag(ZERO_FLAG);
                        reset_flag(ADD_SUB_FLAG);
                        set_flag(HALF_CARRY_FLAG);
@@ -309,7 +316,7 @@ void GameBoy::run_cycle()
                for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, OR_reg)
 
                case 0xB6: //OR (HL)
-                       regs.A |= memory[regs.HL];
+                       regs.A |= memory.read(regs.HL);
                        if (regs.A == 0) set_flag(ZERO_FLAG);
                        reset_flag(ADD_SUB_FLAG);
                        reset_flag(HALF_CARRY_FLAG);
@@ -317,7 +324,7 @@ void GameBoy::run_cycle()
                        break;
 
                case 0xF6: //OR inm
-                       regs.A |= memory[regs.PC++];
+                       regs.A |= memory.read(regs.PC++);
                        if (regs.A == 0) set_flag(ZERO_FLAG);
                        reset_flag(ADD_SUB_FLAG);
                        reset_flag(HALF_CARRY_FLAG);
@@ -328,7 +335,7 @@ void GameBoy::run_cycle()
                for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, XOR_reg)
 
                case 0xAE: //XOR (HL)
-                       regs.A ^= memory[regs.HL];
+                       regs.A ^= memory.read(regs.HL);
                        if (regs.A == 0) set_flag(ZERO_FLAG);
                        reset_flag(ADD_SUB_FLAG);
                        reset_flag(HALF_CARRY_FLAG);
@@ -336,7 +343,7 @@ void GameBoy::run_cycle()
                        break;
 
                case 0xEE: //XOR inm
-                       regs.A ^= memory[regs.PC++];
+                       regs.A ^= memory.read(regs.PC++);
                        if (regs.A == 0) set_flag(ZERO_FLAG);
                        reset_flag(ADD_SUB_FLAG);
                        reset_flag(HALF_CARRY_FLAG);
@@ -347,8 +354,8 @@ void GameBoy::run_cycle()
                for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, CP_reg)
 
                case 0xBE: {//SUB (HL)
-                       int res = regs.A - memory[regs.HL];
-                       int half_res = (regs.A & 0x0F) - (memory[regs.HL] & 0x0F);
+                       int res = regs.A - memory.read(regs.HL);
+                       int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
                        regs.A = static_cast<u8>(res);
 
                        set_flag(ADD_SUB_FLAG);
@@ -359,7 +366,7 @@ void GameBoy::run_cycle()
                        }
                
                case 0xFE: {//SUB #
-                       int inm = memory[regs.PC++];
+                       int inm = memory.read(regs.PC++);
                        int res = regs.A - inm;
                        int half_res = (regs.A & 0x0F) - (inm & 0x0F);
                        regs.A = static_cast<u8>(res);
@@ -375,10 +382,10 @@ void GameBoy::run_cycle()
                for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, INC_reg)
 
                case 0x34: {//INC (HL)
-                       int half_res = (memory[regs.HL] & 0x0F) + 1; 
-                       ++memory[regs.HL]
+                       int half_res = (memory.read(regs.HL) & 0x0F) + 1; 
+                       memory.write(regs.HL, memory.read(regs.HL) - 1)
                        reset_flag(ADD_SUB_FLAG); 
-                       set_flag_if (memory[regs.HL] == 0, ZERO_FLAG); 
+                       set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG); 
                        set_flag_if (half_res > 0x0F,      HALF_CARRY_FLAG); 
                        break; 
                        }       
@@ -387,10 +394,10 @@ void GameBoy::run_cycle()
                for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, DEC_reg)
 
                case 0x35: {//DEC (HL)
-                       int half_res = (memory[regs.HL] & 0x0F) - 1; 
-                       --memory[regs.HL]
+                       int half_res = (memory.read(regs.HL) & 0x0F) - 1; 
+                       memory.write(regs.HL, memory.read(regs.HL) - 1)
                        set_flag(ADD_SUB_FLAG); 
-                       set_flag_if (memory[regs.HL] == 0, ZERO_FLAG); 
+                       set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG); 
                        set_flag_if (half_res < 0,         HALF_CARRY_FLAG);
                        break; 
                        }
@@ -402,7 +409,7 @@ void GameBoy::run_cycle()
                // ADD SP, #
                case 0xE8: {
                        // FIXME: No se que hacer con el half carry, en 4 o en 11?
-                       int n = static_cast<s8>(memory[regs.PC++]);
+                       int n = static_cast<s8>(memory.read(regs.PC++));
                        int res = regs.SP + n;
                        regs.SP = static_cast<u8>(res);
                        reset_flag(ZERO_FLAG);
@@ -420,16 +427,16 @@ void GameBoy::run_cycle()
                // Miscellaneous instructions
                // SWAP n
                case 0xCB: {
-                       int sub_opcode = memory[regs.PC++];
+                       int sub_opcode = memory.read(regs.PC++);
                        switch(sub_opcode)
                        {
                                for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, SWAP_reg)
 
                                // SWAP (HL)
                                case 0x36: {
-                                       u8 tmp = memory[regs.HL];
+                                       u8 tmp = memory.read(regs.HL);
                                        tmp = ((tmp & 0x0F) << 4) | ((tmp & 0xF0)>>4);
-                                       memory[regs.HL] = tmp;
+                                       memory.write(regs.HL, tmp);
                
                                        set_flag_if(tmp==0, ZERO_FLAG);
                                        reset_flag(CARRY_FLAG);
@@ -501,30 +508,215 @@ void GameBoy::run_cycle()
                        break;
 
                // STOP
-               case 0x10:
-                       int sub_opcode = memory[regs.PC++];
+               case 0x10: {
+                       int sub_opcode = memory.read(regs.PC++);
                        if (sub_opcode == 0x00) {
                                HALT = true;
                        } else {
                                logger.critical("Unknown sub-opcode after 0x10");
                        }
+                       break;
+               }
+               
+               // DI
+               case 0xF3:
+                       IME = 0;
+                       break;
 
+               // EI
+               case 0xFB:
+                       IME = 1;
+                       break;
+                          
+               // TODO: Rotates and shifts
+               // TODO: Bit instructions
+               
+               // Jumps
+               // JP nn
+               case 0xC3:
+                       regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       break;
 
+               // JP cc, nn
+               case 0xC2: { // JP NZ, nn
+                       u16 dst = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       if (!check_flag(ZERO_FLAG))
+                               regs.PC = dst;
+                       else
+                               regs.PC += 2; // if !cc, skip 2 dst bytes
+                       break;
+               }
 
+               case 0xCA: { // JP Z, nn
+                       u16 dst = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       if (check_flag(ZERO_FLAG))
+                               regs.PC = dst;
+                       else
+                               regs.PC += 2; // if !cc, skip 2 dst bytes
+                       break;
+               }
 
+               case 0xD2: { // JP NC, nn
+                       u16 dst = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       if (!check_flag(CARRY_FLAG))
+                               regs.PC = dst;
+                       else
+                               regs.PC += 2; // if !cc, skip 2 dst bytes
+                       break;
+               }
 
+               case 0xDA: { // JP C, nn
+                       u16 dst = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       if (check_flag(CARRY_FLAG))
+                               regs.PC = dst;
+                       else
+                               regs.PC += 2; // if !cc, skip 2 dst bytes
+                       break;
+               }
 
-                       
+               // JP (HL)
+               case 0xE9:
+                       regs.PC = regs.HL;
+                       break;
 
+               // JR n
+               case 0x18:
+                       // -1 because PC is now pointing past the opcode
+                       regs.PC += static_cast<s8>(memory.read(regs.PC)) - 1;
+                       break;
 
+               // JR cc, n
+               case 0x20: { // JR NZ, n
+                       s8 offset = static_cast<s8>(memory.read(regs.PC++));
+                       if (!check_flag(ZERO_FLAG)) // -1 because PC is now pointing past the opcode
+                               regs.PC += offset;
+                       break;
+               }
 
+               case 0x28: { // JR Z, n
+                       s8 offset = static_cast<s8>(memory.read(regs.PC++));
+                       if (check_flag(ZERO_FLAG)) // -1 because PC is now pointing past the opcode
+                               regs.PC += offset;
+                       break;
+               }
+
+               case 0x30: { // JR NC, n
+                       s8 offset = static_cast<s8>(memory.read(regs.PC++));
+                       if (!check_flag(CARRY_FLAG)) // -1 because PC is now pointing past the opcode
+                               regs.PC += offset;
+                       break;
+               }
 
+               case 0x38: { // JR C, n
+                       s8 offset = static_cast<s8>(memory.read(regs.PC++));
+                       if (check_flag(CARRY_FLAG)) // -1 because PC is now pointing past the opcode
+                               regs.PC += offset;
+                       break;
+               }
 
+               // Calls
+               // CALL nn
+               case 0xCD: {
+                       // push, then jump
+                       u16 retaddr = regs.PC+2;
+                       memory.write(regs.SP-1, retaddr >> 8); // high
+                       memory.write(regs.SP-2, retaddr & 0xFF); // low
+                       regs.SP -= 2;
                        
+                       regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       break;
+               }
 
+               // CALL cc, nn
+               case 0xC4: { // CALL NZ, nn
+                       if (!check_flag(ZERO_FLAG)) {
+                               // push, then jump
+                               u16 retaddr = regs.PC+2;
+                               memory.write(regs.SP-1, retaddr >> 8); // high
+                               memory.write(regs.SP-2, retaddr & 0xFF); // low
+                               regs.SP -= 2;
 
+                               regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       } else {
+                               regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                       }
+               }
 
-       }
+               case 0xCC: { // CALL Z, nn
+                       if (check_flag(ZERO_FLAG)) {
+                               // push, then jump
+                               u16 retaddr = regs.PC+2;
+                               memory.write(regs.SP-1, retaddr >> 8); // high
+                               memory.write(regs.SP-2, retaddr & 0xFF); // low
+                               regs.SP -= 2;
+
+                               regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       } else {
+                               regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                       }
+               }
+
+               case 0xD4: { // CALL NC, nn
+                       if (!check_flag(CARRY_FLAG)) {
+                               // push, then jump
+                               u16 retaddr = regs.PC+2;
+                               memory.write(regs.SP-1, retaddr >> 8); // high
+                               memory.write(regs.SP-2, retaddr & 0xFF); // low
+                               regs.SP -= 2;
+
+                               regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       } else {
+                               regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                       }
+               }
+
+               case 0xDC: { // CALL C, nn
+                       if (check_flag(CARRY_FLAG)) {
+                               // push, then jump
+                               u16 retaddr = regs.PC+2;
+                               memory.write(regs.SP-1, retaddr >> 8); // high
+                               memory.write(regs.SP-2, retaddr & 0xFF); // low
+                               regs.SP -= 2;
+
+                               regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8);
+                       } else {
+                               regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                       }
+               }
+
+               // TODO: Restarts
+               // TODO: Returns
+
+               default:
+                       std::ostringstream errmsg;
+                       errmsg << "Unknown opcode 0x";
+                       errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode;
+                       errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1;
+                       errmsg << " (cycle count = " << std::dec << cycle_count << ")";
+                       logger.critical(errmsg.str());
+                       break;
+
+       } // end switch
+
+       std::ostringstream tracemsg;
+       tracemsg << "t = " << std::dec << cycle_count << 
+               "\tPC = " << std::hex << std::setw(4) << std::setfill('0') << regs.PC << std::endl <<
+               "A = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.A) <<
+               " B = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.B) <<
+               " C = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.C) <<
+               " D = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.D) <<
+               " E = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.E) <<
+               " H = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.H) <<
+               " L = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.L) <<
+               "\tflags = " << int(regs.flags) << "\tZF = " << check_flag(ZERO_FLAG);
+       logger.trace(tracemsg.str());
+       ++cycle_count;
 
 }
 
+void GameBoy::run() 
+{
+}
+
+
+
index 5915453362407156d81781ee03f1b702b8233a34..d3c0a8b6e091c3b2b4a3f65da4d69a906437de82 100644 (file)
--- a/gbcore.h
+++ b/gbcore.h
@@ -51,22 +51,13 @@ class GameBoy
        } __attribute__((packed)) regs;
 
 
-       union
-       {
-               struct
-               {
-               };
-
-               u8 addr[128];
-
-       } IO;
-
        u8 IME; // Interrupt master enable flag
        u8 HALT; // Is the CPU halted waiting for an interrupt?
+       u32 cycle_count;
 
        void set_flag(const u8 f) { regs.flags |= f; }
        void reset_flag(const u8 f) { regs.flags &= (~f); }
-       bool check_flag(const u8 f) { return (regs.flags & f != 0); }
+       bool check_flag(const u8 f) { return ((regs.flags & f) != 0); }
 
        public:
        GameBoy(std::string rom_name);
index 370afc43796c4a549d609875bbc455de048455d5..5ab12972dae6b0428713feab06a70f92eedb31fc 100644 (file)
--- a/opcodes.h
+++ b/opcodes.h
@@ -23,7 +23,7 @@
 
 #define LD_reg_nn(opcode, reg) \
        case opcode: \
-               regs.reg = memory[regs.PC++]; \
+               regs.reg = memory.read(regs.PC++); \
                break;
 
 #define LD_reg_reg(opcode, reg1, reg2) \
 // LD reg, (HL)
 #define LD_reg__HL_(opcode, reg) \
        case opcode: \
-               regs.reg = memory[regs.HL]; \
+               regs.reg = memory.read(regs.HL); \
                break;
 
 // LD (HL), reg
 #define LD__HL__reg(opcode, reg) \
        case opcode: \
-               memory[regs.HL] = regs.reg; \
+               memory.write(regs.HL, regs.reg); \
                break;
 
 #define PUSH(opcode, regH, regL) \
        case opcode: \
-               memory[regs.SP-1] = regs.regH; \
-               memory[regs.SP-2] = regs.regL; \
+               memory.write(regs.SP-1, regs.regH); \
+               memory.write(regs.SP-2, regs.regL); \
                regs.SP -= 2; \
                break;
 
 #define POP(opcode, regH, regL) \
        case opcode: \
-               regs.regL = memory[regs.SP]; \
-               regs.regH = memory[regs.SP+1]; \
+               regs.regL = memory.read(regs.SP); \
+               regs.regH = memory.read(regs.SP+1); \
                regs.SP += 2; \
                break;
 
diff --git a/tests/test_core.cc b/tests/test_core.cc
new file mode 100644 (file)
index 0000000..6a6b257
--- /dev/null
@@ -0,0 +1,13 @@
+#include "../gbcore.h"
+#include <iostream>
+
+int main(int argc, char **argv)
+{
+       GameBoy gb(argv[1]);
+       while(1)
+       {
+               gb.run_cycle();
+       }
+
+
+}