From 9fd17a71275b5edbe9503ec6f9611a5e35264895 Mon Sep 17 00:00:00 2001 From: Marc Trudel Date: Wed, 25 Nov 2020 10:50:27 +0900 Subject: [PATCH] features: submapper support, g101 - Adding support for NES2.0 headers - IREM-G101 chip/board --- .vscode/settings.json | 3 +- higan/fc/cartridge/board/board.cpp | 3 + higan/fc/cartridge/board/irem-g101.cpp | 55 ++++++++++++++++++ higan/fc/cartridge/chip/chip.cpp | 1 + higan/fc/cartridge/chip/g101.cpp | 79 ++++++++++++++++++++++++++ icarus/cartridge/famicom.cpp | 26 ++++++++- 6 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 higan/fc/cartridge/board/irem-g101.cpp create mode 100644 higan/fc/cartridge/chip/g101.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 26ae8f4..f83fd99 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -78,6 +78,7 @@ "filesystem": "cpp", "memory_resource": "cpp", "cinttypes": "cpp", - "__memory": "cpp" + "__memory": "cpp", + "random": "cpp" } } \ No newline at end of file diff --git a/higan/fc/cartridge/board/board.cpp b/higan/fc/cartridge/board/board.cpp index 618e525..e57f021 100755 --- a/higan/fc/cartridge/board/board.cpp +++ b/higan/fc/cartridge/board/board.cpp @@ -1,6 +1,7 @@ #include "bandai-fcg.cpp" #include "discrete-74x139x74.cpp" #include "hvc-fmr.cpp" +#include "irem-g101.cpp" #include "jaleco-jf.cpp" #include "jaleco-jf16.cpp" #include "konami-vrc1.cpp" @@ -152,6 +153,8 @@ auto Board::load(string manifest) -> Board* { if(type == "BANDAI-FCG" ) return new BandaiFCG(document); if(type == "DISCRETE-74x139x74") return new DISCRETE74x139x74(document); + if(type == "IREM-G101" ) return new IremG101(document); + if(type == "HVC-FMR" ) return new HVC_FMR(document); if(type == "JALECO-JF" ) return new JalecoJF(document); diff --git a/higan/fc/cartridge/board/irem-g101.cpp b/higan/fc/cartridge/board/irem-g101.cpp new file mode 100644 index 0000000..60fe4a2 --- /dev/null +++ b/higan/fc/cartridge/board/irem-g101.cpp @@ -0,0 +1,55 @@ +struct IremG101 : Board { + IremG101(Markup::Node& document) : Board(document), g101(*this, document) { + if(!document["game/board/mirror"]) { + settings.mirror = 0; + } else { + string mirror = document["game/board/mirror/mode"].text(); + if(mirror == "screen-0") settings.mirror = 1; + if(mirror == "screen-1") settings.mirror = 2; + } + } + + auto readPRG(uint addr) -> uint8 { + if((addr & 0x8000) == 0x8000) return prgrom.read(g101.prgAddress(addr)); + if((addr & 0xe000) == 0x6000) return prgram.read(addr & 0x1fff); + return cpu.mdr(); + } + + auto writePRG(uint addr, uint8 data) -> void { + if((addr & 0x8000) == 0x8000) return g101.regWrite(addr, data); + if((addr & 0xe000) == 0x6000) return prgram.write(addr & 0x1fff, data); + } + + auto readCHR(uint addr) -> uint8 { + if(addr & 0x2000) switch(settings.mirror) { + case 0: return ppu.readCIRAM(g101.ciramAddress(addr)); + case 1: return ppu.readCIRAM((addr & 0x03ff) | 0x0000); + case 2: return ppu.readCIRAM((addr & 0x03ff) | 0x0400); + } + return Board::readCHR(g101.chrAddress(addr)); + } + + auto writeCHR(uint addr, uint8 data) -> void { + if(addr & 0x2000) switch(settings.mirror) { + case 0: return ppu.writeCIRAM(g101.ciramAddress(addr), data); + case 1: return ppu.writeCIRAM((addr & 0x03ff) | 0x0000, data); + case 2: return ppu.writeCIRAM((addr & 0x03ff) | 0x0400, data); + } + return Board::writeCHR(g101.chrAddress(addr), data); + } + + auto power(bool reset) -> void { + g101.power(reset); + } + + auto serialize(serializer& s) -> void { + Board::serialize(s); + g101.serialize(s); + } + + struct Settings { + uint2 mirror; //0 = G101-controlled, 1 = screen 0, 2 = screen 1 + } settings; + + G101 g101; +}; diff --git a/higan/fc/cartridge/chip/chip.cpp b/higan/fc/cartridge/chip/chip.cpp index 5fe9ca9..403b110 100755 --- a/higan/fc/cartridge/chip/chip.cpp +++ b/higan/fc/cartridge/chip/chip.cpp @@ -1,3 +1,4 @@ +#include "g101.cpp" #include "n108.cpp" #include "n163.cpp" #include "mmc1.cpp" diff --git a/higan/fc/cartridge/chip/g101.cpp b/higan/fc/cartridge/chip/g101.cpp new file mode 100644 index 0000000..5dbf63b --- /dev/null +++ b/higan/fc/cartridge/chip/g101.cpp @@ -0,0 +1,79 @@ +struct G101 : Chip { + G101(Board& board, Markup::Node& boardNode) : Chip(board) { + } + + auto prgAddress(uint addr) const -> uint { + switch(addr & 0xe000) { + case 0x8000: + if(prgMode == 1) return (0x1e << 13) | (addr & 0x1fff); + return (prgBank[0] << 13) | (addr & 0x1fff); + case 0xa000: + return (prgBank[1] << 13) | (addr & 0x1fff); + case 0xc000: + if(prgMode == 0) return (0x1e << 13) | (addr & 0x1fff); + return (prgBank[0] << 13) | (addr & 0x1fff); + case 0xe000: + return (0x1f << 13) | (addr & 0x1fff); + } + unreachable; + } + + auto chrAddress(uint addr) const -> uint { + return (chrBank[addr >> 10] << 10) | (addr & 0x03ff); + } + + auto ciramAddress(uint addr) const -> uint { + switch(mirror) { + case 0: return (addr & 0x03ff) | ((addr & 0x0400) >> 0); + case 1: return (addr & 0x03ff) | ((addr & 0x0800) >> 1); + } + unreachable; + } + + auto regWrite(uint addr, uint8 data) -> void { + switch(addr & 0xf000) { + case 0x8000: + prgBank[0] = data & 0x1f; + break; + case 0x9000: + mirror = data & 0x01; + prgMode = data & 0x02; + break; + case 0xa000: + prgBank[1] = data & 0x1f; + break; + case 0xb000: + chrBank[addr & 0x0007] = data; + break; + } + } + + auto power(bool reset) -> void { + if(!reset) { + prgMode = 0; + prgBank[0] = 0x00; + prgBank[1] = 0x1e; + chrBank[0] = 0; + chrBank[1] = 0; + chrBank[2] = 0; + chrBank[3] = 0; + chrBank[4] = 0; + chrBank[5] = 0; + chrBank[6] = 0; + chrBank[7] = 0; + mirror = 0; + } + } + + auto serialize(serializer& s) -> void { + s.integer(prgMode); + s.array(prgBank); + s.array(chrBank); + s.integer(mirror); + } + + bool prgMode; + uint5 prgBank[2]; + uint8 chrBank[8]; + bool mirror; +}; \ No newline at end of file diff --git a/icarus/cartridge/famicom.cpp b/icarus/cartridge/famicom.cpp index 94dd64d..5180d3b 100644 --- a/icarus/cartridge/famicom.cpp +++ b/icarus/cartridge/famicom.cpp @@ -73,6 +73,20 @@ auto Famicom::heuristicsINES(vector& data, string location) -> string { uint chrram = chrrom == 0u ? 8192u : 0u; uint eeprom = 0u; + bool nes2 = (data[7] & 0x0c) == 0x08; + uint submapper = 0u; + + if (nes2) { + submapper = data[8] >> 4; + prgrom += (data[9] & 0x0f) * 0x400000; + chrrom += (data[9] >> 4) * 0x200000; + prgram = ((data[10] & 0x0f) == 0 ? 0 : 64) << (data[10] & 0x0f); //no battery + prgram += ((data[10] >> 4) == 0 ? 0 : 64) << (data[10] >> 4); //battery + chrram = ((data[11] & 0x0f) == 0 ? 0 : 64) << (data[11] & 0x0f); //no battery + chrram += ((data[11] >> 4) == 0 ? 0 : 64) << (data[11] >> 4); //battery + + } + string s; s += "game\n"; s +={" name: ", Media::name(location), "\n"}; @@ -178,6 +192,13 @@ auto Famicom::heuristicsINES(vector& data, string location) -> string { s += " chip type=VRC6\n"; prgram = 8192; break; + + case 32: + s += " board: IREM-G101\n"; + s += " chip type=G-101\n"; + if(submapper == 1) s +={" mirror mode=screen-1\n"}; + break; + case 34: s += " board: NES-BNROM\n"; @@ -220,10 +241,8 @@ auto Famicom::heuristicsINES(vector& data, string location) -> string { break; case 78: - // Todo: adde NES 2.0 support to correctly detect the submapper; this will be needed - // for Holy Diver to work correctly s += " board: JALECO-JF16\n"; - s += " submapper id=1\n"; + s += {" submapper id=", submapper, "\n"}; break; case 85: @@ -321,6 +340,7 @@ auto Famicom::heuristicsINES(vector& data, string location) -> string { s += " content: Save\n"; } + printf("%s\n", s.data()); return s; }