diff --git a/gameboy/cartridge/cartridge.cpp b/gameboy/cartridge/cartridge.cpp index aaf2c30d..6e79803b 100755 --- a/gameboy/cartridge/cartridge.cpp +++ b/gameboy/cartridge/cartridge.cpp @@ -1,5 +1,7 @@ #include +#include + #define CARTRIDGE_CPP namespace GameBoy { @@ -8,9 +10,15 @@ namespace GameBoy { #include "mbc2/mbc2.cpp" #include "mbc3/mbc3.cpp" #include "mbc5/mbc5.cpp" +#include "mmm01/mmm01.cpp" +#include "huc1/huc1.cpp" +#include "huc3/huc3.cpp" Cartridge cartridge; void Cartridge::load(uint8_t *data, unsigned size) { +//uint32_t crc = crc32_calculate(data, size); +//print("CRC32 = ", hex<4>(crc), "\n"); + romdata = new uint8[romsize = size]; memcpy(romdata, data, size); @@ -37,6 +45,9 @@ void Cartridge::load(uint8_t *data, unsigned size) { case 0x06: info.mapper = Mapper::MBC2; info.ram = true; info.battery = true; break; case 0x08: info.mapper = Mapper::MBC0; info.ram = true; break; case 0x09: info.mapper = Mapper::MBC0; info.ram = true; info.battery = true; break; + case 0x0b: info.mapper = Mapper::MMM01; break; + case 0x0c: info.mapper = Mapper::MMM01; info.ram = true; break; + case 0x0d: info.mapper = Mapper::MMM01; info.ram = true; info.battery = true; break; case 0x0f: info.mapper = Mapper::MBC3; info.rtc = true; info.battery = true; break; case 0x10: info.mapper = Mapper::MBC3; info.rtc = true; info.ram = true; info.battery = true; break; case 0x11: info.mapper = Mapper::MBC3; break; @@ -48,8 +59,12 @@ void Cartridge::load(uint8_t *data, unsigned size) { case 0x1c: info.mapper = Mapper::MBC5; info.rumble = true; break; case 0x1d: info.mapper = Mapper::MBC5; info.rumble = true; info.ram = true; break; case 0x1e: info.mapper = Mapper::MBC5; info.rumble = true; info.ram = true; info.battery = true; break; - default: print("Unknown mapper: ", hex<2>(romdata[0x0147]), "\n"); break; + case 0xfc: break; //Pocket Camera + case 0xfd: break; //Bandai TAMA5 + case 0xfe: info.mapper = Mapper::HuC3; break; + case 0xff: info.mapper = Mapper::HuC1; info.ram = true; info.battery = true; break; } + print("Mapper: ", hex<2>(romdata[0x0147]), "\n"); switch(romdata[0x0148]) { default: case 0x00: info.romsize = 2 * 16 * 1024; break; @@ -88,6 +103,8 @@ void Cartridge::unload() { } uint8 Cartridge::rom_read(unsigned addr) { +//if(addr >= 0x028000) print(hex<6>(addr), " - ", romsize, "\n"); + if(addr >= romsize) addr %= romsize; return romdata[addr]; } @@ -115,14 +132,20 @@ void Cartridge::power() { mbc2.power(); mbc3.power(); mbc5.power(); + mmm01.power(); + huc1.power(); + huc3.power(); MMIO *mapper = 0; switch(info.mapper) { default: - case Mapper::MBC0: mapper = &mbc0; break; - case Mapper::MBC1: mapper = &mbc1; break; - case Mapper::MBC2: mapper = &mbc2; break; - case Mapper::MBC3: mapper = &mbc3; break; - case Mapper::MBC5: mapper = &mbc5; break; + case Mapper::MBC0: mapper = &mbc0; break; + case Mapper::MBC1: mapper = &mbc1; break; + case Mapper::MBC2: mapper = &mbc2; break; + case Mapper::MBC3: mapper = &mbc3; break; + case Mapper::MBC5: mapper = &mbc5; break; + case Mapper::MMM01: mapper = &mmm01; break; + case Mapper::HuC1: mapper = &huc1; break; + case Mapper::HuC3: mapper = &huc3; break; } if(mapper) { diff --git a/gameboy/cartridge/cartridge.hpp b/gameboy/cartridge/cartridge.hpp index b04d16a0..633a947f 100755 --- a/gameboy/cartridge/cartridge.hpp +++ b/gameboy/cartridge/cartridge.hpp @@ -4,6 +4,9 @@ struct Cartridge : property { #include "mbc2/mbc2.hpp" #include "mbc3/mbc3.hpp" #include "mbc5/mbc5.hpp" + #include "mmm01/mmm01.hpp" + #include "huc1/huc1.hpp" + #include "huc3/huc3.hpp" enum Mapper : unsigned { MBC0, @@ -11,6 +14,9 @@ struct Cartridge : property { MBC2, MBC3, MBC5, + MMM01, + HuC1, + HuC3, Unknown, }; diff --git a/gameboy/cartridge/huc1/huc1.cpp b/gameboy/cartridge/huc1/huc1.cpp new file mode 100755 index 00000000..8f64b560 --- /dev/null +++ b/gameboy/cartridge/huc1/huc1.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::HuC1::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + rom_select = data; + return; + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + ram_select = data; + return; + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + //unknown purpose + return; + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; + } +} + +void Cartridge::HuC1::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/gameboy/cartridge/huc1/huc1.hpp b/gameboy/cartridge/huc1/huc1.hpp new file mode 100755 index 00000000..f7bcc37d --- /dev/null +++ b/gameboy/cartridge/huc1/huc1.hpp @@ -0,0 +1,9 @@ +struct HuC1 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} huc1; diff --git a/gameboy/cartridge/huc3/huc3.cpp b/gameboy/cartridge/huc3/huc3.cpp new file mode 100755 index 00000000..aef74d69 --- /dev/null +++ b/gameboy/cartridge/huc3/huc3.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::HuC3::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + rom_select = data; + return; + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + ram_select = data; + return; + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + //unknown purpose + return; + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; + } +} + +void Cartridge::HuC3::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/gameboy/cartridge/huc3/huc3.hpp b/gameboy/cartridge/huc3/huc3.hpp new file mode 100755 index 00000000..407d3bd4 --- /dev/null +++ b/gameboy/cartridge/huc3/huc3.hpp @@ -0,0 +1,9 @@ +struct HuC3 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} huc3; diff --git a/gameboy/cartridge/mmm01/mmm01.cpp b/gameboy/cartridge/mmm01/mmm01.cpp new file mode 100755 index 00000000..7bef9219 --- /dev/null +++ b/gameboy/cartridge/mmm01/mmm01.cpp @@ -0,0 +1,65 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MMM01::mmio_read(uint16 addr) { + if((addr & 0x8000) == 0x0000) { + if(rom_mode == 0) return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x0000) { + return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff)); + } + + if((addr & 0xc000) == 0x4000) { + return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { + if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + if(rom_mode == 0) { + rom_mode = 1; + } else { + ram_enable = (data & 0x0f) == 0x0a; + } + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + if(rom_mode == 0) { + rom_base = data & 0x3f; + } else { + rom_select = data; + } + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + if(rom_mode == 1) { + ram_select = data; + } + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + //unknown purpose + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data); + } +} + +void Cartridge::MMM01::power() { + rom_mode = 0; + rom_base = 0x00; + + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/gameboy/cartridge/mmm01/mmm01.hpp b/gameboy/cartridge/mmm01/mmm01.hpp new file mode 100755 index 00000000..3474b062 --- /dev/null +++ b/gameboy/cartridge/mmm01/mmm01.hpp @@ -0,0 +1,12 @@ +struct MMM01 : MMIO { + bool rom_mode; + uint8 rom_base; + + bool ram_enable; + uint8 rom_select; + uint8 ram_select; + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mmm01; diff --git a/gameboy/gameboy.hpp b/gameboy/gameboy.hpp index 1a51634b..4327602e 100755 --- a/gameboy/gameboy.hpp +++ b/gameboy/gameboy.hpp @@ -5,7 +5,7 @@ namespace GameBoy { namespace Info { static const char Name[] = "bgameboy"; - static const char Version[] = "000.08"; + static const char Version[] = "000.09"; } }