#include "MBC.h"
-#include "Logger.h"
-#include <cstring>
-#include <sstream>
-#include <iostream>
-#include <iomanip>
+#include "NoMBC.h"
+#include "MBC1.h"
-using namespace cartridge_types;
+#include "Logger.h"
MBC *create_MBC(GBRom *rom)
{
switch (rom->header.cartridge_type)
{
- case ROM_ONLY: return new NoMBC(rom);
- //case MBC1: return new MBC1(rom);
+ case cartridge_types::ROM_ONLY: return new NoMBC(rom);
+ case cartridge_types::MBC1: return new MBC1(rom);
default:
logger.critical("Unsupported cartridge type ",
int(rom->header.cartridge_type));
}
}
-u8 NoMBC::read(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;
-}
-
-u16 NoMBC::read16(int addr) const
-{
- if (addr <= 0x7FFF)
- return ROM[addr]+(ROM[addr+1] << 8);
- else //if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF)
- return RAM[addr-0xA000] + (RAM[addr-0xA000+1] << 8);
- //else
- // logger.error("NoMBC: Incorrect read");
- return 0;
-}
-
-void NoMBC::write(int addr, u8 value)
-{
- 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.debug(errmsg.str());
- }
-}
-
class MBC
{
public:
- virtual u8 read(int addr) const=0;
- virtual u16 read16(int addr) const=0;
- virtual void write(int addr, u8 value)=0;
+ virtual u8 read (u16 addr) const=0;
+ virtual u16 read16(u16 addr) const=0;
+ virtual void write (u16 addr, u8 value)=0;
virtual ~MBC() {};
};
-class NoMBC: public MBC
-{
- u8 ROM[32768];
- u8 RAM[8192];
-
- public:
- NoMBC(GBRom *rom) { memcpy(ROM, rom->data, 32768); }
- u8 read (int addr) const;
- void write(int addr, u8 value);
-
- u16 read16(int addr) const;
-};
-
MBC *create_MBC(GBRom *rom);
--- /dev/null
+#include "MBC1.h"
+#include "Logger.h"
+
+#include <iomanip>
+#include <cassert>
+
+u8 MBC1::read(u16 addr) const
+{
+ if (addr <= 0x3FFF) // ROM Bank 0
+ return ROM[addr];
+ else if (addr <= 0x7FFF) // ROM (switchable)
+ {
+ u8 rom_bank = rom_bank_low;
+ if (mode == ROM_BANKING_MODE) rom_bank |= (ram_bank << 5);
+
+ u32 base = 16384*rom_bank;
+ return ROM[base + (addr-0x4000)];
+ }
+ else // if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF)
+ {
+ if (ram_enabled)
+ {
+ u32 base = (mode == RAM_BANKING_MODE ? 8192*ram_bank : 0);
+ return RAM[base + (addr-0xA000)];
+ }
+ else return 0xFF;
+ }
+ //else
+ // logger.error("MBC1: Incorrect read");
+ return 0;
+}
+
+u16 MBC1::read16(u16 addr) const
+{
+ assert (addr != 0x3FFF);
+ assert (addr != 0x7FFF);
+ assert (addr != 0xBFFF);
+
+ if (addr <= 0x3FFF) // ROM Bank 0
+ return ROM[addr] | (ROM[addr+1] << 8);
+ else if (addr <= 0x7FFF) // ROM (switchable)
+ {
+ u8 rom_bank = rom_bank_low;
+ if (mode == ROM_BANKING_MODE) rom_bank |= (ram_bank << 5);
+
+ u32 offset = 16384*rom_bank + (addr-0x4000);
+ return ROM[offset] | (ROM[offset+1] << 8);
+ }
+ else // if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF)
+ {
+ if (ram_enabled)
+ {
+ u32 base = (mode == RAM_BANKING_MODE ? 8192*ram_bank : 0);
+ u32 offset = base + (addr-0xA000);
+ return RAM[offset] | (RAM[offset+1] << 8);
+ }
+ else return 0xFFFF;
+ }
+ //else
+ // logger.error("MBC1: Incorrect read");
+ return 0;
+}
+
+void MBC1::write(u16 addr, u8 value)
+{
+ if (addr <= 0x1FFF)
+ {
+ if ((value & 0x0F) == 0x0A)
+ ram_enabled = true;
+ else
+ ram_enabled = false;
+ }
+ else if (addr <= 0x3FFF)
+ {
+ rom_bank_low = value & 0x1F;
+ if (rom_bank_low == 0) rom_bank_low = 1;
+ }
+ else if (addr <= 0x5FFF)
+ {
+ ram_bank = value & 0x03;
+ }
+ else if (addr <= 0x7FFF)
+ {
+ mode = BankingMode(value & 1);
+ }
+ else if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF)
+ {
+ u32 base = (mode == RAM_BANKING_MODE ? 8192*ram_bank : 0);
+ RAM[base + (addr-0xA000)]=value;
+ return;
+ }
+ else
+ {
+ logger.debug("MBC1: trying to write in ROM, addr=0x",std::hex,addr);
+ }
+}
+
+
--- /dev/null
+#ifndef MBC1_H
+#define MBC1_H
+
+
+#include "MBC.h"
+
+
+class MBC1: public MBC
+{
+ u8 ROM[128*16384];
+ u8 RAM[ 4* 8192];
+
+ u8 rom_bank_low;
+ u8 ram_bank;
+ bool ram_enabled;
+
+ enum BankingMode
+ {
+ ROM_BANKING_MODE=0,
+ RAM_BANKING_MODE=1
+ } mode;
+
+ public:
+ MBC1(GBRom *rom): rom_bank_low(1), ram_bank(0), ram_enabled(false), mode(ROM_BANKING_MODE)
+ {
+ memcpy(ROM, rom->data, 32768 << rom->header.rom_size);
+ }
+
+ u8 read (u16 addr) const;
+ u16 read16(u16 addr) const;
+ void write (u16 addr, u8 value);
+};
+
+#endif
+
-CXXFLAGS=-pg -O3 -g -Wall -Weffc++ -Wstrict-null-sentinel -Wold-style-cast \
+#CXXFLAGS=-pg -O3 -g -Wall -Weffc++ -Wstrict-null-sentinel -Wold-style-cast
+CXXFLAGS=-pg -O3 -g -Wall -Weffc++ -Wold-style-cast \
-Woverloaded-virtual $(shell sdl-config --cflags)
LDFLAGS=-pg -g $(shell sdl-config --libs)
GBMemory.o: GBMemory.cc GBMemory.h Logger.h MBC.h gbcore.h
g++ $(CXXFLAGS) -c -o $@ $<
-MBC.o: MBC.cc MBC.h Logger.h
+MBC.o: MBC.cc MBC.h Logger.h NoMBC.h MBC1.h
+ g++ $(CXXFLAGS) -c -o $@ $<
+
+NoMBC.o: NoMBC.cc NoMBC.h Logger.h
+ g++ $(CXXFLAGS) -c -o $@ $<
+
+MBC1.o: MBC1.cc MBC1.h Logger.h
g++ $(CXXFLAGS) -c -o $@ $<
gbcore.o: gbcore.cc gbcore.h opcodes.h disasm.h \
g++ $(CXXFLAGS) -c -o $@ $<
tests/test_gbrom: GBRom.cc GBRom.h
- g++ $(CXXFLAGS) $(LDFLAGS) -DTEST_GBROM -o $@ GBRom.cc
+ g++ $(CXXFLAGS) -DTEST_GBROM -o $@ GBRom.cc $(LDFLAGS)
tests/test_core: tests/test_core.cc gbcore.o MBC.o GBMemory.o GBRom.o \
- GBVideo.o util.o
- g++ $(CXXFLAGS) $(LDFLAGS) -o $@ $^
+ GBVideo.o util.o NoMBC.o MBC1.o
+ g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
clean:
rm -f *.o tests/test_gbrom tests/test_core
--- /dev/null
+#include "NoMBC.h"
+#include "Logger.h"
+
+#include <iomanip>
+
+u8 NoMBC::read(u16 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;
+}
+
+u16 NoMBC::read16(u16 addr) const
+{
+ if (addr <= 0x7FFF)
+ return ROM[addr] | (ROM[addr+1] << 8);
+ else //if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF)
+ {
+ u16 offset = addr - 0xA000;
+ return RAM[offset] | (RAM[offset+1] << 8);
+ }
+ //else
+ // logger.error("NoMBC: Incorrect read");
+ return 0;
+}
+
+void NoMBC::write(u16 addr, u8 value)
+{
+ if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF)
+ {
+ RAM[addr-0xA000]=value;
+ return;
+ }
+ else
+ {
+ logger.debug("NoMBC: trying to write in ROM, addr=0x", std::hex, addr);
+ }
+}
+
+
--- /dev/null
+#ifndef NOMBC_H
+#define NOMBC_H
+
+#include "MBC.h"
+
+class NoMBC: public MBC
+{
+ u8 ROM[32768];
+ u8 RAM[8192];
+
+ public:
+ NoMBC(GBRom *rom) { memcpy(ROM, rom->data, 32768); }
+ u8 read (u16 addr) const;
+ u16 read16(u16 addr) const;
+ void write (u16 addr, u8 value);
+
+};
+
+#endif