diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 7653d89c..a6178fb8 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -447,6 +447,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index be92c7d9..85254acd 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -1126,6 +1126,9 @@
Nes\Mappers\Unif
+
+ Nes\Mappers\Unif
+
diff --git a/Core/MMC3_Fk23C.h b/Core/MMC3_Fk23C.h
new file mode 100644
index 00000000..170aa5a3
--- /dev/null
+++ b/Core/MMC3_Fk23C.h
@@ -0,0 +1,141 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_Fk23C : public MMC3
+{
+private:
+ bool _isFk23Ca;
+ uint8_t _exRegs[8];
+ uint8_t _chrReg;
+
+protected:
+ uint32_t GetChrRamSize() override { return _isFk23Ca ? 0x2000 : 0; }
+ uint16_t GetChrRamPageSize() override { return 0x400; }
+
+ void InitMapper() override
+ {
+ _exRegs[0] = _exRegs[1] = _exRegs[2] = _exRegs[3] = 0;
+ _exRegs[4] = _exRegs[5] = _exRegs[6] = _exRegs[7] = 0xFF;
+ _chrReg = 0;
+
+ AddRegisterRange(0x5000, 0x5FFF, MemoryOperation::Write);
+
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softReset) override
+ {
+ _exRegs[0] = _exRegs[1] = _exRegs[2] = _exRegs[3] = 0;
+ _exRegs[4] = _exRegs[5] = _exRegs[6] = _exRegs[7] = 0xFF;
+ _chrReg = 0;
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ ArrayInfo exRegs{ _exRegs,8 };
+ Stream(_chrReg, exRegs);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ if(_exRegs[0] & 0x20) {
+ MMC3::SelectCHRPage(slot, page, _isFk23Ca ? ChrMemoryType::ChrRam : ChrMemoryType::Default);
+ } else {
+ uint16_t base = (_exRegs[2] & 0x7F) << 3;
+ MMC3::SelectCHRPage(slot, page | base, memoryType);
+ }
+ }
+
+ void UpdateChrMapping() override
+ {
+ if(_exRegs[0] & 0x40) {
+ SelectChrPage8x(0, (_exRegs[2] | _chrReg) << 3);
+ } else if(_exRegs[3] & 0x02) {
+ uint16_t base = (_exRegs[2] & 0x7F) << 3;
+ int slotBase = _chrMode ? 4 : 0;
+ MMC3::SelectCHRPage(0 ^ slotBase, _registers[0] | base);
+ MMC3::SelectCHRPage(1 ^ slotBase, _exRegs[6] | base);
+ MMC3::SelectCHRPage(2 ^ slotBase, _registers[1] | base);
+ MMC3::SelectCHRPage(3 ^ slotBase, _exRegs[7] | base);
+ MMC3::SelectCHRPage(4 ^ slotBase, _registers[2] | base);
+ MMC3::SelectCHRPage(5 ^ slotBase, _registers[3] | base);
+ MMC3::SelectCHRPage(6 ^ slotBase, _registers[4] | base);
+ MMC3::SelectCHRPage(7 ^ slotBase, _registers[5] | base);
+ } else {
+ MMC3::UpdateChrMapping();
+ }
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ if((_exRegs[0] & 0x07) == 0x04) {
+ SelectPrgPage4x(0, _exRegs[1] << 1);
+ } else if((_exRegs[0] & 0x07) == 0x03) {
+ SelectPrgPage2x(0, _exRegs[1] << 1);
+ SelectPrgPage2x(1, _exRegs[1] << 1);
+ } else {
+ if(_exRegs[0] & 0x03) {
+ uint32_t blocksize = 6 - (_exRegs[0] & 0x03);
+ uint32_t mask = (1 << blocksize) - 1;
+ MMC3::SelectPRGPage(slot, (page & mask) | (_exRegs[1] << 1));
+ } else {
+ MMC3::SelectPRGPage(slot, page & (_isFk23Ca ? 0x3F : 0x7F));
+ }
+
+ if(_exRegs[3] & 0x02) {
+ MMC3::SelectPRGPage(2, _exRegs[4]);
+ MMC3::SelectPRGPage(3, _exRegs[5]);
+ }
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr >= 0x8000) {
+ if(_exRegs[0] & 0x40) {
+ if(_exRegs[0] & 0x30) {
+ _chrReg = 0;
+ } else {
+ _chrReg = value & 0x03;
+ UpdateChrMapping();
+ }
+ } else {
+ if(addr == 0x8001 && (_exRegs[3] & 0x02) && (GetState().Reg8000 & 0x08)) {
+ _exRegs[0x04 | (GetState().Reg8000 & 0x03)] = value;
+ UpdateChrMapping();
+ UpdatePrgMapping();
+ } else {
+ if(addr < 0xC000) {
+ if(HasChrRam()) {
+ if((addr == 0x8000) && (value == 0x46)) {
+ value = 0x47;
+ } else if((addr == 0x8000) && (value == 0x47)) {
+ value = 0x46;
+ }
+ }
+ }
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+ } else {
+ if(addr & 0x10) {
+ _exRegs[addr & 0x03] = value;
+ if(((_exRegs[0] & 0xF0) == 0x20) || (addr & 0x03) == 1 || (addr & 0x03) == 2) {
+ UpdateState();
+ }
+ }
+
+ if(_isFk23Ca && (_exRegs[3] & 0x02)) {
+ _exRegs[0] &= ~7;
+ }
+ }
+ }
+
+public:
+ MMC3_Fk23C(bool isFk23Ca)
+ {
+ _isFk23Ca = isFk23Ca;
+ }
+};
\ No newline at end of file
diff --git a/Core/MapperFactory.cpp b/Core/MapperFactory.cpp
index 51623662..670f2887 100644
--- a/Core/MapperFactory.cpp
+++ b/Core/MapperFactory.cpp
@@ -160,6 +160,7 @@
#include "MMC3_BmcF15.h"
#include "MMC3_ChrRam.h"
#include "MMC3_Coolboy.h"
+#include "MMC3_Fk23C.h"
#include "MMC3_Kof97.h"
#include "MMC3_MaliSB.h"
#include "MMC3_StreetHeroes.h"
@@ -511,6 +512,8 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case UnifBoards::DreamTech01: return new DreamTech01();
case UnifBoards::Edu2000: return new Edu2000();
case UnifBoards::Eh8813A: return new Eh8813A();
+ case UnifBoards::Fk23C: return new MMC3_Fk23C(false);
+ case UnifBoards::Fk23Ca: return new MMC3_Fk23C(true);
case UnifBoards::Ghostbusters63in1: return new Ghostbusters63in1();
case UnifBoards::Gs2004: return new Gs2004();
case UnifBoards::Gs2013: return new Gs2013();
diff --git a/Core/UnifBoards.h b/Core/UnifBoards.h
index 658a160b..be50eede 100644
--- a/Core/UnifBoards.h
+++ b/Core/UnifBoards.h
@@ -49,5 +49,7 @@ namespace UnifBoards {
Unl43272,
Bmc411120C,
UnlPuzzle,
+ Fk23C,
+ Fk23Ca,
};
}
\ No newline at end of file
diff --git a/Core/UnifLoader.cpp b/Core/UnifLoader.cpp
index 97710703..6bc7b7f2 100644
--- a/Core/UnifLoader.cpp
+++ b/Core/UnifLoader.cpp
@@ -41,8 +41,8 @@ std::unordered_map UnifLoader::_boardMappings = std::unordered_map<
{ "ELROM", 5 },
{ "ETROM", 5 },
{ "EWROM", 5 },
- { "FK23C", UnifBoards::UnknownBoard },
- { "FK23CA", UnifBoards::UnknownBoard },
+ { "FK23C", UnifBoards::Fk23C },
+ { "FK23CA", UnifBoards::Fk23Ca },
{ "FS304", 162 },
{ "G-146", UnifBoards::BmcG146 },
{ "GK-192", 58 },