diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 25c6c5a7..a1e997a2 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "103.20"; + static const string Version = "103.21"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/gb/cartridge/cartridge.cpp b/higan/gb/cartridge/cartridge.cpp index 25ab6997..b07bd81b 100644 --- a/higan/gb/cartridge/cartridge.cpp +++ b/higan/gb/cartridge/cartridge.cpp @@ -2,6 +2,7 @@ namespace GameBoy { +Cartridge cartridge; #include "mbc0/mbc0.cpp" #include "mbc1/mbc1.cpp" #include "mbc1m/mbc1m.cpp" @@ -11,8 +12,8 @@ namespace GameBoy { #include "mmm01/mmm01.cpp" #include "huc1/huc1.cpp" #include "huc3/huc3.cpp" +#include "tama/tama.cpp" #include "serialization.cpp" -Cartridge cartridge; auto Cartridge::load() -> bool { information = {}; @@ -43,49 +44,40 @@ auto Cartridge::load() -> bool { auto board = document["board"]; information.title = document["information/title"].text(); - auto mapperid = document["board/mapper"].text(); - if(mapperid == "none" ) information.mapper = Mapper::MBC0; - if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1; - if(mapperid == "MBC1M") information.mapper = Mapper::MBC1M; - if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2; - if(mapperid == "MBC3" ) information.mapper = Mapper::MBC3; - if(mapperid == "MBC5" ) information.mapper = Mapper::MBC5; - if(mapperid == "MMM01") information.mapper = Mapper::MMM01; - if(mapperid == "HuC1" ) information.mapper = Mapper::HuC1; - if(mapperid == "HuC3" ) information.mapper = Mapper::HuC3; + auto mapperID = document["board/mapper"].text(); + if(mapperID == "MBC0" ) mapper = &mbc0; + if(mapperID == "MBC1" ) mapper = &mbc1; + if(mapperID == "MBC1M") mapper = &mbc1m; + if(mapperID == "MBC2" ) mapper = &mbc2; + if(mapperID == "MBC3" ) mapper = &mbc3; + if(mapperID == "MBC5" ) mapper = &mbc5; + if(mapperID == "MMM01") mapper = &mmm01; + if(mapperID == "HuC1" ) mapper = &huc1; + if(mapperID == "HuC3" ) mapper = &huc3; + if(mapperID == "TAMA" ) mapper = &tama; - information.rtc = false; - information.rumble = false; - - rom.size = max(32768u, board["rom/size"].natural()); + rom.size = max(0x4000, document["board/rom/size"].natural()); rom.data = (uint8*)memory::allocate(rom.size, 0xff); - - ram.size = board["ram/size"].natural(); - ram.data = (uint8*)memory::allocate(ram.size, 0xff); - - if(auto name = board["rom/name"].text()) { + if(auto name = document["board/rom/name"].text()) { if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) { fp->read(rom.data, min(rom.size, fp->size())); } } - if(auto name = board["ram/name"].text()) { + + ram.size = document["board/ram/size"].natural(); + ram.data = (uint8*)memory::allocate(ram.size, 0xff); + if(auto name = document["board/ram/name"].text()) { if(auto fp = platform->open(pathID(), name, File::Read, File::Optional)) { fp->read(ram.data, min(ram.size, fp->size())); } } - information.battery = (bool)board["ram/name"]; - - switch(information.mapper) { default: - case Mapper::MBC0: mapper = &mbc0; break; - case Mapper::MBC1: mapper = &mbc1; break; - case Mapper::MBC1M: mapper = &mbc1m; 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; + rtc.size = document["board/rtc/size"].natural(); + rtc.data = (uint8*)memory::allocate(rtc.size, 0xff); + if(auto name = document["board/rtc/name"].text()) { + if(auto fp = platform->open(pathID(), name, File::Read, File::Optional)) { + fp->read(rtc.data, min(rtc.size, fp->size())); + } } information.sha256 = Hash::SHA256(rom.data, rom.size).digest(); @@ -100,35 +92,21 @@ auto Cartridge::save() -> void { fp->write(ram.data, ram.size); } } + + if(auto name = document["board/rtc/name"].text()) { + if(auto fp = platform->open(pathID(), name, File::Write)) { + fp->write(rtc.data, rtc.size); + } + } } auto Cartridge::unload() -> void { delete[] rom.data; delete[] ram.data; + delete[] rtc.data; rom = {}; ram = {}; -} - -auto Cartridge::readROM(uint addr) -> uint8 { - if(addr >= rom.size) addr %= rom.size; - return rom.data[addr]; -} - -auto Cartridge::writeROM(uint addr, uint8 data) -> void { - if(addr >= rom.size) addr %= rom.size; - rom.data[addr] = data; -} - -auto Cartridge::readRAM(uint addr) -> uint8 { - if(ram.size == 0) return 0xff; - if(addr >= ram.size) addr %= ram.size; - return ram.data[addr]; -} - -auto Cartridge::writeRAM(uint addr, uint8 data) -> void { - if(ram.size == 0) return; - if(addr >= ram.size) addr %= ram.size; - ram.data[addr] = data; + rtc = {}; } auto Cartridge::readIO(uint16 addr) -> uint8 { @@ -140,10 +118,10 @@ auto Cartridge::readIO(uint16 addr) -> uint8 { if(Model::GameBoyColor()) data = system.bootROM.cgb; if(Model::SuperGameBoy()) data = system.bootROM.sgb; if(addr >= 0x0000 && addr <= 0x00ff) return data[addr]; - if(addr >= 0x0200 && addr <= 0x08ff && Model::GameBoyColor()) return data[addr - 256]; + if(addr >= 0x0200 && addr <= 0x08ff && Model::GameBoyColor()) return data[addr - 0x100]; } - return mapper->readIO(addr); + return mapper->read(addr); } auto Cartridge::writeIO(uint16 addr, uint8 data) -> void { @@ -152,25 +130,33 @@ auto Cartridge::writeIO(uint16 addr, uint8 data) -> void { return; } - mapper->writeIO(addr, data); + mapper->write(addr, data); } auto Cartridge::power() -> void { - bootromEnable = true; - - mbc0.power(); - mbc1.power(); - mbc1m.power(); - mbc2.power(); - mbc3.power(); - mbc5.power(); - mmm01.power(); - huc1.power(); - huc3.power(); - for(uint n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this; for(uint n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this; bus.mmio[0xff50] = this; + + bootromEnable = true; + + mapper->power(); +} + +auto Cartridge::second() -> void { + mapper->second(); +} + +auto Cartridge::Memory::read(uint address) const -> uint8 { + if(!size) return 0xff; + if(address >= size) address %= size; + return data[address]; +} + +auto Cartridge::Memory::write(uint address, uint8 byte) -> void { + if(!size) return; + if(address >= size) address %= size; + data[address] = byte; } } diff --git a/higan/gb/cartridge/cartridge.hpp b/higan/gb/cartridge/cartridge.hpp index 8c9d1ac4..06e5655f 100644 --- a/higan/gb/cartridge/cartridge.hpp +++ b/higan/gb/cartridge/cartridge.hpp @@ -8,19 +8,41 @@ struct Cartridge : MMIO { auto save() -> void; auto unload() -> void; - auto readROM(uint addr) -> uint8; - auto writeROM(uint addr, uint8 data) -> void; - - auto readRAM(uint addr) -> uint8; - auto writeRAM(uint addr, uint8 data) -> void; - - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; + auto readIO(uint16 address) -> uint8; + auto writeIO(uint16 address, uint8 data) -> void; auto power() -> void; + auto second() -> void; auto serialize(serializer&) -> void; + struct Information { + uint pathID = 0; + string sha256; + string manifest; + string title; + } information; + + struct Memory { + auto read(uint address) const -> uint8; + auto write(uint address, uint8 data) -> void; + + uint8* data = nullptr; + uint size = 0; + } rom, ram, rtc; + + bool bootromEnable = true; + +private: + struct Mapper { + virtual auto second() -> void {} + virtual auto read(uint16 address) -> uint8 = 0; + virtual auto write(uint16 address, uint8 data) -> void = 0; + virtual auto power() -> void = 0; + virtual auto serialize(serializer&) -> void = 0; + }; + Mapper* mapper = nullptr; + #include "mbc0/mbc0.hpp" #include "mbc1/mbc1.hpp" #include "mbc1m/mbc1m.hpp" @@ -30,40 +52,7 @@ struct Cartridge : MMIO { #include "mmm01/mmm01.hpp" #include "huc1/huc1.hpp" #include "huc3/huc3.hpp" - - enum Mapper : uint { - MBC0, - MBC1, - MBC1M, - MBC2, - MBC3, - MBC5, - MMM01, - HuC1, - HuC3, - Unknown, - }; - - struct Information { - uint pathID = 0; - string sha256; - string manifest; - string title; - - Mapper mapper = Mapper::Unknown; - boolean ram; - boolean battery; - boolean rtc; - boolean rumble; - } information; - - struct Memory { - uint8* data = nullptr; - uint size = 0; - } rom, ram; - - MMIO* mapper = nullptr; - bool bootromEnable = true; + #include "tama/tama.hpp" }; extern Cartridge cartridge; diff --git a/higan/gb/cartridge/huc1/huc1.cpp b/higan/gb/cartridge/huc1/huc1.cpp index 7080c062..6fadc198 100644 --- a/higan/gb/cartridge/huc1/huc1.cpp +++ b/higan/gb/cartridge/huc1/huc1.cpp @@ -1,49 +1,54 @@ -auto Cartridge::HuC1::readIO(uint16 addr) -> uint8 { - if((addr & 0xc000) == 0x0000) { //$0000-3fff - return cartridge.readROM(addr); +auto Cartridge::HuC1::read(uint16 address) -> uint8 { + if((address & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom.read(address.bits(0,13)); } - if((addr & 0xc000) == 0x4000) { //$4000-7fff - return cartridge.readROM(rom.select << 14 | (uint14)addr); + if((address & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13)); } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - return cartridge.readRAM(ram.select << 13 | (uint13)addr); + if((address & 0xe000) == 0xa000) { //$a000-bfff + return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12)); } return 0xff; } -auto Cartridge::HuC1::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { //$0000-1fff - ram.writable = data.bits(0,3) == 0x0a; +auto Cartridge::HuC1::write(uint16 address, uint8 data) -> void { + if((address & 0xe000) == 0x0000) { //$0000-1fff + io.ram.writable = data.bits(0,3) == 0x0a; return; } - if((addr & 0xe000) == 0x2000) { //$2000-3fff - rom.select = data + (data == 0); + if((address & 0xe000) == 0x2000) { //$2000-3fff + io.rom.bank = data; + if(!io.rom.bank) io.rom.bank = 0x01; return; } - if((addr & 0xe000) == 0x4000) { //$4000-5fff - ram.select = data; + if((address & 0xe000) == 0x4000) { //$4000-5fff + io.ram.bank = data; return; } - if((addr & 0xe000) == 0x6000) { //$6000-7fff - model = data.bit(0); + if((address & 0xe000) == 0x6000) { //$6000-7fff + io.model = data.bit(0); return; } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(!ram.writable) return; - return cartridge.writeRAM(ram.select << 13 | (uint13)addr, data); + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.writable) return; + return cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data); } } auto Cartridge::HuC1::power() -> void { - rom.select = 0x01; - ram.writable = false; - ram.select = 0x00; - model = 0; + io = {}; +} + +auto Cartridge::HuC1::serialize(serializer& s) -> void { + s.integer(io.model); + s.integer(io.rom.bank); + s.integer(io.ram.writable); + s.integer(io.ram.bank); } diff --git a/higan/gb/cartridge/huc1/huc1.hpp b/higan/gb/cartridge/huc1/huc1.hpp index 3ef4674d..5aa26677 100644 --- a/higan/gb/cartridge/huc1/huc1.hpp +++ b/higan/gb/cartridge/huc1/huc1.hpp @@ -1,14 +1,17 @@ -struct HuC1 : MMIO { - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; +struct HuC1 : Mapper { + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer&) -> void; - struct ROM { - uint8 select; - } rom; - struct RAM { - bool writable; - uint8 select; - } ram; - bool model; + struct IO { + uint1 model; + struct ROM { + uint8 bank = 0x01; + } rom; + struct RAM { + uint1 writable; + uint8 bank; + } ram; + } io; } huc1; diff --git a/higan/gb/cartridge/huc3/huc3.cpp b/higan/gb/cartridge/huc3/huc3.cpp index e07cc257..4ff79291 100644 --- a/higan/gb/cartridge/huc3/huc3.cpp +++ b/higan/gb/cartridge/huc3/huc3.cpp @@ -1,49 +1,48 @@ -auto Cartridge::HuC3::readIO(uint16 addr) -> uint8 { - if((addr & 0xc000) == 0x0000) { //$0000-3fff - return cartridge.readROM(addr); +auto Cartridge::HuC3::read(uint16 address) -> uint8 { + if((address & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom.read(address.bits(0,13)); } - if((addr & 0xc000) == 0x4000) { //$4000-7fff - return cartridge.readROM(rom.select << 14 | (uint14)addr); + if((address & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13)); } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) return cartridge.readRAM(ram.select << 13 | (uint13)addr); - return 0x01; //does not return open collection + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return 0x01; //does not return open collection + return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12)); } return 0xff; } -auto Cartridge::HuC3::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { //$0000-1fff - ram.enable = data.bits(0,3) == 0x0a; +auto Cartridge::HuC3::write(uint16 address, uint8 data) -> void { + if((address & 0xe000) == 0x0000) { //$0000-1fff + io.ram.enable = data.bits(0,3) == 0x0a; return; } - if((addr & 0xe000) == 0x2000) { //$2000-3fff - rom.select = data; + if((address & 0xe000) == 0x2000) { //$2000-3fff + io.rom.bank = data; return; } - if((addr & 0xe000) == 0x4000) { //$4000-5fff - ram.select = data; + if((address & 0xe000) == 0x4000) { //$4000-5fff + io.ram.bank = data; return; } - if((addr & 0xe000) == 0x6000) { //$6000-7fff - //unknown purpose - return; - } - - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) cartridge.writeRAM(ram.select << 13 | (uint13)addr, data); - return; + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return; + return cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data); } } auto Cartridge::HuC3::power() -> void { - rom.select = 0x01; - ram.enable = false; - ram.select = 0x00; + io = {}; +} + +auto Cartridge::HuC3::serialize(serializer& s) -> void { + s.integer(io.rom.bank); + s.integer(io.ram.enable); + s.integer(io.ram.bank); } diff --git a/higan/gb/cartridge/huc3/huc3.hpp b/higan/gb/cartridge/huc3/huc3.hpp index bc03b3a3..dc665f3a 100644 --- a/higan/gb/cartridge/huc3/huc3.hpp +++ b/higan/gb/cartridge/huc3/huc3.hpp @@ -1,13 +1,16 @@ -struct HuC3 : MMIO { - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; +struct HuC3 : Mapper { + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer&) -> void; - struct ROM { - uint8 select; - } rom; - struct RAM { - bool enable; - uint8 select; - } ram; + struct IO { + struct ROM { + uint8 bank = 0x01; + } rom; + struct RAM { + uint1 enable; + uint8 bank; + } ram; + } io; } huc3; diff --git a/higan/gb/cartridge/mbc0/mbc0.cpp b/higan/gb/cartridge/mbc0/mbc0.cpp index 5f6c49ec..14aa7586 100644 --- a/higan/gb/cartridge/mbc0/mbc0.cpp +++ b/higan/gb/cartridge/mbc0/mbc0.cpp @@ -1,21 +1,24 @@ -auto Cartridge::MBC0::readIO(uint16 addr) -> uint8 { - if((addr & 0x8000) == 0x0000) { //$0000-7fff - return cartridge.readROM(addr); +auto Cartridge::MBC0::read(uint16 address) -> uint8 { + if((address & 0x8000) == 0x0000) { //$0000-7fff + return cartridge.rom.read(address.bits(0,14)); } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - return cartridge.readRAM((uint13)addr); + if((address & 0xe000) == 0xa000) { //$a000-bfff + return cartridge.ram.read(address.bits(0,12)); } return 0xff; } -auto Cartridge::MBC0::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0xa000) { //$a000-bfff - cartridge.writeRAM((uint13)addr, data); +auto Cartridge::MBC0::write(uint16 address, uint8 data) -> void { + if((address & 0xe000) == 0xa000) { //$a000-bfff + cartridge.ram.write(address.bits(0,12), data); return; } } auto Cartridge::MBC0::power() -> void { } + +auto Cartridge::MBC0::serialize(serializer& s) -> void { +} diff --git a/higan/gb/cartridge/mbc0/mbc0.hpp b/higan/gb/cartridge/mbc0/mbc0.hpp index 0f9311e7..cbcccc6f 100644 --- a/higan/gb/cartridge/mbc0/mbc0.hpp +++ b/higan/gb/cartridge/mbc0/mbc0.hpp @@ -1,5 +1,6 @@ -struct MBC0 : MMIO { - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; +struct MBC0 : Mapper { + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer&) -> void; } mbc0; diff --git a/higan/gb/cartridge/mbc1/mbc1.cpp b/higan/gb/cartridge/mbc1/mbc1.cpp index 3eb57e49..44631479 100644 --- a/higan/gb/cartridge/mbc1/mbc1.cpp +++ b/higan/gb/cartridge/mbc1/mbc1.cpp @@ -1,66 +1,67 @@ -auto Cartridge::MBC1::readIO(uint16 addr) -> uint8 { - if((addr & 0xc000) == 0x0000) { //$0000-3fff - return cartridge.readROM(addr); +auto Cartridge::MBC1::read(uint16 address) -> uint8 { + if((address & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom.read(address.bits(0,13)); } - if((addr & 0xc000) == 0x4000) { //$4000-7fff - if(mode == 0) { - return cartridge.readROM(ram.select << 19 | rom.select << 14 | (uint14)addr); + if((address & 0xc000) == 0x4000) { //$4000-7fff + if(io.mode == 0) { + return cartridge.rom.read(io.ram.bank << 19 | io.rom.bank << 14 | address.bits(0,13)); } else { - return cartridge.readROM(rom.select << 14 | (uint14)addr); + return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13)); } } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) { - if(mode == 0) { - return cartridge.readRAM((uint13)addr); - } else { - return cartridge.readRAM(ram.select << 13 | (uint13)addr); - } + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return 0xff; + if(io.mode == 0) { + return cartridge.ram.read(address.bits(0,12)); + } else { + return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12)); } - return 0xff; } return 0xff; } -auto Cartridge::MBC1::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { //$0000-1fff - ram.enable = (data & 0x0f) == 0x0a; +auto Cartridge::MBC1::write(uint16 address, uint8 data) -> void { + if((address & 0xe000) == 0x0000) { //$0000-1fff + io.ram.enable = data.bits(0,3) == 0x0a; return; } - if((addr & 0xe000) == 0x2000) { //$2000-3fff - rom.select = (data & 0x1f) + ((data & 0x1f) == 0); + if((address & 0xe000) == 0x2000) { //$2000-3fff + io.rom.bank = data.bits(0,4); + if(!io.rom.bank) io.rom.bank = 0x01; return; } - if((addr & 0xe000) == 0x4000) { //$4000-5fff - ram.select = data & 0x03; + if((address & 0xe000) == 0x4000) { //$4000-5fff + io.ram.bank = data.bits(0,1); return; } - if((addr & 0xe000) == 0x6000) { //$6000-7fff - mode = data & 0x01; + if((address & 0xe000) == 0x6000) { //$6000-7fff + io.mode = data.bit(0); return; } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) { - if(mode == 0) { - cartridge.writeRAM(addr & 0x1fff, data); - } else { - cartridge.writeRAM(ram.select << 13 | (uint13)addr, data); - } + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return; + if(io.mode == 0) { + return cartridge.ram.write(address.bits(0,12), data); + } else { + return cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data); } - return; } } auto Cartridge::MBC1::power() -> void { - rom.select = 0x01; - ram.enable = false; - ram.select = 0x00; - mode = 0; + io = {}; +} + +auto Cartridge::MBC1::serialize(serializer& s) -> void { + s.integer(io.mode); + s.integer(io.rom.bank); + s.integer(io.ram.enable); + s.integer(io.ram.bank); } diff --git a/higan/gb/cartridge/mbc1/mbc1.hpp b/higan/gb/cartridge/mbc1/mbc1.hpp index 104bef44..85cd0ef5 100644 --- a/higan/gb/cartridge/mbc1/mbc1.hpp +++ b/higan/gb/cartridge/mbc1/mbc1.hpp @@ -1,14 +1,17 @@ -struct MBC1 : MMIO { - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; +struct MBC1 : Mapper { + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer& s) -> void; - struct ROM { - uint8 select; - } rom; - struct RAM { - bool enable; - uint8 select; - } ram; - bool mode; + struct IO { + uint1 mode; + struct ROM { + uint8 bank = 0x01; + } rom; + struct RAM { + uint1 enable; + uint8 bank; + } ram; + } io; } mbc1; diff --git a/higan/gb/cartridge/mbc1m/mbc1m.cpp b/higan/gb/cartridge/mbc1m/mbc1m.cpp index 647be028..9d447dce 100644 --- a/higan/gb/cartridge/mbc1m/mbc1m.cpp +++ b/higan/gb/cartridge/mbc1m/mbc1m.cpp @@ -1,40 +1,43 @@ -auto Cartridge::MBC1M::readIO(uint16 addr) -> uint8 { - if((addr & 0xc000) == 0x0000) { //$0000-3fff - if(mode == 0) return cartridge.readROM((uint14)addr); - return cartridge.readROM(rom.hi << 18 | (uint14)addr); +auto Cartridge::MBC1M::read(uint16 address) -> uint8 { + if((address & 0xc000) == 0x0000) { //$0000-3fff + if(io.mode == 0) return cartridge.rom.read(address.bits(0,13)); + return cartridge.rom.read(io.rom.bank.bits(4,5) << 18 | address.bits(0,13)); } - if((addr & 0xc000) == 0x4000) { //$4000-7fff - return cartridge.readROM(rom.hi << 18 | rom.lo << 14 | (uint14)addr); + if((address & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13)); } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - return cartridge.readRAM((uint13)addr); + if((address & 0xe000) == 0xa000) { //$a000-bfff + return cartridge.ram.read(address.bits(0,12)); } return 0xff; } -auto Cartridge::MBC1M::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x2000) { //$2000-3fff - rom.lo = data.bits(0,3); +auto Cartridge::MBC1M::write(uint16 address, uint8 data) -> void { + if((address & 0xe000) == 0x2000) { //$2000-3fff + io.rom.bank.bits(0,3) = data.bits(0,3); } - if((addr & 0xe000) == 0x4000) { //$4000-5fff - rom.hi = data.bits(0,1); + if((address & 0xe000) == 0x4000) { //$4000-5fff + io.rom.bank.bits(4,5) = data.bits(0,1); } - if((addr & 0xe000) == 0x6000) { //$6000-7fff - mode = data.bit(0); + if((address & 0xe000) == 0x6000) { //$6000-7fff + io.mode = data.bit(0); } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - cartridge.writeRAM((uint13)addr, data); + if((address & 0xe000) == 0xa000) { //$a000-bfff + cartridge.ram.write(address.bits(0,13), data); } } auto Cartridge::MBC1M::power() -> void { - rom.lo = 1; - rom.hi = 0; - mode = 0; + io = {}; +} + +auto Cartridge::MBC1M::serialize(serializer& s) -> void { + s.integer(io.mode); + s.integer(io.rom.bank); } diff --git a/higan/gb/cartridge/mbc1m/mbc1m.hpp b/higan/gb/cartridge/mbc1m/mbc1m.hpp index bf083215..5510a6d3 100644 --- a/higan/gb/cartridge/mbc1m/mbc1m.hpp +++ b/higan/gb/cartridge/mbc1m/mbc1m.hpp @@ -1,11 +1,13 @@ -struct MBC1M : MMIO { - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; +struct MBC1M : Mapper { + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer&) -> void; - struct ROM { - uint4 lo; - uint2 hi; - } rom; - uint1 mode; + struct IO { + uint1 mode; + struct ROM { + uint6 bank = 0x01; + } rom; + } io; } mbc1m; diff --git a/higan/gb/cartridge/mbc2/mbc2.cpp b/higan/gb/cartridge/mbc2/mbc2.cpp index 8e1c03bd..c2d536fa 100644 --- a/higan/gb/cartridge/mbc2/mbc2.cpp +++ b/higan/gb/cartridge/mbc2/mbc2.cpp @@ -1,38 +1,61 @@ -auto Cartridge::MBC2::readIO(uint16 addr) -> uint8 { - if((addr & 0xc000) == 0x0000) { //$0000-3fff - return cartridge.readROM(addr); +auto Cartridge::MBC2::read(uint16 address) -> uint8 { + if((address & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom.read(address.bits(0,13)); } - if((addr & 0xc000) == 0x4000) { //$4000-7fff - return cartridge.readROM(rom.select << 14 | (uint14)addr); + if((address & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13)); } - if((addr & 0xee00) == 0xa000) { //$a000-a1ff - if(ram.enable) return cartridge.readRAM((uint9)addr); - return 0xff; + if((address & 0xee01) == 0xa000) { //$a000-a1ff (even) + if(!io.ram.enable) return 0xff; + auto ram = cartridge.ram.read(address.bits(1,8)); + return 0xf0 | ram.bits(0,3); + } + + if((address & 0xee01) == 0xa001) { //$a000-a1ff (odd) + if(!io.ram.enable) return 0xff; + auto ram = cartridge.ram.read(address.bits(1,8)); + return 0xf0 | ram.bits(4,7); } return 0xff; } -auto Cartridge::MBC2::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { //$0000-1fff - if(!addr.bit(8)) ram.enable = data.bits(0,3) == 0x0a; +auto Cartridge::MBC2::write(uint16 address, uint8 data) -> void { + if((address & 0xe000) == 0x0000) { //$0000-1fff + if(!address.bit(8)) io.ram.enable = data.bits(0,3) == 0x0a; return; } - if((addr & 0xe000) == 0x2000) { //$2000-3fff - if( addr.bit(8)) rom.select = data.bits(0,3) + (data.bits(0,3) == 0); + if((address & 0xe000) == 0x2000) { //$2000-3fff + if(address.bit(8)) io.rom.bank = data.bits(0,3); + if(!io.rom.bank) io.rom.bank = 0x01; return; } - if((addr & 0xee00) == 0xa000) { //$a000-a1ff - if(ram.enable) cartridge.writeRAM((uint9)addr, data.bits(0,3)); + if((address & 0xee01) == 0xa000) { //$a000-a1ff (even) + if(!io.ram.enable) return; + auto ram = cartridge.ram.read(address.bits(1,8)); + ram.bits(0,3) = data.bits(0,3); + cartridge.ram.write(address.bits(1,8), ram); + return; + } + + if((address & 0xee01) == 0xa001) { //$a000-a1ff (odd) + if(!io.ram.enable) return; + auto ram = cartridge.ram.read(address.bits(1,8)); + ram.bits(4,7) = data.bits(0,3); + cartridge.ram.write(address.bits(1,8), ram); return; } } auto Cartridge::MBC2::power() -> void { - rom.select = 0x01; - ram.enable = false; + io = {}; +} + +auto Cartridge::MBC2::serialize(serializer& s) -> void { + s.integer(io.rom.bank); + s.integer(io.ram.enable); } diff --git a/higan/gb/cartridge/mbc2/mbc2.hpp b/higan/gb/cartridge/mbc2/mbc2.hpp index 7f8458c6..cdc62298 100644 --- a/higan/gb/cartridge/mbc2/mbc2.hpp +++ b/higan/gb/cartridge/mbc2/mbc2.hpp @@ -1,12 +1,15 @@ -struct MBC2 : MMIO { - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; +struct MBC2 : Mapper { + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer&) -> void; - struct ROM { - uint8 select; - } rom; - struct RAM { - bool enable; - } ram; + struct IO { + struct ROM { + uint8 bank = 0x01; + } rom; + struct RAM { + uint1 enable = 0; + } ram; + } io; } mbc2; diff --git a/higan/gb/cartridge/mbc3/mbc3.cpp b/higan/gb/cartridge/mbc3/mbc3.cpp index dd6d3577..3fad4b21 100644 --- a/higan/gb/cartridge/mbc3/mbc3.cpp +++ b/higan/gb/cartridge/mbc3/mbc3.cpp @@ -1,118 +1,113 @@ auto Cartridge::MBC3::second() -> void { - if(!rtc.halt) { - if(++rtc.second >= 60) { - rtc.second = 0; - if(++rtc.minute >= 60) { - rtc.minute = 0; - if(++rtc.hour >= 24) { - rtc.hour = 0; - if(++rtc.day >= 512) { - rtc.day = 0; - rtc.dayCarry = true; - } + if(io.rtc.halt) return; + if(++io.rtc.second >= 60) { + io.rtc.second = 0; + if(++io.rtc.minute >= 60) { + io.rtc.minute = 0; + if(++io.rtc.hour >= 24) { + io.rtc.hour = 0; + if(++io.rtc.day == 0) { + io.rtc.dayCarry = true; } } } } } -auto Cartridge::MBC3::readIO(uint16 addr) -> uint8 { - if((addr & 0xc000) == 0x0000) { //$0000-3fff - return cartridge.readROM(addr); +auto Cartridge::MBC3::read(uint16 address) -> uint8 { + if((address & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom.read(address.bits(0,13)); } - if((addr & 0xc000) == 0x4000) { //$4000-7fff - return cartridge.readROM(rom.select<< 14 | (uint14)addr); + if((address & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13)); } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) { - if(ram.select <= 0x03) { - return cartridge.readRAM(ram.select << 13 | (uint13)addr); - } - if(ram.select == 0x08) return rtc.latchSecond; - if(ram.select == 0x09) return rtc.latchMinute; - if(ram.select == 0x0a) return rtc.latchHour; - if(ram.select == 0x0b) return rtc.latchDay; - if(ram.select == 0x0c) return rtc.latchDayCarry << 7 | rtc.latchDay >> 8; - } + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return 0xff; + if(io.ram.bank <= 0x03) return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12)); + if(io.ram.bank == 0x08) return io.rtc.latchSecond; + if(io.ram.bank == 0x09) return io.rtc.latchMinute; + if(io.ram.bank == 0x0a) return io.rtc.latchHour; + if(io.ram.bank == 0x0b) return io.rtc.latchDay; + if(io.ram.bank == 0x0c) return io.rtc.latchDayCarry << 7 | io.rtc.latchDay >> 8; return 0xff; } return 0xff; } -auto Cartridge::MBC3::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { //$0000-1fff - ram.enable = (data & 0x0f) == 0x0a; +auto Cartridge::MBC3::write(uint16 address, uint8 data) -> void { + if((address & 0xe000) == 0x0000) { //$0000-1fff + io.ram.enable = data.bits(0,3) == 0x0a; return; } - if((addr & 0xe000) == 0x2000) { //$2000-3fff - rom.select = (data & 0x7f) + ((data & 0x7f) == 0); + if((address & 0xe000) == 0x2000) { //$2000-3fff + io.rom.bank = data.bits(0,6); + if(!io.rom.bank) io.rom.bank = 0x01; return; } - if((addr & 0xe000) == 0x4000) { //$4000-5fff - ram.select = data; + if((address & 0xe000) == 0x4000) { //$4000-5fff + io.ram.bank = data; return; } - if((addr & 0xe000) == 0x6000) { //$6000-7fff - if(rtc.latch == 0 && data == 1) { - rtc.latchSecond = rtc.second; - rtc.latchMinute = rtc.minute; - rtc.latchHour = rtc.hour; - rtc.latchDay = rtc.day; - rtc.latchDayCarry = rtc.dayCarry; + if((address & 0xe000) == 0x6000) { //$6000-7fff + if(io.rtc.latch == 0 && data == 1) { + io.rtc.latchSecond = io.rtc.second; + io.rtc.latchMinute = io.rtc.minute; + io.rtc.latchHour = io.rtc.hour; + io.rtc.latchDay = io.rtc.day; + io.rtc.latchDayCarry = io.rtc.dayCarry; } - rtc.latch = data; + io.rtc.latch = data; return; } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) { - if(ram.select <= 0x03) { - cartridge.writeRAM(ram.select << 13 | (uint13)addr, data); - } else if(ram.select == 0x08) { - if(data >= 60) data = 0; - rtc.second = data; - } else if(ram.select == 0x09) { - if(data >= 60) data = 0; - rtc.minute = data; - } else if(ram.select == 0x0a) { - if(data >= 24) data = 0; - rtc.hour = data; - } else if(ram.select == 0x0b) { - rtc.day = (rtc.day & 0x0100) | data; - } else if(ram.select == 0x0c) { - rtc.day = ((data & 1) << 8) | (rtc.day & 0xff); - rtc.halt = data & 0x40; - rtc.dayCarry = data & 0x80; - } + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return; + if(io.ram.bank <= 0x03) { + cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data); + } else if(io.ram.bank == 0x08) { + if(data >= 60) data = 0; + io.rtc.second = data; + } else if(io.ram.bank == 0x09) { + if(data >= 60) data = 0; + io.rtc.minute = data; + } else if(io.ram.bank == 0x0a) { + if(data >= 24) data = 0; + io.rtc.hour = data; + } else if(io.ram.bank == 0x0b) { + io.rtc.day.bits(0,7) = data.bits(0,7); + } else if(io.ram.bank == 0x0c) { + io.rtc.day.bit(8) = data.bit(0); + io.rtc.halt = data.bit(6); + io.rtc.dayCarry = data.bit(7); } return; } } auto Cartridge::MBC3::power() -> void { - rom.select = 0x01; - - ram.enable = false; - ram.select = 0x00; - - rtc.latch = 0; - - rtc.halt = true; - rtc.second = 0; - rtc.minute = 0; - rtc.hour = 0; - rtc.day = 0; - rtc.dayCarry = false; - - rtc.latchSecond = 0; - rtc.latchMinute = 0; - rtc.latchHour = 0; - rtc.latchDay = 0; - rtc.latchDayCarry = false; + io = {}; +} + +auto Cartridge::MBC3::serialize(serializer& s) -> void { + s.integer(io.rom.bank); + s.integer(io.ram.enable); + s.integer(io.ram.bank); + s.integer(io.rtc.halt); + s.integer(io.rtc.latch); + s.integer(io.rtc.second); + s.integer(io.rtc.minute); + s.integer(io.rtc.hour); + s.integer(io.rtc.day); + s.integer(io.rtc.dayCarry); + s.integer(io.rtc.latchSecond); + s.integer(io.rtc.latchMinute); + s.integer(io.rtc.latchHour); + s.integer(io.rtc.latchDay); + s.integer(io.rtc.latchDayCarry); } diff --git a/higan/gb/cartridge/mbc3/mbc3.hpp b/higan/gb/cartridge/mbc3/mbc3.hpp index 97cb0d13..5f9e63da 100644 --- a/higan/gb/cartridge/mbc3/mbc3.hpp +++ b/higan/gb/cartridge/mbc3/mbc3.hpp @@ -1,30 +1,33 @@ -struct MBC3 : MMIO { +struct MBC3 : Mapper { auto second() -> void; - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer& s) -> void; - struct ROM { - uint8 select; - } rom; - struct RAM { - bool enable; - uint8 select; - } ram; - struct RTC { - bool latch; + struct IO { + struct ROM { + uint8 bank = 0x01; + } rom; + struct RAM { + uint1 enable; + uint8 bank; + } ram; + struct RTC { + uint1 halt = true; + uint1 latch; - bool halt; - uint second; - uint minute; - uint hour; - uint day; - bool dayCarry; + uint8 second; + uint8 minute; + uint8 hour; + uint9 day; + uint1 dayCarry; - uint latchSecond; - uint latchMinute; - uint latchHour; - uint latchDay; - uint latchDayCarry; - } rtc; + uint8 latchSecond; + uint8 latchMinute; + uint8 latchHour; + uint9 latchDay; + uint1 latchDayCarry; + } rtc; + } io; } mbc3; diff --git a/higan/gb/cartridge/mbc5/mbc5.cpp b/higan/gb/cartridge/mbc5/mbc5.cpp index 07f2b826..b3b4b404 100644 --- a/higan/gb/cartridge/mbc5/mbc5.cpp +++ b/higan/gb/cartridge/mbc5/mbc5.cpp @@ -1,49 +1,53 @@ -auto Cartridge::MBC5::readIO(uint16 addr) -> uint8 { - if((addr & 0xc000) == 0x0000) { //$0000-3fff - return cartridge.readROM(addr); +auto Cartridge::MBC5::read(uint16 address) -> uint8 { + if((address & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom.read(address.bits(0,13)); } - if((addr & 0xc000) == 0x4000) { //$4000-7fff - return cartridge.readROM(rom.select << 14 | (uint14)addr); + if((address & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13)); } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) return cartridge.readRAM(ram.select << 13 | (uint13)addr); - return 0xff; + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return 0xff; + return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12)); } return 0xff; } -auto Cartridge::MBC5::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { //$0000-1fff - ram.enable = data.bits(0,3) == 0x0a; +auto Cartridge::MBC5::write(uint16 address, uint8 data) -> void { + if((address & 0xe000) == 0x0000) { //$0000-1fff + io.ram.enable = data.bits(0,3) == 0x0a; return; } - if((addr & 0xf000) == 0x2000) { //$2000-2fff - rom.select.byte(0) = data; + if((address & 0xf000) == 0x2000) { //$2000-2fff + io.rom.bank.bits(0,7) = data.bits(0,7); return; } - if((addr & 0xf000) == 0x3000) { //$3000-3fff - rom.select.byte(1) = data.bit(0); + if((address & 0xf000) == 0x3000) { //$3000-3fff + io.rom.bank.bit(8) = data.bit(0); return; } - if((addr & 0xe000) == 0x4000) { //$4000-5fff - ram.select = data.bits(0,3); + if((address & 0xe000) == 0x4000) { //$4000-5fff + io.ram.bank = data.bits(0,3); return; } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) cartridge.writeRAM(ram.select << 13 | (uint13)addr, data); - return; + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return; + return cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data); } } auto Cartridge::MBC5::power() -> void { - rom.select = 0x001; - ram.enable = false; - ram.select = 0x00; + io = {}; +} + +auto Cartridge::MBC5::serialize(serializer& s) -> void { + s.integer(io.rom.bank); + s.integer(io.ram.enable); + s.integer(io.ram.bank); } diff --git a/higan/gb/cartridge/mbc5/mbc5.hpp b/higan/gb/cartridge/mbc5/mbc5.hpp index 1d6bcf94..0d7b26c6 100644 --- a/higan/gb/cartridge/mbc5/mbc5.hpp +++ b/higan/gb/cartridge/mbc5/mbc5.hpp @@ -1,13 +1,16 @@ -struct MBC5 : MMIO { - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; +struct MBC5 : Mapper { + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer&) -> void; - struct ROM { - uint9 select; - } rom; - struct RAM { - bool enable; - uint4 select; - } ram; + struct IO { + struct ROM { + uint9 bank = 0x01; + } rom; + struct RAM { + uint1 enable; + uint4 bank; + } ram; + } io; } mbc5; diff --git a/higan/gb/cartridge/mmm01/mmm01.cpp b/higan/gb/cartridge/mmm01/mmm01.cpp index 8755aa84..7e8a9bde 100644 --- a/higan/gb/cartridge/mmm01/mmm01.cpp +++ b/higan/gb/cartridge/mmm01/mmm01.cpp @@ -1,60 +1,65 @@ -auto Cartridge::MMM01::readIO(uint16 addr) -> uint8 { - if((addr & 0x8000) == 0x0000) { //$0000-7fff - if(mode == 0) return cartridge.readROM(addr); - } +auto Cartridge::MMM01::read(uint16 address) -> uint8 { + if(io.mode == 0) { + if((address & 0x8000) == 0x0000) { //$0000-7fff + return cartridge.rom.read(cartridge.rom.size - 0x8000 + address.bits(0,14)); + } - if((addr & 0xc000) == 0x0000) { //$0000-3fff - return cartridge.readROM(0x8000 + (rom.base << 14) + (uint14)addr); - } + return 0xff; + } else { + if((address & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom.read((io.rom.base << 14) + address.bits(0,13)); + } - if((addr & 0xc000) == 0x4000) { //$4000-7fff - return cartridge.readROM(0x8000 + (rom.base << 14) + (rom.select<< 14) + (uint14)addr); - } + if((address & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom.read((io.rom.base << 14) + (io.rom.bank << 14) + address.bits(0,13)); + } + + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return 0xff; + return cartridge.ram.read(io.ram.bank << 13 | address.bits(0,12)); + } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) return cartridge.readRAM(ram.select << 13 | (uint13)addr); return 0xff; } - - return 0xff; } -auto Cartridge::MMM01::writeIO(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { //$0000-1fff - if(mode == 0) { - mode = 1; - } else { - ram.enable= data.bits(0,3) == 0x0a; +auto Cartridge::MMM01::write(uint16 address, uint8 data) -> void { + if(io.mode == 0) { + if((address & 0xe000) == 0x0000) { //$0000-1fff + io.mode = 1; } - } - if((addr & 0xe000) == 0x2000) { //$2000-3fff - if(mode == 0) { - rom.base = data.bits(0,5); - } else { - rom.select = data; + if((address & 0xe000) == 0x2000) { //$2000-3fff + io.rom.base = data.bits(0,5); } - } - - if((addr & 0xe000) == 0x4000) { //$4000-5fff - if(mode == 1) { - ram.select = data; + } else { + if((address & 0xe000) == 0x0000) { //$0000-1fff + io.ram.enable = data.bits(0,3) == 0x0a; } - } - if((addr & 0xe000) == 0x6000) { //$6000-7fff - //unknown purpose - } + if((address & 0xe000) == 0x2000) { //$2000-3fff + io.rom.bank = data; + } - if((addr & 0xe000) == 0xa000) { //$a000-bfff - if(ram.enable) cartridge.writeRAM(ram.select << 13 | (uint13)addr, data); + if((address & 0xe000) == 0x4000) { //$4000-5fff + io.ram.bank = data; + } + + if((address & 0xe000) == 0xa000) { //$a000-bfff + if(!io.ram.enable) return; + cartridge.ram.write(io.ram.bank << 13 | address.bits(0,12), data); + } } } auto Cartridge::MMM01::power() -> void { - rom.base = 0x00; - rom.select = 0x01; - ram.enable = false; - ram.select = 0x00; - mode = 0; + io = {}; +} + +auto Cartridge::MMM01::serialize(serializer& s) -> void { + s.integer(io.mode); + s.integer(io.rom.base); + s.integer(io.rom.bank); + s.integer(io.ram.enable); + s.integer(io.ram.bank); } diff --git a/higan/gb/cartridge/mmm01/mmm01.hpp b/higan/gb/cartridge/mmm01/mmm01.hpp index 958f9d06..04c650d3 100644 --- a/higan/gb/cartridge/mmm01/mmm01.hpp +++ b/higan/gb/cartridge/mmm01/mmm01.hpp @@ -1,15 +1,18 @@ -struct MMM01 : MMIO { - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; +struct MMM01 : Mapper { + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; auto power() -> void; + auto serialize(serializer& s) -> void; - struct ROM { - uint6 base; - uint8 select; - } rom; - struct RAM { - bool enable; - uint8 select; - } ram; - bool mode; + struct IO { + uint1 mode; + struct ROM { + uint6 base; + uint8 bank = 0x01; + } rom; + struct RAM { + uint1 enable; + uint8 bank; + } ram; + } io; } mmm01; diff --git a/higan/gb/cartridge/serialization.cpp b/higan/gb/cartridge/serialization.cpp index 7ea9dc8a..a03a4d9d 100644 --- a/higan/gb/cartridge/serialization.cpp +++ b/higan/gb/cartridge/serialization.cpp @@ -1,51 +1,8 @@ auto Cartridge::serialize(serializer& s) -> void { - if(information.battery) s.array(ram.data, ram.size); + if(ram.size) s.array(ram.data, ram.size); + if(rtc.size) s.array(rtc.data, rtc.size); + s.integer(bootromEnable); - s.integer(mbc1.rom.select); - s.integer(mbc1.ram.enable); - s.integer(mbc1.ram.select); - s.integer(mbc1.mode); - - s.integer(mbc1m.rom.lo); - s.integer(mbc1m.rom.hi); - s.integer(mbc1m.mode); - - s.integer(mbc2.rom.select); - s.integer(mbc2.ram.enable); - - s.integer(mbc3.rom.select); - s.integer(mbc3.ram.enable); - s.integer(mbc3.ram.select); - s.integer(mbc3.rtc.latch); - s.integer(mbc3.rtc.halt); - s.integer(mbc3.rtc.second); - s.integer(mbc3.rtc.minute); - s.integer(mbc3.rtc.hour); - s.integer(mbc3.rtc.day); - s.integer(mbc3.rtc.dayCarry); - s.integer(mbc3.rtc.latchSecond); - s.integer(mbc3.rtc.latchMinute); - s.integer(mbc3.rtc.latchHour); - s.integer(mbc3.rtc.latchDay); - s.integer(mbc3.rtc.latchDayCarry); - - s.integer(mbc5.rom.select); - s.integer(mbc5.ram.enable); - s.integer(mbc5.ram.select); - - s.integer(mmm01.rom.base); - s.integer(mmm01.rom.select); - s.integer(mmm01.ram.enable); - s.integer(mmm01.ram.select); - s.integer(mmm01.mode); - - s.integer(huc1.rom.select); - s.integer(huc1.ram.writable); - s.integer(huc1.ram.select); - s.integer(huc1.model); - - s.integer(huc3.rom.select); - s.integer(huc3.ram.enable); - s.integer(huc3.ram.select); + mapper->serialize(s); } diff --git a/higan/gb/cartridge/tama/tama.cpp b/higan/gb/cartridge/tama/tama.cpp new file mode 100644 index 00000000..199bfac6 --- /dev/null +++ b/higan/gb/cartridge/tama/tama.cpp @@ -0,0 +1,126 @@ +//U1: TAMA7: Mask ROM (512KB) +//U2: TAMA5: Game Boy cartridge connector interface +//U3: TAMA6: Toshiba TMP47C243M (4-bit MCU) +//U4: RTC: Toshiba TC8521AM + +//note: the TMP47C243M's 2048 x 8-bit program ROM is currently undumped +//as such, high level emulation is used as a necessary evil + +auto Cartridge::TAMA::second() -> void { +} + +auto Cartridge::TAMA::read(uint16 address) -> uint8 { + if((address & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom.read(address.bits(0,13)); + } + + if((address & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom.read(io.rom.bank << 14 | address.bits(0,13)); + } + + if((address & 0xe001) == 0xa000) { //$a000-bfff (even) + if(io.select == 0x0a) { + return 0xf0 | io.ready; + } + + if(io.select == 0x0c) { + return 0xf0 | io.output.bits(0,3); + } + + if(io.select == 0x0d) { + return 0xf0 | io.output.bits(4,7); + } + + return 0xff; + } + + if((address & 0xe001) == 0xa001) { //$a000-bfff (odd) + return 0xff; + } + + return 0xff; +} + +auto Cartridge::TAMA::write(uint16 address, uint8 data) -> void { + if((address & 0xe001) == 0xa000) { //$a000-bfff (even) + if(io.select == 0x00) { + io.rom.bank.bits(0,3) = data.bits(0,3); + } + + if(io.select == 0x01) { + io.rom.bank.bit(4) = data.bit(0); + } + + if(io.select == 0x04) { + io.input.bits(0,3) = data.bits(0,3); + } + + if(io.select == 0x05) { + io.input.bits(4,7) = data.bits(0,3); + } + + if(io.select == 0x06) { + io.index.bit(4) = data.bit(0); + io.mode = data.bits(1,3); + } + + if(io.select == 0x07) { + io.index.bits(0,3) = data.bits(0,3); + + if(io.mode == 0) { + cartridge.ram.write(io.index, io.input); + } + + if(io.mode == 1) { + io.output = cartridge.ram.read(io.index); + } + } + + return; + } + + if((address & 0xe001) == 0xa001) { //$a000-bfff (odd) + io.select = data.bits(0,3); + + if(io.select == 0x0a) { + io.ready = true; + } + + return; + } +} + +auto Cartridge::TAMA::readRTC(uint1 page, uint4 address) -> uint4 { + if(address >= 13) return 0xf; + auto ram = cartridge.rtc.read(page * 13 + address.bits(1,3)); + if(!address.bit(0)) { + return ram.bits(0,3); + } else { + return ram.bits(4,7); + } +} + +auto Cartridge::TAMA::writeRTC(uint1 page, uint4 address, uint4 data) -> void { + if(address >= 13) return; + auto ram = cartridge.rtc.read(page * 13 + address.bits(1,3)); + if(!address.bit(0)) { + ram.bits(0,3) = data; + } else { + ram.bits(4,7) = data; + } + cartridge.rtc.write(page * 13 + address.bits(1,3), ram); +} + +auto Cartridge::TAMA::power() -> void { + io = {}; +} + +auto Cartridge::TAMA::serialize(serializer& s) -> void { + s.integer(io.ready); + s.integer(io.select); + s.integer(io.mode); + s.integer(io.index); + s.integer(io.input); + s.integer(io.output); + s.integer(io.rom.bank); +} diff --git a/higan/gb/cartridge/tama/tama.hpp b/higan/gb/cartridge/tama/tama.hpp new file mode 100644 index 00000000..28643063 --- /dev/null +++ b/higan/gb/cartridge/tama/tama.hpp @@ -0,0 +1,21 @@ +struct TAMA : Mapper { + auto second() -> void; + auto read(uint16 address) -> uint8; + auto write(uint16 address, uint8 data) -> void; + auto readRTC(uint1 page, uint4 address) -> uint4; + auto writeRTC(uint1 page, uint4 address, uint4 data) -> void; + auto power() -> void; + auto serialize(serializer&) -> void; + + struct IO { + uint1 ready; + uint4 select; + uint3 mode; + uint5 index; + uint8 input; + uint8 output; + struct ROM { + uint5 bank; + } rom; + } io; +} tama; diff --git a/higan/gb/cpu/timing.cpp b/higan/gb/cpu/timing.cpp index afe8e29d..71e619f9 100644 --- a/higan/gb/cpu/timing.cpp +++ b/higan/gb/cpu/timing.cpp @@ -5,7 +5,7 @@ auto CPU::step(uint clocks) -> void { for(auto n : range(clocks)) { if(++status.clock == 0) { - cartridge.mbc3.second(); + cartridge.second(); } //4MHz / N(hz) - 1 = mask diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp index bcb26dab..b0ceae80 100644 --- a/higan/md/vdp/io.cpp +++ b/higan/md/vdp/io.cpp @@ -63,7 +63,7 @@ auto VDP::readDataPort() -> uint16 { auto address = io.address.bits(1,6); auto data = cram.read(address); io.address += io.dataIncrement; - return data.bits(0,2) << 1 | data.bits(3,5) << 2 | data.bits(6,8) << 3; + return data.bits(0,2) << 1 | data.bits(3,5) << 5 | data.bits(6,8) << 9; } return 0x0000; diff --git a/higan/target-tomoko/presentation/presentation.cpp b/higan/target-tomoko/presentation/presentation.cpp index d71d942e..2451f089 100644 --- a/higan/target-tomoko/presentation/presentation.cpp +++ b/higan/target-tomoko/presentation/presentation.cpp @@ -313,13 +313,15 @@ auto Presentation::resizeViewport(bool resizeWindow) -> void { auto Presentation::toggleFullScreen() -> void { if(!fullScreen()) { - menuBar.setVisible(false); statusBar.setVisible(false); + menuBar.setVisible(false); setFullScreen(true); video->setExclusive(settings["Video/Fullscreen/Exclusive"].boolean()); + if(video->exclusive()) setVisible(false); if(!input->acquired()) input->acquire(); } else { if(input->acquired()) input->release(); + if(video->exclusive()) setVisible(true); video->setExclusive(false); setFullScreen(false); menuBar.setVisible(true); diff --git a/higan/target-tomoko/program/program.cpp b/higan/target-tomoko/program/program.cpp index 1deb7dce..a729c2c9 100644 --- a/higan/target-tomoko/program/program.cpp +++ b/higan/target-tomoko/program/program.cpp @@ -99,5 +99,8 @@ auto Program::quit() -> void { unloadMedium(); settings.quit(); inputManager->quit(); + video.reset(); + audio.reset(); + input.reset(); Application::quit(); } diff --git a/icarus/heuristics/game-boy.cpp b/icarus/heuristics/game-boy.cpp index 002a6bf2..f2047041 100644 --- a/icarus/heuristics/game-boy.cpp +++ b/icarus/heuristics/game-boy.cpp @@ -1,106 +1,224 @@ struct GameBoyCartridge { - GameBoyCartridge(uint8_t* data, unsigned size); + GameBoyCartridge(uint8_t* data, uint size); string markup; -//private: - struct Information { - string mapper; - bool ram; - bool battery; - bool rtc; - bool rumble; + bool black = false; //cartridge works in DMG+CGB mode + bool clear = false; //cartridge works in CGB mode only - unsigned romsize; - unsigned ramsize; + string mapper = "MBC0"; + bool battery = false; + bool ram = false; + bool rtc = false; + bool rumble = false; + bool accelerometer = false; - bool cgb; - bool cgbonly; - } info; + uint romSize = 0; + uint ramSize = 0; + uint rtcSize = 0; }; -GameBoyCartridge::GameBoyCartridge(uint8_t* romdata, unsigned romsize) { - if(romsize < 0x4000) return; +GameBoyCartridge::GameBoyCartridge(uint8_t* data, uint size) { + if(size < 0x4000) return; - info.mapper = "unknown"; - info.ram = false; - info.battery = false; - info.rtc = false; - info.rumble = false; - - info.romsize = 0; - info.ramsize = 0; - - unsigned base = romsize - 0x8000; - if(romdata[base + 0x0104] == 0xce && romdata[base + 0x0105] == 0xed - && romdata[base + 0x0106] == 0x66 && romdata[base + 0x0107] == 0x66 - && romdata[base + 0x0108] == 0xcc && romdata[base + 0x0109] == 0x0d - && romdata[base + 0x0147] >= 0x0b && romdata[base + 0x0147] <= 0x0d + uint index = size < 0x8000 ? size : size - 0x8000; + if(data[index + 0x0104] == 0xce && data[index + 0x0105] == 0xed + && data[index + 0x0106] == 0x66 && data[index + 0x0107] == 0x66 + && data[index + 0x0108] == 0xcc && data[index + 0x0109] == 0x0d + && data[index + 0x0147] >= 0x0b && data[index + 0x0147] <= 0x0d ) { - //MMM01 stores header at bottom of image - //flip this around for consistency with all other mappers - uint8_t header[0x8000]; - memcpy(header, romdata + base, 0x8000); - memmove(romdata + 0x8000, romdata, romsize - 0x8000); - memcpy(romdata, header, 0x8000); + //MMM01 stores header at bottom of data[] + } else { + //all other mappers store header at top of data[] + index = 0; } - info.cgb = (romdata[0x0143] & 0x80) == 0x80; - info.cgbonly = (romdata[0x0143] & 0xc0) == 0xc0; + black = (data[index + 0x0143] & 0xc0) == 0x80; + clear = (data[index + 0x0143] & 0xc0) == 0xc0; + + switch(data[index + 0x0147]) { + + case 0x00: + mapper = "MBC0"; + break; + + case 0x01: + mapper = "MBC1"; + break; + + case 0x02: + mapper = "MBC1"; + ram = true; + break; + + case 0x03: + mapper = "MBC1"; + battery = true; + ram = true; + break; + + case 0x05: + mapper = "MBC2"; + ram = true; + break; + + case 0x06: + mapper = "MBC2"; + battery = true; + ram = true; + break; + + case 0x08: + mapper = "MBC0"; + ram = true; + break; + + case 0x09: + mapper = "MBC0"; + battery = true; + ram = true; + break; + + case 0x0b: + mapper = "MMM01"; + break; + + case 0x0c: + mapper = "MMM01"; + ram = true; + break; + + case 0x0d: + mapper = "MMM01"; + battery = true; + ram = true; + break; + + case 0x0f: + mapper = "MBC3"; + battery = true; + rtc = true; + break; + + case 0x10: + mapper = "MBC3"; + battery = true; + ram = true; + rtc = true; + break; + + case 0x11: + mapper = "MBC3"; + break; + + case 0x12: + mapper = "MBC3"; + ram = true; + break; + + case 0x13: + mapper = "MBC3"; + battery = true; + ram = true; + break; + + case 0x19: + mapper = "MBC5"; + break; + + case 0x1a: + mapper = "MBC5"; + ram = true; + break; + + case 0x1b: + mapper = "MBC5"; + battery = true; + ram = true; + break; + + case 0x1c: + mapper = "MBC5"; + rumble = true; + break; + + case 0x1d: + mapper = "MBC5"; + ram = true; + rumble = true; + break; + + case 0x1e: + mapper = "MBC5"; + battery = true; + ram = true; + rumble = true; + break; + + case 0x20: + mapper = "MBC6"; + break; + + case 0x22: + mapper = "MBC7"; + battery = true; + ram = true; + rumble = true; + accelerometer = true; + break; + + case 0xfc: + mapper = "CAMERA"; + break; + + case 0xfd: + mapper = "TAMA"; + battery = true; + ram = true; + rtc = true; + break; + + case 0xfe: + mapper = "HuC3"; + break; + + case 0xff: + mapper = "HuC1"; + battery = true; + ram = true; + break; - switch(romdata[0x0147]) { - case 0x00: info.mapper = "none"; break; - case 0x01: info.mapper = "MBC1"; break; - case 0x02: info.mapper = "MBC1"; info.ram = true; break; - case 0x03: info.mapper = "MBC1"; info.ram = true; info.battery = true; break; - case 0x05: info.mapper = "MBC2"; info.ram = true; break; - case 0x06: info.mapper = "MBC2"; info.ram = true; info.battery = true; break; - case 0x08: info.mapper = "none"; info.ram = true; break; - case 0x09: info.mapper = "MBC0"; info.ram = true; info.battery = true; break; - case 0x0b: info.mapper = "MMM01"; break; - case 0x0c: info.mapper = "MMM01"; info.ram = true; break; - case 0x0d: info.mapper = "MMM01"; info.ram = true; info.battery = true; break; - case 0x0f: info.mapper = "MBC3"; info.rtc = true; info.battery = true; break; - case 0x10: info.mapper = "MBC3"; info.rtc = true; info.ram = true; info.battery = true; break; - case 0x11: info.mapper = "MBC3"; break; - case 0x12: info.mapper = "MBC3"; info.ram = true; break; - case 0x13: info.mapper = "MBC3"; info.ram = true; info.battery = true; break; - case 0x19: info.mapper = "MBC5"; break; - case 0x1a: info.mapper = "MBC5"; info.ram = true; break; - case 0x1b: info.mapper = "MBC5"; info.ram = true; info.battery = true; break; - case 0x1c: info.mapper = "MBC5"; info.rumble = true; break; - case 0x1d: info.mapper = "MBC5"; info.rumble = true; info.ram = true; break; - case 0x1e: info.mapper = "MBC5"; info.rumble = true; info.ram = true; info.battery = true; break; - case 0xfc: break; //Pocket Camera - case 0xfd: break; //Bandai TAMA5 - case 0xfe: info.mapper = "HuC3"; break; - case 0xff: info.mapper = "HuC1"; info.ram = true; info.battery = true; break; } - switch(romdata[0x0148]) { default: - case 0x00: info.romsize = 2 * 16 * 1024; break; - case 0x01: info.romsize = 4 * 16 * 1024; break; - case 0x02: info.romsize = 8 * 16 * 1024; break; - case 0x03: info.romsize = 16 * 16 * 1024; break; - case 0x04: info.romsize = 32 * 16 * 1024; break; - case 0x05: info.romsize = 64 * 16 * 1024; break; - case 0x06: info.romsize = 128 * 16 * 1024; break; - case 0x07: info.romsize = 256 * 16 * 1024; break; - case 0x52: info.romsize = 72 * 16 * 1024; break; - case 0x53: info.romsize = 80 * 16 * 1024; break; - case 0x54: info.romsize = 96 * 16 * 1024; break; + switch(data[index + 0x0148]) { default: + case 0x00: romSize = 2 * 16 * 1024; break; + case 0x01: romSize = 4 * 16 * 1024; break; + case 0x02: romSize = 8 * 16 * 1024; break; + case 0x03: romSize = 16 * 16 * 1024; break; + case 0x04: romSize = 32 * 16 * 1024; break; + case 0x05: romSize = 64 * 16 * 1024; break; + case 0x06: romSize = 128 * 16 * 1024; break; + case 0x07: romSize = 256 * 16 * 1024; break; + case 0x52: romSize = 72 * 16 * 1024; break; + case 0x53: romSize = 80 * 16 * 1024; break; + case 0x54: romSize = 96 * 16 * 1024; break; } - switch(romdata[0x0149]) { default: - case 0x00: info.ramsize = 0 * 1024; break; - case 0x01: info.ramsize = 2 * 1024; break; - case 0x02: info.ramsize = 8 * 1024; break; - case 0x03: info.ramsize = 32 * 1024; break; + switch(data[index + 0x0149]) { default: + case 0x00: ramSize = 0 * 1024; break; + case 0x01: ramSize = 2 * 1024; break; + case 0x02: ramSize = 8 * 1024; break; + case 0x03: ramSize = 32 * 1024; break; } - if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit + if(mapper == "MBC2" && ram) ramSize = 256; + if(mapper == "TAMA" && ram) ramSize = 32; - markup.append("board mapper=", info.mapper, "\n"); - markup.append(" rom name=program.rom size=0x", hex(romsize), "\n"); - if(info.ramsize > 0) markup.append(" ram name=save.ram size=0x", hex(info.ramsize), "\n"); + if(mapper == "MBC3" && rtc) rtcSize = 13; + if(mapper == "TAMA" && rtc) rtcSize = 21; + + markup.append("board mapper=", mapper, "\n"); + markup.append(" rom name=program.rom size=0x", hex(romSize), "\n"); + if(ram && ramSize) markup.append(" ram ", battery ? "name=save.ram " : "", "size=0x", hex(ramSize), "\n"); + if(rtc && rtcSize) markup.append(" rtc ", battery ? "name=rtc.ram " : "", "size=0x", hex(rtcSize), "\n"); } diff --git a/libco/fiber.c b/libco/fiber.c index 38a293df..50af4a72 100644 --- a/libco/fiber.c +++ b/libco/fiber.c @@ -1,5 +1,6 @@ #define LIBCO_C #include "libco.h" +#include "settings.h" #define WINVER 0x0400 #define _WIN32_WINNT 0x0400 diff --git a/libco/sjlj.c b/libco/sjlj.c index 4d5017f5..1d0cb59a 100644 --- a/libco/sjlj.c +++ b/libco/sjlj.c @@ -7,6 +7,7 @@ #include "libco.h" #include "settings.h" +#define _BSD_SOURCE #define _XOPEN_SOURCE 500 #include #include diff --git a/libco/ucontext.c b/libco/ucontext.c index f4527bfb..9ba47c88 100644 --- a/libco/ucontext.c +++ b/libco/ucontext.c @@ -12,8 +12,10 @@ #define LIBCO_C #include "libco.h" +#include "settings.h" #define _BSD_SOURCE +#define _XOPEN_SOURCE 500 #include #include