Mas cosas sobre memoria y MBCs
authorslack <slack@0666ae3d-8926-0410-aeff-ae84559ff337>
Sun, 19 Aug 2007 02:39:00 +0000 (02:39 +0000)
committerslack <slack@0666ae3d-8926-0410-aeff-ae84559ff337>
Sun, 19 Aug 2007 02:39:00 +0000 (02:39 +0000)
git-svn-id: http://slack.codemaniacs.com/wenboi@6 0666ae3d-8926-0410-aeff-ae84559ff337

GBMemory.cc [new file with mode: 0644]
GBMemory.h
GBRom.h
MBC.cc [new file with mode: 0644]
MBC.h
Makefile
gbcore.cc
gbcore.h
logger.h

diff --git a/GBMemory.cc b/GBMemory.cc
new file mode 100644 (file)
index 0000000..c9d1345
--- /dev/null
@@ -0,0 +1,43 @@
+#include "GBMemory.h"
+#include "MBC.h"
+#include "gbcore.h"
+
+u8& GBMemory::operator[](unsigned int addr)
+{
+       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];
+       else {
+               logger.error("Invalid write address");
+               return *(static_cast<u8*>(0));
+       }
+}
+
+
+u8  GBMemory::operator[](unsigned 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];
+       else if (addr >= 0xFF00 && addr <= 0xFF7F) 
+               return core->IO.addr[addr-0xFF00];
+       else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr-0xFF80];
+       else {
+               logger.error("Invalid write address");
+               return *(static_cast<u8*>(0));
+       }
+}
+
+
+
index 8119c47856d2be834d6e04d73cbcdeb31c341a7f..6e02479deedd771d15fd1aaf11b74e207d99e235 100644 (file)
@@ -2,10 +2,13 @@
 #define GBMEMORY_H
 
 #include "sized_types.h"
-#include "MBC.h"
+
+class GameBoy;
+class MBC;
 
 class GBMemory
 {
+       GameBoy *core;
        MBC *mbc;
                        // 0000-3FFF: ROM Bank 0 (in cart)
                        // 4000-7FFF: Switchable ROM Bank (in cart)
@@ -18,12 +21,12 @@ class GBMemory
        u8 HRAM[126];   // FF80-FFFE: High RAM
 
        public:
-       GBMemory(): mbc(0) {}
+       GBMemory(GameBoy *core): core(core), mbc(0) {}
        void init(MBC *mbc) { this->mbc = mbc; }
 
 
-       int& operator[](int index)=0;
-       int  operator[](int index) const=0;
+       u8& operator[](unsigned int addr);
+       u8  operator[](unsigned int addr) const;
 
 };
 
diff --git a/GBRom.h b/GBRom.h
index c88dd81e4cc4ab9a47e48a5ffa282ac0a9fb8b86..365f90078e36e55a00488c02b72d6cbd2936d5ff 100644 (file)
--- a/GBRom.h
+++ b/GBRom.h
@@ -4,7 +4,7 @@
 #include "sized_types.h"
 #include <string>
 
-namespace cartrigde_types {
+namespace cartridge_types {
        const u8 ROM_ONLY=0x00;
        const u8 MBC1=0x01;
        const u8 MBC1_RAM=0x02;
diff --git a/MBC.cc b/MBC.cc
new file mode 100644 (file)
index 0000000..112ffa3
--- /dev/null
+++ b/MBC.cc
@@ -0,0 +1,16 @@
+#include "MBC.h"
+#include "logger.h"
+
+using namespace cartridge_types;
+
+MBC *create_MBC(GBRom *rom)
+{
+       switch (rom->header.cartridge_type)
+       {
+               case ROM_ONLY:          return new NoMBC(rom);
+               //case MBC1:            return new MBC1(rom);
+               default:
+                       logger.critical("Unsupported cartridge type");
+                       return 0;
+       }
+}
diff --git a/MBC.h b/MBC.h
index 0d4babaaad40e1b0a8182f797ba53c3563f06262..2f52f90e02372200243640557186647c8a3dac8e 100644 (file)
--- a/MBC.h
+++ b/MBC.h
@@ -2,11 +2,48 @@
 #define MBC_H
 
 #include "sized_types.h"
+#include "GBRom.h"
+#include "logger.h"
+#include <cstring>
 
 class MBC
 {
-       virtual u8 read_byte() const=0;
-       virtual void write_byte(u8)=0;
+       public:
+       virtual u8  operator[](unsigned int addr) const=0;
+       virtual u8& operator[](unsigned int addr)=0;
+       virtual ~MBC();
 };
 
+class NoMBC: public MBC
+{
+       u8 ROM[32768];
+       u8 RAM[8192];
+       
+       public:
+       NoMBC(GBRom *rom) { memcpy(ROM, rom->data, 32768); }
+
+       u8 operator[](unsigned int addr) const
+       {
+               if (addr <= 0x7FFF)
+                       return ROM[addr];
+               else if ((addr&0xE000) == 0xA000)   //(addr >= 0xA000 && addr <= 0xBFFF)
+                       return RAM[addr-0xA000];
+               else
+                       logger.error("NoMBC: Incorrect read");
+               return 0;
+       }
+
+       u8& operator[](unsigned int addr) 
+       {
+               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
+       }
+};
+
+
+MBC *create_MBC(GBRom *rom);
+
 #endif // MBC_H
index 274c684bd9145daa7caee5df4d66c30f448302f7..ca4ff790d43ec1f6dcef3a6ef5e57f572e293dd6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,23 @@
 CXXFLAGS=-g -Wall -Weffc++ -Wstrict-null-sentinel -Wold-style-cast \
         -Woverloaded-virtual 
 
-all: gbcore.o
+all: gbcore.o MBC.o GBMemory.o logger.o
 
 tests: tests/test_gbrom
 
-gbcore.o: gbcore.cc gbcore.h gbrom.h
+logger.o: logger.cc logger.h
+       g++ $(CXXFLAGS) -c -o $@ $<
+
+GBMemory.o: GBMemory.cc GBMemory.h
+       g++ $(CXXFLAGS) -c -o $@ $<
+
+MBC.o: MBC.cc MBC.h
+       g++ $(CXXFLAGS) -c -o $@ $<
+
+gbcore.o: gbcore.cc gbcore.h GBRom.h logger.h MBC.h GBMemory.h
        g++ $(CXXFLAGS) -c -o $@ $<
                
-tests/test_gbrom: gbrom.cc gbrom.h
+tests/test_gbrom: GBRom.cc GBRom.h
        g++ -DTEST_GBROM -o $@ $<
 
 clean:
index 9bd08e66e9b4879563e3616fb33667d97565a21e..f9875ac2e69123b744c6577a05d3b0b623c7a691 100644 (file)
--- a/gbcore.cc
+++ b/gbcore.cc
 #include "gbcore.h"
 
-#include "sized_types.h"
 #include "GBRom.h"
-#include "GBMemory.h"
 #include "MBC.h"
 #include "logger.h"
 #include <string>
 #include <cstring>
 
-class MBC
-{
-       virtual u8 read_byte() const=0;
-       virtual void write_byte(u8)=0;
-};
-
-class GBMemory
-{
-       MBC *mbc;
-                       // 0000-3FFF: ROM Bank 0 (in cart)
-                       // 4000-7FFF: Switchable ROM Bank (in cart)
-       u8 VRAM[8192];  // 8000-9FFF: Video RAM
-                       // A000-BFFF: External RAM (in cart, switchable)
-       u8 WRAM0[4096]; // C000-CFFF: Work RAM Bank 0
-       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
-       u8 HRAM[126];   // FF80-FFFE: High RAM
-
-       public:
-       GBMemory(): mbc(0) {}
-       void init(MBC *mbc) { this->mbc = mbc; }
-
-
-       int& operator[](int index)=0;
-       int  operator[](int index) const=0;
-
-};
-
-class GameBoy
-{
-       GBMemory memory;
-       GBRom *rom;
-
-       enum flags_enum
-       {
-               ZERO_FLAG=0x80,
-               ADD_SUB_FLAG=0x40,
-               HALF_CARRY_FLAG=0x20,
-               CARRY_FLAG=0x10,
-       };
-
-       // CPU Registers
-       // ENDIANNESS WARNING!
-       struct 
-       {
-               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;
-
-       } __attribute__((packed)) regs;
-
-       u8 IME; // Interrupt master enable flag
-       u8 HALT; // Is the CPU halted waiting for an interrupt?
-
-       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); }
-
-       public:
-       GameBoy(std::string rom_name);
-
-       void reset();
-       void run_cycle();
-       void run();
-
-};
-
 GameBoy::GameBoy(std::string rom_name):
-       rom(0), regs(), IME(1), HALT(0)
+       memory(this),rom(0), regs(), IO(), IME(1), HALT(0)
 {
        logger.info("GameBoy init");
        rom = read_gbrom(rom_name);
+
+       MBC *mbc = create_MBC(rom);
+       memory.init(mbc);
+       
        reset();
 }
 
 void GameBoy::reset()
 {
        logger.info("GameBoy reset");
-       std::memcpy(memory, rom->data, 16384);
        regs.PC = 0x100;
 }
 
@@ -235,7 +149,7 @@ void GameBoy::run_cycle()
                // LD HL, SP+n
                // LDHL SP, n
                case 0xF8: {
-                       s8 offset = *(reinterpret_cast<s8*>(memory+regs.PC++));
+                       s8 offset = memory[regs.PC++];
                        int res = regs.SP + offset;
                        
                        // TODO: Verificar si los flags van asi
@@ -488,7 +402,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 = *(reinterpret_cast<s8*>(memory+regs.PC++));
+                       int n = static_cast<s8>(memory[regs.PC++]);
                        int res = regs.SP + n;
                        regs.SP = static_cast<u8>(res);
                        reset_flag(ZERO_FLAG);
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5915453362407156d81781ee03f1b702b8233a34 100644 (file)
--- a/gbcore.h
+++ b/gbcore.h
@@ -0,0 +1,80 @@
+#ifndef GBCORE_H
+#define GBCORE_H
+
+#include "sized_types.h"
+#include "GBMemory.h"
+#include <string>
+
+union GBRom;
+
+class GameBoy
+{
+       friend class GBMemory;
+       GBMemory memory;
+       GBRom *rom;
+
+       enum flags_enum
+       {
+               ZERO_FLAG=0x80,
+               ADD_SUB_FLAG=0x40,
+               HALF_CARRY_FLAG=0x20,
+               CARRY_FLAG=0x10,
+       };
+
+       // CPU Registers
+       // ENDIANNESS WARNING!
+       struct 
+       {
+               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;
+
+       } __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?
+
+       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); }
+
+       public:
+       GameBoy(std::string rom_name);
+
+       void reset();
+       void run_cycle();
+       void run();
+
+};
+
+#endif
index 3649563442267ae44b2a3510d1e933030846a609..8d0138a7b53f2c72b2ed1d70766e98734fd14ed6 100644 (file)
--- a/logger.h
+++ b/logger.h
@@ -12,9 +12,6 @@ class Logger
                static Logger instance;
 
        public:
-               static Logger& getInstance() { return instance; }
-               Logger(std::ostream& os): out(os) {}
-
                enum log_level{
                        OFF = -1,
                        CRITICAL=0,
@@ -25,6 +22,11 @@ class Logger
                        TRACE=5
                };
 
+               static Logger& getInstance() { return instance; }
+               Logger(std::ostream& os): 
+                       out(os), 
+                       current_log_level(TRACE) {}
+
                log_level current_log_level;
 
 
@@ -40,6 +42,8 @@ class Logger
                void info    (std::string str) { log(INFO    , str); }
                void debug   (std::string str) { log(DEBUG   , str); }
                void trace   (std::string str) { log(TRACE   , str); }
+
+               void set_log_level (log_level level) { current_log_level = level; }
 };
 
 #define logger Logger::getInstance()