diff --git a/Core/Bmc235.h b/Core/Bmc235.h
index 9a97675ab..b34a611d1 100644
--- a/Core/Bmc235.h
+++ b/Core/Bmc235.h
@@ -4,12 +4,12 @@
class Bmc235 : public BaseMapper
{
-private:
- bool _openBus = false;
protected:
virtual uint16_t GetPRGPageSize() override { return 0x4000; }
virtual uint16_t GetCHRPageSize() override { return 0x2000; }
+ uint8_t _unrom;
+
void InitMapper() override
{
SelectPrgPage2x(0, 0);
@@ -19,45 +19,34 @@ class Bmc235 : public BaseMapper
void Reset(bool softReset) override
{
SelectPrgPage2x(0, 0);
- _openBus = false;
- }
-
- void StreamState(bool saving) override
- {
- BaseMapper::StreamState(saving);
- Stream(_openBus);
- if(!saving && _openBus) {
- RemoveCpuMemoryMapping(0x8000, 0xFFFF);
+ if(_prgSize & 0x20000) {
+ if(softReset) {
+ _unrom = !_unrom;
+ } else {
+ _unrom = false;
+ }
}
}
void WriteRegister(uint16_t addr, uint8_t value) override
{
- SetMirroringType((addr & 0x0400) ? MirroringType::ScreenAOnly : (addr & 0x2000) ? MirroringType::Horizontal : MirroringType::Vertical);
+ uint8_t bank = (addr >> 3) & 0x60 | (addr & 0x1F);
- const uint8_t config[4][4][2] = {
- { { 0x00, 0 }, { 0x00, 1 }, { 0x00, 1 }, { 0x00, 1 } },
- { { 0x00, 0 }, { 0x00, 1 }, { 0x20, 0 }, { 0x00, 1 } },
- { { 0x00, 0 }, { 0x00, 1 }, { 0x20, 0 }, { 0x40, 0 } },
- { { 0x00, 0 }, { 0x20, 0 }, { 0x40, 0 }, { 0x60, 0 } }
- };
+ if(_unrom) {
+ SetMirroringType(MirroringType::Vertical);
+ SelectPRGPage(0, GetPRGPageCount() & 0xC0 | value & 0x07);
+ SelectPRGPage(1, GetPRGPageCount() & 0xC0 | 0x07);
+ return;
+ }
- uint8_t mode;
- switch(GetPRGPageCount()) {
- case 64: mode = 0; break;
- case 128: mode = 1; break;
- case 256: mode = 2; break;
- default: mode = 3; break;
- };
+ if(bank >= (GetPRGPageCount() >> 1)) {
+ RemoveCpuMemoryMapping(0x8000, 0xFFFF);
+ return;
+ }
- uint8_t bank = config[mode][addr >> 8 & 0x03][0] | (addr & 0x1F);
+ SetMirroringType((addr & 0x0400) ? MirroringType::ScreenAOnly : (addr & 0x2000) ? MirroringType::Horizontal : MirroringType::Vertical);
- _openBus = false;
- if(config[mode][addr >> 8 & 0x03][1]) {
- //Open bus
- _openBus = true;
- RemoveCpuMemoryMapping(0x8000, 0xFFFF);
- } else if(addr & 0x800) {
+ if(addr & 0x800) {
bank = (bank << 1) | (addr >> 12 & 0x01);
SelectPRGPage(0, bank);
SelectPRGPage(1, bank);
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index d01ebc69e..46d5abdf1 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -769,6 +769,7 @@
+
@@ -784,6 +785,9 @@
+
+
+
@@ -796,8 +800,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 06609825b..af281d922 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -436,6 +436,9 @@
Nes\Mappers\Unnamed
+
+ Nes\Mappers\Unnamed
+
Nes\Mappers\Sunsoft
@@ -1429,6 +1432,15 @@
Nes\Mappers\Unnamed
+
+ Nes\Mappers\Unnamed
+
+
+ Nes\Mappers\Unnamed
+
+
+ Nes\Mappers\Unnamed
+
Nes\Mappers\MMC
@@ -1459,6 +1471,69 @@
Nes\Mappers\MMC
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
+
+ Nes\Mappers\MMC
+
Nes\Mappers\Unif
diff --git a/Core/MMC3_219.h b/Core/MMC3_219.h
index d4496ec83..e49fa5f1d 100644
--- a/Core/MMC3_219.h
+++ b/Core/MMC3_219.h
@@ -10,59 +10,79 @@ class MMC3_219 : public MMC3
void InitMapper() override
{
MMC3::InitMapper();
- SelectPrgPage4x(0, -4);
- SelectChrPage8x(0, 0);
- _exRegs[0] = _exRegs[1] = _exRegs[2] = 0;
+ AddRegisterRange(0x5000, 0x5FFF);
}
- void UpdatePrgMapping() override
+ void Reset(bool softreset) override
{
+ _exRegs[0] = _exRegs[2] = 0x00;
+ _exRegs[1] = 0x03;
+ MMC3::UpdateState();
}
- void UpdateChrMapping() override
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
{
+ MMC3::SelectCHRPage(slot, (_exRegs[1] << 7) | (page & 0x7F));
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ MMC3::SelectPRGPage(slot, (_exRegs[1] << 4) | (page & 0x0F));
}
void WriteRegister(uint16_t addr, uint8_t value) override
{
- if(addr < 0xA000) {
+ if(addr < 0x8000) {
+ switch(addr & 0x01) {
+ case 0: _exRegs[1] = (_exRegs[1] & ~0x01) | ((value >> 3) & 0x01); break;
+ case 1: _exRegs[1] = (_exRegs[1] & ~0x02) | ((value >> 4) & 0x02); break;
+ }
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ } else if(addr < 0xA000) {
switch(addr & 0xE003) {
- case 0x8000:
- _exRegs[0] = 0;
- _exRegs[1] = value;
- break;
+ case 0x8000:
+ MMC3::WriteRegister(addr, value);
+ break;
+
+ case 0x8002:
+ _exRegs[0] = value;
+ MMC3::WriteRegister(addr, value);
+ break;
- case 0x8001:
- if(_exRegs[0] >= 0x23 && _exRegs[0] <= 0x26) {
+ case 0x8001:
+ if(_exRegs[0] & 0x20) { // Extended Mode
+ uint8_t bankRegister = MMC3::GetState().Reg8000;
+ if((bankRegister >= 0x25) && (bankRegister <= 0x26)) {
uint8_t prgBank = ((value & 0x20) >> 5) | ((value & 0x10) >> 3) | ((value & 0x08) >> 1) | ((value & 0x04) << 1);
- SelectPRGPage(0x26 - _exRegs[0], prgBank);
- }
-
- switch(_exRegs[1]) {
- case 0x08: case 0x0A: case 0x0E: case 0x12: case 0x16: case 0x1A: case 0x1E:
- _exRegs[2] = value << 4;
- break;
+ MMC3::_registers[6 | (bankRegister & 0x01)] = prgBank;
+ MMC3::UpdatePrgMapping();
+ } else if((bankRegister >= 0x08) && (bankRegister <= 0x1F)) {
+ switch(bankRegister) {
+ case 0x08: case 0x0A: case 0x0E: case 0x12: case 0x16: case 0x1A: case 0x1E:
+ _exRegs[2] = value << 4;
+ break;
- case 0x09: SelectCHRPage(0, _exRegs[2] | (value >> 1 & 0x0E)); break;
- case 0x0B: SelectCHRPage(1, _exRegs[2] | (value >> 1 | 0x1)); break;
- case 0x0C:
- case 0x0D: SelectCHRPage(2, _exRegs[2] | (value >> 1 & 0xE)); break;
- case 0x0F: SelectCHRPage(3, _exRegs[2] | (value >> 1 | 0x1)); break;
- case 0x10:
- case 0x11: SelectCHRPage(4, _exRegs[2] | (value >> 1 & 0xF)); break;
- case 0x14:
- case 0x15: SelectCHRPage(5, _exRegs[2] | (value >> 1 & 0xF)); break;
- case 0x18:
- case 0x19: SelectCHRPage(6, _exRegs[2] | (value >> 1 & 0xF)); break;
- case 0x1C:
- case 0x1D: SelectCHRPage(7, _exRegs[2] | (value >> 1 & 0xF)); break;
+ case 0x09: MMC3::_registers[0] = _exRegs[2] | (value >> 1 & 0x0E); break;
+ case 0x0B: MMC3::_registers[0] = _exRegs[2] | (value >> 1 | 0x1); break;
+ case 0x0C:
+ case 0x0D: MMC3::_registers[1] = _exRegs[2] | (value >> 1 & 0xE); break;
+ case 0x0F: MMC3::_registers[1] = _exRegs[2] | (value >> 1 | 0x1); break;
+ case 0x10:
+ case 0x11: MMC3::_registers[2] = _exRegs[2] | (value >> 1 & 0xF); break;
+ case 0x14:
+ case 0x15: MMC3::_registers[3] = _exRegs[2] | (value >> 1 & 0xF); break;
+ case 0x18:
+ case 0x19: MMC3::_registers[4] = _exRegs[2] | (value >> 1 & 0xF); break;
+ case 0x1C:
+ case 0x1D: MMC3::_registers[5] = _exRegs[2] | (value >> 1 & 0xF); break;
+ }
+ MMC3::UpdateChrMapping();
}
- break;
-
- case 0x8002:
- _exRegs[0] = value;
- _exRegs[1] = 0;
- break;
+ } else { // Normal MMC3
+ MMC3::WriteRegister(addr, value);
+ }
+ break;
}
} else {
MMC3::WriteRegister(addr, value);
diff --git a/Core/MMC3_267.h b/Core/MMC3_267.h
new file mode 100644
index 000000000..694f91eeb
--- /dev/null
+++ b/Core/MMC3_267.h
@@ -0,0 +1,52 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_267 : public MMC3
+{
+private:
+ uint8_t _outerBank = 0;
+
+protected:
+ virtual uint16_t RegisterStartAddress() override { return 0x6000; }
+ virtual uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ virtual void Reset(bool softreset) override
+ {
+ _outerBank = 0;
+ MMC3::UpdateState();
+ }
+
+ virtual void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_outerBank);
+ }
+
+ virtual void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ page &= 0x7F;
+ page |= (((_outerBank >> 2) & 0x08) | (_outerBank & 0x06)) << 6;
+ MMC3::SelectCHRPage(slot, page, memoryType);
+ }
+
+ virtual void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ page &= 0x1F;
+ page |= (((_outerBank >> 2) & 0x08) | (_outerBank & 0x06)) << 4;
+ MMC3::SelectPRGPage(slot, page, memoryType);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ if(!(_outerBank & 0x80)) {
+ _outerBank = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_334.h b/Core/MMC3_334.h
new file mode 100644
index 000000000..5ab2cdc01
--- /dev/null
+++ b/Core/MMC3_334.h
@@ -0,0 +1,45 @@
+#pragma once
+#include "MMC3.h"
+
+class MMC3_334 : public MMC3
+{
+protected:
+ uint32_t GetDipSwitchCount() override { return 1; }
+ bool AllowRegisterRead() override { return true; }
+
+ void InitMapper() override
+ {
+ MMC3::InitMapper();
+ SelectPrgPage4x(0, -4);
+ SelectChrPage8x(0, 0);
+ AddRegisterRange(0x6000, 0x7FFF, MemoryOperation::Any);
+ RemoveRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read);
+ }
+
+ void UpdatePrgMapping() override
+ {
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ uint8_t value = _console->GetMemoryManager()->GetOpenBus();
+
+ if(addr & 0x02) {
+ value &= ~0x01;
+ value |= GetDipSwitches() & 0x01;
+ }
+
+ return value;
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ if(!(addr & 0x01)) {
+ SelectPrgPage4x(0, (value & 0xFE) << 1);
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_353.h b/Core/MMC3_353.h
new file mode 100644
index 000000000..898ddd27a
--- /dev/null
+++ b/Core/MMC3_353.h
@@ -0,0 +1,94 @@
+#pragma once
+#include "MMC3.h"
+
+class MMC3_353 : public MMC3
+{
+protected:
+ uint16_t GetChrRamPageSize() override { return 0x2000; }
+ uint32_t GetChrRamSize() override { return 0x2000; }
+
+ uint8_t _exReg;
+
+ void InitMapper() override
+ {
+ _exReg = 0;
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softreset)
+ {
+ _exReg = 0;
+ MMC3::UpdateState();
+ }
+
+ void UpdateMirroring() override
+ {
+ if(!(_exReg == 0)) {
+ MMC3::UpdateMirroring();
+ }
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType) override
+ {
+ if((_exReg == 2) && (MMC3::_registers[0] & 0x80)) {
+ MMC3::SelectChrPage8x(0, 0, ChrMemoryType::ChrRam);
+ } else {
+ MMC3::SelectCHRPage(slot, (_exReg << 7) | (page & 0x7F), memoryType);
+ }
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ if(_exReg == 2) {
+ page &= 0x0F;
+ page |= ((MMC3::_registers[0] >> 3) & 0x10);
+ page |= (_exReg << 5);
+ } else {
+ page &= 0x1F;
+ page |= (_exReg << 5);
+ }
+
+ MMC3::SelectPRGPage(slot, page);
+
+ if((_exReg == 3) && !(MMC3::_registers[0] & 0x80)) {
+ MMC3::SelectPRGPage(2, MMC3::_registers[6] | 0x70);
+ MMC3::SelectPRGPage(3, MMC3::_registers[7] | 0x70);
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if((addr & 0x80) == 0x80) {
+ _exReg = (addr >> 13) & 0x03;
+ UpdatePrgMapping();
+ UpdateChrMapping();
+ } else {
+ if((_exReg == 0) && (addr & 0xE001) == 0x8001) {
+ uint8_t nametable = value >> 7;
+
+ if(GetChrMode() == 0) {
+ switch(GetCurrentRegister()) {
+ case 0:
+ SetNametable(0, nametable);
+ SetNametable(1, nametable);
+ break;
+
+ case 1:
+ SetNametable(2, nametable);
+ SetNametable(3, nametable);
+ break;
+ }
+ } else {
+ switch(GetCurrentRegister()) {
+ case 2: SetNametable(0, nametable); break;
+ case 3: SetNametable(1, nametable); break;
+ case 4: SetNametable(2, nametable); break;
+ case 5: SetNametable(3, nametable); break;
+ }
+ }
+ }
+
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_364.h b/Core/MMC3_364.h
new file mode 100644
index 000000000..69dac6e9b
--- /dev/null
+++ b/Core/MMC3_364.h
@@ -0,0 +1,38 @@
+#pragma once
+#include "MMC3.h"
+
+class MMC3_364 : public MMC3
+{
+protected:
+ uint8_t _exReg;
+
+ void InitMapper() override
+ {
+ _exReg = 0;
+ MMC3::InitMapper();
+ AddRegisterRange(0x7000, 0x7FFF, MemoryOperation::Write);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType) override
+ {
+ uint8_t mask = (_exReg & 0x20) ? 0x7F : 0xFF;
+ MMC3::SelectCHRPage(slot, ((_exReg << 4) & 0x100) | (page & mask));
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ uint8_t mask = (_exReg & 0x20) ? 0x0F : 0x1F;
+ MMC3::SelectPRGPage(slot, ((_exReg >> 1) & 0x20) | (page & mask));
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr <= 0x7FFF) {
+ _exReg = value;
+ UpdatePrgMapping();
+ UpdateChrMapping();
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_370.h b/Core/MMC3_370.h
new file mode 100644
index 000000000..f7ce05f62
--- /dev/null
+++ b/Core/MMC3_370.h
@@ -0,0 +1,90 @@
+#pragma once
+#include "MMC3.h"
+
+class MMC3_370 : public MMC3
+{
+protected:
+ uint32_t GetDipSwitchCount() override { return 1; }
+ bool AllowRegisterRead() override { return true; }
+
+ uint8_t _exReg;
+
+ void InitMapper() override
+ {
+ _exReg = 0;
+ MMC3::InitMapper();
+ AddRegisterRange(0x5000, 0x5FFF, MemoryOperation::Any);
+ RemoveRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read);
+ }
+
+ void Reset(bool softreset)
+ {
+ _exReg = 0;
+ MMC3::UpdateState();
+ }
+
+ void UpdateMirroring() override
+ {
+ if((_exReg & 0x07) != 0x01) {
+ MMC3::UpdateMirroring();
+ }
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType) override
+ {
+ uint8_t mask = (_exReg & 0x04) ? 0xFF : 0x7F;
+ MMC3::SelectCHRPage(slot, ((_exReg << 7) & 0x380) | (page & mask));
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ uint8_t mask = (_exReg & 0x20) ? 0x0F : 0x1F;
+ MMC3::SelectPRGPage(slot, ((_exReg << 1) & 0x70) | (page & mask));
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ uint8_t value = _console->GetMemoryManager()->GetOpenBus();
+
+ value &= ~0x80;
+ value |= ((GetDipSwitches() << 7) & 0x80);
+
+ return value;
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x5FFF) {
+ _exReg = addr & 0x3F;
+ UpdatePrgMapping();
+ UpdateChrMapping();
+ } else {
+ if(((_exReg & 0x07) == 0x01) && (addr & 0xE001) == 0x8001) {
+ uint8_t nametable = value >> 7;
+
+ if(GetChrMode() == 0) {
+ switch(GetCurrentRegister()) {
+ case 0:
+ SetNametable(0, nametable);
+ SetNametable(1, nametable);
+ break;
+
+ case 1:
+ SetNametable(2, nametable);
+ SetNametable(3, nametable);
+ break;
+ }
+ } else {
+ switch(GetCurrentRegister()) {
+ case 2: SetNametable(0, nametable); break;
+ case 3: SetNametable(1, nametable); break;
+ case 4: SetNametable(2, nametable); break;
+ case 5: SetNametable(3, nametable); break;
+ }
+ }
+ }
+
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_372.h b/Core/MMC3_372.h
new file mode 100644
index 000000000..61ee7929f
--- /dev/null
+++ b/Core/MMC3_372.h
@@ -0,0 +1,18 @@
+#pragma once
+#include "MMC3_45.h"
+
+class MMC3_372 : public MMC3_45
+{
+private:
+ uint16_t GetChrRamPageSize() override { return 0x400; }
+ uint32_t GetChrRamSize() override { return 0x2000; }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ if(!(_reg[2] & 0x20)) {
+ page &= 0xFF >> (0x0F - (_reg[2] & 0x0F));
+ page |= _reg[0] | ((_reg[2] & 0xF0) << 4);
+ }
+ MMC3::SelectCHRPage(slot, page, (_reg[2] & 0x20) ? ChrMemoryType::ChrRam : ChrMemoryType::ChrRom);
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_376.h b/Core/MMC3_376.h
new file mode 100644
index 000000000..5d8b43b24
--- /dev/null
+++ b/Core/MMC3_376.h
@@ -0,0 +1,58 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_376 : public MMC3
+{
+private:
+ uint8_t _exReg[2];
+
+protected:
+ uint16_t RegisterStartAddress() override { return 0x7000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ void InitMapper() override
+ {
+ _exReg[0] = _exReg[1] = 0;
+ MMC3::InitMapper();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_exReg[0], _exReg[1]);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ page &= 0x7F;
+ page |= ((_exReg[1] << 8) & 0x100) | ((_exReg[0] << 1) & 0x80);
+ MMC3::SelectCHRPage(slot, page, memoryType);
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ uint8_t outerBank = ((_exReg[1] << 4) & 0x10) | ((_exReg[0] >> 3) & 0x08) | (_exReg[0] & 0x07);
+ if(_exReg[0] & 0x80) {
+ if(_exReg[0] & 0x20) {
+ MMC3::SelectPrgPage4x(0, (outerBank & 0xFE) << 1);
+ } else {
+ MMC3::SelectPrgPage2x(0, outerBank << 1);
+ MMC3::SelectPrgPage2x(1, outerBank << 1);
+ }
+ } else {
+ MMC3::SelectPRGPage(slot, ((outerBank << 1) & ~0x0F) | (page & 0x0F), memoryType);
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ _exReg[addr & 0x01] = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_377.h b/Core/MMC3_377.h
new file mode 100644
index 000000000..95284c543
--- /dev/null
+++ b/Core/MMC3_377.h
@@ -0,0 +1,52 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_377 : public MMC3
+{
+private:
+ uint8_t _outerBank = 0;
+
+protected:
+ virtual uint16_t RegisterStartAddress() override { return 0x6000; }
+ virtual uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ virtual void Reset(bool softreset) override
+ {
+ _outerBank = 0;
+ MMC3::UpdateState();
+ }
+
+ virtual void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_outerBank);
+ }
+
+ virtual void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ page &= 0x7F;
+ page |= (((_outerBank >> 2) & 0x08) | (_outerBank & 0x06)) << 6;
+ MMC3::SelectCHRPage(slot, page, memoryType);
+ }
+
+ virtual void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ page &= 0x0F;
+ page |= (((_outerBank >> 2) & 0x08) | (_outerBank & 0x06)) << 3;
+ MMC3::SelectPRGPage(slot, page, memoryType);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ if(!(_outerBank & 0x80)) {
+ _outerBank = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_383.h b/Core/MMC3_383.h
new file mode 100644
index 000000000..1db3487c2
--- /dev/null
+++ b/Core/MMC3_383.h
@@ -0,0 +1,79 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_383 : public MMC3
+{
+private:
+ uint8_t _A15;
+ uint8_t _A16;
+ uint8_t _A17A18;
+
+protected:
+ bool AllowRegisterRead() override { return true; }
+
+ void InitMapper() override
+ {
+ MMC3::InitMapper();
+ RemoveRegisterRange(0xC000, 0xFFFF, MemoryOperation::Read);
+ }
+
+ void Reset(bool softreset) override
+ {
+ _A15 = 0;
+ _A16 = 0;
+ _A17A18 = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_A15, _A16, _A17A18);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ MMC3::SelectCHRPage(slot, (_A17A18 << 3) | (page & 0x7F), memoryType);
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ switch(_A17A18) {
+ case 0x00:
+ page &= _A16 ? 0x07: 0x03;
+ MMC3::SelectPRGPage(slot, _A17A18 | _A16 | (_A16 ? 0x00 : _A15) | page);
+ break;
+ case 0x10:
+ case 0x20:
+ MMC3::SelectPRGPage(slot, _A17A18 | (page & 0x0F));
+ break;
+ case 0x30:
+ MMC3::SelectPRGPage(slot ^ 0x02, _A17A18 | (page & 0x0F));
+ if(slot == 3) {
+ SetCpuMemoryMapping(0x6000, 0x7FFF, _A17A18 | (page & 0x0B), PrgMemoryType::PrgRom);
+ }
+ break;
+ }
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ if(_A17A18 == 0x00) {
+ _A16 = MMC3::_registers[6 | (addr >> 13) & 0x01] & 0x08;
+ MMC3::UpdatePrgMapping();
+ }
+ return InternalReadRam(addr);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr & 0x100) {
+ _A15 = (addr >> 11) & 0x04;
+ _A17A18 = addr & 0x30;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ MMC3::WriteRegister(addr, value);
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_391.h b/Core/MMC3_391.h
new file mode 100644
index 000000000..d77492f38
--- /dev/null
+++ b/Core/MMC3_391.h
@@ -0,0 +1,72 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_391 : public MMC3
+{
+private:
+ uint8_t _reg[2];
+
+protected:
+ uint16_t RegisterStartAddress() override { return 0x6000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ void InitMapper() override
+ {
+ MMC3::InitMapper();
+ RemoveRegisterRange(0xC000, 0xFFFF, MemoryOperation::Read);
+ }
+
+ void Reset(bool softreset) override
+ {
+ _reg[0] = _reg[1] = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_reg[0], _reg[1]);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ uint8_t mask = (_reg[0] & 0x40) ? 0x7F : 0xFF;
+ page &= mask;
+ page |= ((_reg[1] << 8) & 0x100 | ((_reg[0] << 3) & 0x80)) & ~mask;
+ MMC3::SelectCHRPage(slot, page, memoryType);
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ uint8_t mask = (_reg[0] & 0x08) ? 0x0F: 0x1F;
+ uint8_t outerBank = (_reg[0] << 4) & 0x30;
+ if(_reg[0] &0x20) {
+ if(_reg[0] & 0x04) {
+ MMC3::SelectPRGPage(0, (outerBank & ~mask) | ((MMC3::_registers[6] & ~0x02) & mask));
+ MMC3::SelectPRGPage(1, (outerBank & ~mask) | ((MMC3::_registers[7] & ~0x02) & mask));
+ MMC3::SelectPRGPage(2, (outerBank & ~mask) | ((MMC3::_registers[6] | 0x02) & mask));
+ MMC3::SelectPRGPage(3, (outerBank & ~mask) | ((MMC3::_registers[7] | 0x02) & mask));
+ } else {
+ MMC3::SelectPRGPage(0, (outerBank & ~mask) | (MMC3::_registers[6] & mask));
+ MMC3::SelectPRGPage(1, (outerBank & ~mask) | (MMC3::_registers[7] & mask));
+ MMC3::SelectPRGPage(2, (outerBank & ~mask) | (MMC3::_registers[6] & mask));
+ MMC3::SelectPRGPage(3, (outerBank & ~mask) | (MMC3::_registers[7] & mask));
+ }
+ } else {
+ MMC3::SelectPRGPage(slot, (outerBank & ~mask) | (page & mask));
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ _reg[0] = value;
+ _reg[1] = addr >> 8;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_393.h b/Core/MMC3_393.h
new file mode 100644
index 000000000..bac970da3
--- /dev/null
+++ b/Core/MMC3_393.h
@@ -0,0 +1,72 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_393 : public MMC3
+{
+private:
+ uint8_t _exReg[2];
+
+protected:
+ uint16_t RegisterStartAddress() override { return 0x6000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ uint16_t GetChrRamPageSize() override { return 0x400; }
+ uint32_t GetChrRamSize() override { return 0x2000; }
+
+ void InitMapper() override
+ {
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softreset) override
+ {
+ _exReg[0] = _exReg[1] = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_exReg[0], _exReg[1]);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ if(_exReg[0] & 0x08) {
+ MMC3::SelectChrPage8x(0, 0, ChrMemoryType::ChrRam);
+ } else {
+ MMC3::SelectCHRPage(slot, (_exReg[0] << 8) | page, memoryType);
+ }
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ if(_exReg[0] & 0x20) {
+ if(_exReg[0] & 0x10) {
+ MMC3::SelectPrgPage2x(0, ((_exReg[0] << 3) | (_exReg[1] & 0x07)) << 1);
+ MMC3::SelectPrgPage2x(1, ((_exReg[0] << 3) | 0x07) << 1);
+ } else {
+ page = (MMC3::_registers[6] >> 2) & 3;
+ SelectPrgPage4x(0, ((_exReg[0] << 2) | page) << 2);
+ }
+ } else {
+ MMC3::SelectPRGPage(slot, (_exReg[0] << 4) | (page & 0x0F));
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ _exReg[0] = (uint8_t)addr;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ } else {
+ MMC3::WriteRegister(addr, value);
+ if(_exReg[1] != value) {
+ _exReg[1] = value;
+ MMC3::UpdatePrgMapping();
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_395.h b/Core/MMC3_395.h
new file mode 100644
index 000000000..7f4fcbc1f
--- /dev/null
+++ b/Core/MMC3_395.h
@@ -0,0 +1,53 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_395 : public MMC3
+{
+private:
+ uint8_t _exReg[2];
+
+protected:
+ uint16_t RegisterStartAddress() override { return 0x6000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ void Reset(bool softreset) override
+ {
+ _exReg[0] = _exReg[1] = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_exReg[0], _exReg[1]);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ uint8_t mask = (_exReg[1] & 0x40) ? 0x7F: 0xFF;
+ uint16_t outerBank = ((_exReg[1] << 5) & 0x400) | ((_exReg[0] << 4) & 0x300) | ((_exReg[1] << 3) & 0x80);
+ MMC3::SelectCHRPage(slot, outerBank | (page & mask));
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ uint8_t mask = (_exReg[1] & 0x08) ? 0x0F: 0x1F;
+ uint8_t outerBank = ((_exReg[0] << 4) & 0x80) | ((_exReg[0] << 1) & 0x60) | ((_exReg[1] << 4) &0x10);
+ MMC3::SelectPRGPage(slot, outerBank | (page & mask), memoryType);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ WritePrgRam(addr, value);
+ if(!(_exReg[1] & 0x80)) {
+ _exReg[(addr >> 4) & 0x01] = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_401.h b/Core/MMC3_401.h
new file mode 100644
index 000000000..766d524ce
--- /dev/null
+++ b/Core/MMC3_401.h
@@ -0,0 +1,33 @@
+#pragma once
+#include "MMC3_45.h"
+
+class MMC3_401 : public MMC3_45
+{
+private:
+ uint32_t GetDipSwitchCount() override { return 3; }
+ bool AllowRegisterRead() override { return true; }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ page &= 0x1F ^ (_reg[3] & 0x1F); // mask
+ page |= (_reg[2] & 0x80) | _reg[1] & 0x1F; // outerbank
+ page |= (GetDipSwitches() & 0x02) ? (_reg[2] & 0x20): ((_reg[1] >> 1) & 0x20); // A18
+ page |= (GetDipSwitches() & 0x04) ? (_reg[2] & 0x40): ((_reg[1] << 1) & 0x40); // A19
+
+ if((GetDipSwitches() & 0x01) && (_reg[1] & 0x80)) {
+ // openbus
+ } else {
+ MMC3::SelectPRGPage(slot, page, memoryType);
+ }
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ if((addr >= 0x8000) && (addr <= 0xFFFF)) {
+ if((GetDipSwitches() & 0x01) && (_reg[1] & 0x80)) {
+ return _console->GetMemoryManager()->GetOpenBus();
+ }
+ }
+ return InternalReadRam(addr);
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_410.h b/Core/MMC3_410.h
new file mode 100644
index 000000000..aa57085e8
--- /dev/null
+++ b/Core/MMC3_410.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "MMC3_45.h"
+
+class MMC3_410 : public MMC3_45
+{
+private:
+ uint16_t GetChrRamPageSize() override { return 0x400; }
+ uint32_t GetChrRamSize() override { return 0x2000; }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ uint8_t mask = 0xFF >> (0x0F - (_reg[2] & 0x0F));
+ if(_reg[2] & 0x40) {
+ MMC3::SelectChrPage8x(0, 0, ChrMemoryType::ChrRam);
+ } else {
+ page &= mask;
+ page |= _reg[0] | ((_reg[2] & 0xF0) << 4);
+ MMC3::SelectCHRPage(slot, page);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_411.h b/Core/MMC3_411.h
new file mode 100644
index 000000000..9851de828
--- /dev/null
+++ b/Core/MMC3_411.h
@@ -0,0 +1,62 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_411 : public MMC3
+{
+private:
+ uint8_t _exRegs[2];
+
+protected:
+ virtual void InitMapper() override
+ {
+ AddRegisterRange(0x5000, 0x5FFF);
+ MMC3::InitMapper();
+ }
+
+ virtual void Reset(bool softreset) override
+ {
+ _exRegs[0] = 0x80;
+ _exRegs[1] = 0x82;
+ MMC3::UpdateState();
+ }
+
+ virtual void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_exRegs[0], _exRegs[1]);
+ }
+
+ virtual void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ page &= (_exRegs[1] & 2) ? 0xFF : 0x7F;
+ MMC3::SelectCHRPage(slot, ((_exRegs[1] << 5) & 0x80) | ((_exRegs[0] << 4) & 0x100) | page);
+ }
+
+ virtual void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ if (_exRegs[0] & 0x40) { // NROM Mode
+ uint8_t bank = ((_exRegs[1] >> 2) & 0x10) | (_exRegs[1] & 0x08) | (_exRegs[0] & 0x04) | ((_exRegs[0] >> 2) & 0x02) | (_exRegs[0] & 0x01);
+ if (_exRegs[0] & 0x02) { // NROM-256
+ SelectPrgPage4x(0, (bank & 0xFE) << 1);
+ } else { // NROM-128
+ MMC3::SelectPrgPage2x(0, bank << 1);
+ MMC3::SelectPrgPage2x(1, bank << 1);
+ }
+ } else { // MMC3 Mode
+ page &= (_exRegs[1] & 2) ? 0x1F : 0x0F;
+ MMC3::SelectPRGPage(slot, ((_exRegs[1] >> 1) & 0x20) | ((_exRegs[1] << 1) & 0x10) | page);
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr <= 0x5FFF) {
+ _exRegs[addr & 0x01] = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_412.h b/Core/MMC3_412.h
new file mode 100644
index 000000000..ceb9a610a
--- /dev/null
+++ b/Core/MMC3_412.h
@@ -0,0 +1,72 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_412 : public MMC3
+{
+private:
+ uint8_t _exRegs[4];
+
+protected:
+ virtual uint16_t RegisterStartAddress() override { return 0x6000; }
+ virtual uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ void InitMapper() override
+ {
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softreset) override
+ {
+ _exRegs[0] = 0;
+ _exRegs[1] = 0;
+ _exRegs[2] = 0;
+ _exRegs[3] = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_exRegs[0], _exRegs[1], _exRegs[2], _exRegs[3]);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ if (_exRegs[2] & 0x02) {
+ MMC3::SelectChrPage8x(0, _exRegs[0] << 1);
+ } else {
+ page &= 0x7F;
+ MMC3::SelectCHRPage(slot, (_exRegs[1] & 0x80) | page);
+ }
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ if (_exRegs[2] & 0x02) { // NROM Mode
+ uint8_t bank = (_exRegs[2] >> 3);
+ if (_exRegs[2] & 0x04) { // NROM-256
+ SelectPrgPage4x(0, (bank & 0xFE) << 1);
+ } else { // NROM-128
+ MMC3::SelectPrgPage2x(0, bank << 1);
+ MMC3::SelectPrgPage2x(1, bank << 1);
+ }
+ } else { // MMC3 Mode
+ uint8_t mask = 0x3F & ~((_exRegs[1] << 3) & 0x38);
+ page &= mask;
+ page |= ((_exRegs[1] >> 2) & 0x3E) & ~mask;
+ MMC3::SelectPRGPage(slot, page);
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ _exRegs[addr & 0x03] = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_430.h b/Core/MMC3_430.h
new file mode 100644
index 000000000..f81f48f1c
--- /dev/null
+++ b/Core/MMC3_430.h
@@ -0,0 +1,64 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_430 : public MMC3
+{
+private:
+ uint8_t _reg;
+
+protected:
+ uint16_t RegisterStartAddress() override { return 0x6000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ void InitMapper() override
+ {
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softreset) override
+ {
+ _reg = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_reg);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ if(_reg & 0x04) {
+ MMC3::SelectCHRPage(slot, ((_reg << 6) & 0x180) | (page & 0x7F), memoryType);
+ } else {
+ MMC3::SelectCHRPage(slot, ((_reg << 6) & 0x100) | (page & 0xFF), memoryType);
+ }
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ if(_reg & 0x08) {
+ MMC3::SelectPRGPage(0, (_reg << 4) | ((MMC3::_registers[6] & ~0x02) & 0x0F));
+ MMC3::SelectPRGPage(1, (_reg << 4) | ((MMC3::_registers[7] & ~0x02) & 0x0F));
+ MMC3::SelectPRGPage(2, (_reg << 4) | ((MMC3::_registers[6] | 0x02) & 0x0F));
+ MMC3::SelectPRGPage(3, (_reg << 4) | ((MMC3::_registers[7] | 0x02) & 0x0F));
+ } else {
+ MMC3::SelectPRGPage(slot, (_reg << 4) | (page & 0x0F));
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ if(MMC3::CanWriteToWorkRam()) {
+ _reg = (uint8_t)addr;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_432.h b/Core/MMC3_432.h
new file mode 100644
index 000000000..e36abf659
--- /dev/null
+++ b/Core/MMC3_432.h
@@ -0,0 +1,77 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_432 : public MMC3
+{
+private:
+ uint8_t _exRegs[2];
+
+protected:
+ uint32_t GetDipSwitchCount() override { return 2; }
+ uint16_t RegisterStartAddress() override { return 0x6000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+ bool AllowRegisterRead() override { return true; }
+
+ void InitMapper() override
+ {
+ RemoveRegisterRange(0x6000, 0x7FFF, MemoryOperation::Read);
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softreset) override
+ {
+ _exRegs[0] = 0;
+ _exRegs[1] = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_exRegs[0], _exRegs[1]);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ uint8_t mask = (_exRegs[1] & 0x04) ? 0x7F : 0xFF;
+ page &= mask;
+ page |= (((_exRegs[1] << 5) & 0x100) | ((_exRegs[1] << 7) & 0x80)) & ~mask;
+ MMC3::SelectCHRPage(slot, page, memoryType);
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ uint8_t mask = (_exRegs[1] & 0x02) ? 0x0F : 0x1F;
+ uint8_t outerBank = ((_exRegs[1] << 1) & 0x20) | ((_exRegs[1] << 4) & 0x10);
+ if(_exRegs[1] & 0x40) {
+ MMC3::SelectPRGPage(0, (outerBank & ~mask) | (MMC3::_registers[6] & mask), memoryType);
+ MMC3::SelectPRGPage(1, (outerBank & ~mask) | (MMC3::_registers[7] & mask), memoryType);
+ MMC3::SelectPRGPage(2, (outerBank & ~mask) | (MMC3::_registers[6] & mask), memoryType);
+ MMC3::SelectPRGPage(3, (outerBank & ~mask) | (MMC3::_registers[7] & mask), memoryType);
+ } else {
+ MMC3::SelectPRGPage(slot, (outerBank & ~mask) | (page & mask), memoryType);
+ }
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ if(_exRegs[0] & 0x01) {
+ return GetDipSwitches();
+ }
+ return InternalReadRam(addr);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ if(MMC3::CanWriteToWorkRam()) {
+ _exRegs[addr & 0x01] = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_441.h b/Core/MMC3_441.h
new file mode 100644
index 000000000..954af8f96
--- /dev/null
+++ b/Core/MMC3_441.h
@@ -0,0 +1,67 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_441 : public MMC3
+{
+private:
+ uint8_t _reg;
+
+protected:
+ uint16_t RegisterStartAddress() override { return 0x6000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ void InitMapper() override
+ {
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softreset) override
+ {
+ _reg = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_reg);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ uint8_t mask = (_reg & 0x40) ? 0x7F : 0xFF;
+ page &= mask;
+ page |= ((_reg << 3) & 0x180) & ~mask;
+ MMC3::SelectCHRPage(slot, page, memoryType);
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ uint8_t mask = (_reg & 0x08) ? 0x0F: 0x1F;
+ uint8_t outerBank = (_reg << 4) & 0x30;
+ if(_reg & 0x04) {
+ MMC3::SelectPRGPage(0, (outerBank & ~mask) | ((MMC3::_registers[6] & ~0x02) & mask));
+ MMC3::SelectPRGPage(1, (outerBank & ~mask) | ((MMC3::_registers[7] & ~0x02) & mask));
+ MMC3::SelectPRGPage(2, (outerBank & ~mask) | ((MMC3::_registers[6] | 0x02) & mask));
+ MMC3::SelectPRGPage(3, (outerBank & ~mask) | ((MMC3::_registers[7] | 0x02) & mask));
+ } else {
+ MMC3::SelectPRGPage(slot, (outerBank & ~mask) | (page & mask));
+ }
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ if(MMC3::CanWriteToWorkRam()) {
+ if(!(_reg & 0x80)) {
+ _reg = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_444.h b/Core/MMC3_444.h
new file mode 100644
index 000000000..6da5848ac
--- /dev/null
+++ b/Core/MMC3_444.h
@@ -0,0 +1,82 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+// NES 2.0 Mapper 444 denotes the NC7000M multicart circuit board.
+// Its UNIF board name is BMC-BS-110, which is the name of a different PCB whose name was mixed-up.
+
+class MMC3_444 : public MMC3
+{
+private:
+ uint8_t _exRegs;
+
+protected:
+ uint32_t GetDipSwitchCount() override { return 2; }
+ uint16_t RegisterStartAddress() override { return 0x6000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+ bool AllowRegisterRead() override { return true; }
+
+ void InitMapper() override
+ {
+ RemoveRegisterRange(0x6000, 0x7FFF, MemoryOperation::Read);
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softreset) override
+ {
+ _exRegs = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_exRegs);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ uint8_t mask = (_romInfo.SubMapperID & 0x01) ? 0xFF : 0x7F;
+ uint16_t outerBank = (_exRegs << 7) & ((_romInfo.SubMapperID & 0x01) ? 0x00 : 0x80); // A17
+ outerBank |= ((_exRegs << ((_romInfo.SubMapperID & 0x02) ? 4 : 7)) & 0x100); // A18
+ MMC3::SelectCHRPage(slot, (outerBank & ~mask) | (page & mask), memoryType);
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ if(_exRegs & 0x04) {
+ page = (_exRegs << 4) | (MMC3::_registers[6] & 0x0F);
+ if(_exRegs & 0x08) {
+ page &= 0xFE;
+ MMC3::SelectPrgPage2x(0, page, memoryType);
+ MMC3::SelectPrgPage2x(1, page, memoryType);
+ } else {
+ page &= 0xFC;
+ MMC3::SelectPrgPage4x(0, page, memoryType);
+ }
+ } else {
+ MMC3::SelectPRGPage(slot, (_exRegs << 4) | (page & 0x0F), memoryType);
+ }
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ if((_exRegs & 0x0C) == 0x08) {
+ return GetDipSwitches();
+ }
+ return InternalReadRam(addr);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ /*if(MMC3::CanWriteToWorkRam()) */{
+ _exRegs = (uint8_t)addr;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_445.h b/Core/MMC3_445.h
new file mode 100644
index 000000000..3dfbc196e
--- /dev/null
+++ b/Core/MMC3_445.h
@@ -0,0 +1,56 @@
+#pragma once
+#include "stdafx.h"
+#include "MMC3.h"
+
+class MMC3_445 : public MMC3
+{
+private:
+ uint8_t _reg[4];
+
+protected:
+
+ void InitMapper() override
+ {
+ AddRegisterRange(0x5000, 0x5FFF);
+ MMC3::InitMapper();
+ }
+
+ void Reset(bool softreset) override
+ {
+ _reg[0] = _reg[1] = _reg[2] = _reg[3] = 0;
+ MMC3::UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ MMC3::StreamState(saving);
+ Stream(_reg[0], _reg[1], _reg[2], _reg[3]);
+ }
+
+ void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
+ {
+ uint8_t mask = (_reg[2] & 0x08) ? 0x7F : 0xFF;
+ MMC3::SelectCHRPage(slot, ((_reg[1] << 3) & ~mask) | (page & mask), memoryType);
+ }
+
+ void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
+ {
+ uint8_t mask = (_reg[2] & 0x01) ? 0x0F: 0x1F;
+ MMC3::SelectPRGPage(slot, (_reg[0] & ~mask) | (page & mask), memoryType);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ if(MMC3::CanWriteToWorkRam()) {
+ if(!(_reg[3] & 0x20)) {
+ _reg[addr & 0x03] = value;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
+ }
+ }
+ } else {
+ MMC3::WriteRegister(addr, value);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/MMC3_45.h b/Core/MMC3_45.h
index 5f64adbc0..197bac2d8 100644
--- a/Core/MMC3_45.h
+++ b/Core/MMC3_45.h
@@ -6,24 +6,16 @@ class MMC3_45 : public MMC3
{
private:
uint8_t _regIndex;
- uint8_t _reg[4];
protected:
- virtual uint16_t RegisterStartAddress() override { return 0x8000; }
+ uint8_t _reg[4];
+
+ virtual uint16_t RegisterStartAddress() override { return 0x6000; }
virtual uint16_t RegisterEndAddress() override { return 0xFFFF; }
virtual void InitMapper() override
{
MMC3::InitMapper();
-
- //Needed by Famicom Yarou Vol 1 - Game apparently writes to CHR RAM before initializing the registers
- _registers[0] = 0;
- _registers[1] = 2;
- _registers[2] = 4;
- _registers[3] = 5;
- _registers[4] = 6;
- _registers[5] = 7;
- UpdateChrMapping();
}
virtual void StreamState(bool saving) override
@@ -31,26 +23,24 @@ class MMC3_45 : public MMC3
MMC3::StreamState(saving);
ArrayInfo reg = { _reg, 4 };
Stream(_regIndex, reg);
-
- if(_reg[3] & 0x40) {
- RemoveRegisterRange(0x6000, 0x7FFF);
- }
}
virtual void Reset(bool softReset) override
{
- AddRegisterRange(0x6000, 0x7FFF);
_regIndex = 0;
- memset(_reg, 0, sizeof(_reg));
+ _reg[0] = 0x00;
+ _reg[1] = 0x00;
_reg[2] = 0x0F;
+ _reg[3] = 0x00;
UpdateState();
}
virtual void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override
{
+ uint8_t mask = 0xFF >> (0x0F - (_reg[2] & 0x0F));
if(!HasChrRam()) {
- page &= 0xFF >> (0x0F - (_reg[2] & 0x0F));
- page |= _reg[0] | ((_reg[2] & 0xF0) << 4);
+ page &= mask;
+ page |= ((_reg[0] | ((_reg[2] & 0xF0) << 4)) & ~mask);
}
MMC3::SelectCHRPage(slot, page, memoryType);
}
@@ -58,22 +48,20 @@ class MMC3_45 : public MMC3
virtual void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override
{
page &= 0x3F ^ (_reg[3] & 0x3F);
- page |= _reg[1];
+ page |= ((_reg[2] << 2) & 0x300) | _reg[1];
MMC3::SelectPRGPage(slot, page, memoryType);
}
void WriteRegister(uint16_t addr, uint8_t value) override
{
if(addr < 0x8000) {
+ WritePrgRam(addr, value);
if(!(_reg[3] & 0x40)) {
_reg[_regIndex] = value;
_regIndex = (_regIndex + 1) & 0x03;
+ MMC3::UpdatePrgMapping();
+ MMC3::UpdateChrMapping();
}
-
- if(_reg[3] & 0x40) {
- RemoveRegisterRange(0x6000, 0x7FFF);
- }
- UpdateState();
} else {
MMC3::WriteRegister(addr, value);
}
diff --git a/Core/Mapper227.h b/Core/Mapper227.h
index 748233f06..6ce2516a7 100644
--- a/Core/Mapper227.h
+++ b/Core/Mapper227.h
@@ -4,20 +4,44 @@
class Mapper227 : public BaseMapper
{
protected:
+ uint32_t GetDipSwitchCount() override { return 4; }
uint16_t GetPRGPageSize() override { return 0x4000; }
uint16_t GetCHRPageSize() override { return 0x2000; }
+ bool AllowRegisterRead() override { return true; }
+
+ bool _mFlag;
void InitMapper() override
{
WriteRegister(0x8000, 0);
}
+ void Reset(bool softreset) override
+ {
+ WriteRegister(0x8000, 0);
+ }
+
+ void StreamState(bool saving) override
+ {
+ BaseMapper::StreamState(saving);
+ Stream(_mFlag);
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ if(_mFlag) {
+ addr |= GetDipSwitches();
+ }
+ return InternalReadRam(addr);
+ }
+
void WriteRegister(uint16_t addr, uint8_t value) override
{
uint16_t prgBank = ((addr >> 2) & 0x1F) | ((addr & 0x100) >> 3);
bool sFlag = (addr & 0x01) == 0x01;
bool lFlag = ((addr >> 9) & 0x01) == 0x01;
bool prgMode = ((addr >> 7) & 0x01) == 0x01;
+ _mFlag = ((addr >> 10) & 0x01) == 0x01;
if(prgMode) {
if(sFlag) {
@@ -46,6 +70,9 @@ class Mapper227 : public BaseMapper
}
}
+ // protect CHR-RAM on nrom modes
+ SetPpuMemoryMapping(0, 0x1FFF, 0, ChrMemoryType::Default, (!HasBattery() && prgMode) ? MemoryAccessType::Read : MemoryAccessType::ReadWrite);
+
SetMirroringType((addr & 0x02) == 0x02 ? MirroringType::Horizontal : MirroringType::Vertical);
}
};
\ No newline at end of file
diff --git a/Core/Mapper242.h b/Core/Mapper242.h
index de8279a49..af960f5fd 100644
--- a/Core/Mapper242.h
+++ b/Core/Mapper242.h
@@ -1,28 +1,69 @@
-#pragma once
-#include "stdafx.h"
+#pragma once
#include "BaseMapper.h"
class Mapper242 : public BaseMapper
{
protected:
- virtual uint16_t GetPRGPageSize() override { return 0x8000; }
- virtual uint16_t GetCHRPageSize() override { return 0x2000; }
+ uint16_t GetPRGPageSize() override { return 0x4000; }
+ uint16_t GetCHRPageSize() override { return 0x2000; }
void InitMapper() override
{
- Reset(false);
- SelectCHRPage(0, 0);
+ WriteRegister(0x8000, 0);
}
- virtual void Reset(bool softReset) override
+ void Reset(bool softreset) override
{
- SelectPRGPage(0, 0);
- SetMirroringType(MirroringType::Vertical);
+ WriteRegister(0x8000, 0);
}
void WriteRegister(uint16_t addr, uint8_t value) override
{
- SetMirroringType(addr & 0x02 ? MirroringType::Horizontal : MirroringType::Vertical);
- SelectPRGPage(0, (addr >> 3) & 0x0F);
+ uint16_t prgBank = (addr >> 2) & 0x1F;
+ bool sFlag = (addr & 0x01) == 0x01;
+ bool lFlag = ((addr >> 9) & 0x01) == 0x01;
+ bool prgMode = ((addr >> 7) & 0x01) == 0x01;
+ bool cFlag = ((addr >> 10) & 0x01) == 0x01;
+ bool twoChips = (_prgSize & 0x20000) && (_prgSize > 0x20000);
+
+ if(twoChips) {
+ if(cFlag | lFlag) {
+ prgBank &= 0x1F;
+ } else {
+ prgBank = 0x20 + (prgBank & 0x07);
+ }
+ }
+
+ if(prgMode) {
+ if(sFlag) {
+ SelectPrgPage2x(0, prgBank & 0xFE);
+ } else {
+ SelectPRGPage(0, prgBank);
+ SelectPRGPage(1, prgBank);
+ }
+ } else {
+ if(sFlag){
+ if(lFlag) {
+ SelectPRGPage(0, prgBank & 0x3E);
+ SelectPRGPage(1, prgBank | 0x07);
+ } else {
+ SelectPRGPage(0, prgBank & 0x3E);
+ SelectPRGPage(1, prgBank & 0x38);
+ }
+ } else {
+ if(lFlag) {
+ SelectPRGPage(0, prgBank);
+ SelectPRGPage(1, prgBank | 0x07);
+ } else {
+ SelectPRGPage(0, prgBank);
+ SelectPRGPage(1, prgBank & 0x38);
+ }
+ }
+ }
+
+ // protect CHR-RAM on nrom modes
+ SetPpuMemoryMapping(0, 0x1FFF, 0, ChrMemoryType::Default, (!HasBattery() && prgMode && (_prgSize > 256 * 1024)) ? MemoryAccessType::Read : MemoryAccessType::ReadWrite);
+
+ SetMirroringType((addr & 0x02) == 0x02 ? MirroringType::Horizontal : MirroringType::Vertical);
}
};
\ No newline at end of file
diff --git a/Core/Mapper319.h b/Core/Mapper319.h
new file mode 100644
index 000000000..a39e8d3e7
--- /dev/null
+++ b/Core/Mapper319.h
@@ -0,0 +1,51 @@
+#pragma once
+#include "stdafx.h"
+#include "BaseMapper.h"
+
+class Mapper319 : public BaseMapper
+{
+private:
+ uint8_t _regs[3];
+
+protected:
+ uint16_t GetPRGPageSize() override { return 0x4000; }
+ uint16_t GetCHRPageSize() override { return 0x2000; }
+ uint16_t RegisterStartAddress() override { return 0x6000; }
+ uint16_t RegisterEndAddress() override { return 0xFFFF; }
+
+ void InitMapper() override
+ {
+ _regs[0] = _regs[1] = _regs[2] = 0;
+ UpdateState();
+ }
+
+ void StreamState(bool saving) override
+ {
+ BaseMapper::StreamState(saving);
+ Stream(_regs[0], _regs[1], _regs[2]);
+ }
+
+ void UpdateState()
+ {
+ if(_regs[1] & 0x40) {
+ SelectPrgPage2x(0, (_regs[1] >> 2) & 0xE);
+ } else {
+ uint8_t bank = (_regs[1] >> 2) & 0x06 | (_regs[1] >> 5) & 0x01;
+ SelectPRGPage(0, bank);
+ SelectPRGPage(1, bank);
+ }
+ SelectCHRPage(0, (_regs[0] >> 4) & ~((_regs[0] << 2) & 0x04) | (_regs[2] << 2) & ((_regs[0] << 2) & 0x04));
+ SetMirroringType(_regs[1] & 0x80 ? MirroringType::Vertical : MirroringType::Horizontal);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x8000) {
+ _regs[(addr & 0x04) >> 2] = value;
+ UpdateState();
+ } else {
+ _regs[2] = value;
+ UpdateState();
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/Mapper375.h b/Core/Mapper375.h
new file mode 100644
index 000000000..f15636f58
--- /dev/null
+++ b/Core/Mapper375.h
@@ -0,0 +1,78 @@
+#pragma once
+#include "BaseMapper.h"
+
+class Mapper375 : public BaseMapper
+{
+protected:
+ uint16_t GetPRGPageSize() override { return 0x4000; }
+ uint16_t GetCHRPageSize() override { return 0x2000; }
+
+ uint16_t latchea;
+ uint8_t latched;
+
+ void InitMapper() override
+ {
+ WriteRegister(0x8000, 0);
+ }
+
+ virtual void StreamState(bool saving) override
+ {
+ BaseMapper::StreamState(saving);
+ Stream(latchea, latched);
+ }
+
+ void UpdateState()
+ {
+ uint16_t prgBank = ((latchea >> 2) & 0x1F) | ((latchea >> 3) & 0x20) | ((latchea >> 4) & 0x40);
+ bool sFlag = (latchea & 0x01) == 0x01;
+ bool lFlag = ((latchea >> 9) & 0x01) == 0x01;
+ bool prgMode = ((latchea >> 7) & 0x01) == 0x01;
+ uint16_t p0 = prgBank;
+
+ if((latchea & 0x800) == 0x800)
+ p0 = (prgBank & ~0x07) | (latched & 0x07);
+
+ if (prgMode) {
+ if (sFlag) {
+ SelectPrgPage2x(0, prgBank & 0xFE);
+ } else {
+ SelectPRGPage(0, p0);
+ SelectPRGPage(1, prgBank);
+ }
+ } else {
+ if (sFlag) {
+ if (lFlag) {
+ SelectPRGPage(0, p0 & 0x7E);
+ SelectPRGPage(1, prgBank | 0x07);
+ } else {
+ SelectPRGPage(0, p0 & 0x7E);
+ SelectPRGPage(1, prgBank & 0x78);
+ }
+ } else {
+ if (lFlag) {
+ SelectPRGPage(0, p0);
+ SelectPRGPage(1, prgBank | 0x07);
+ } else {
+ SelectPRGPage(0, p0);
+ SelectPRGPage(1, prgBank & 0x78);
+ }
+ }
+ }
+
+ // protect CHR-RAM on nrom modes
+ SetPpuMemoryMapping(0, 0x1FFF, 0, ChrMemoryType::Default, (latchea & 0x80) ? MemoryAccessType::Read : MemoryAccessType::ReadWrite);
+
+ SetMirroringType((latchea & 0x02) == 0x02 ? MirroringType::Horizontal : MirroringType::Vertical);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(latchea & 0x800) {
+ latched = value;
+ } else {
+ latchea = addr;
+ latched = value;
+ }
+ UpdateState();
+ }
+};
\ No newline at end of file
diff --git a/Core/Mapper380.h b/Core/Mapper380.h
new file mode 100644
index 000000000..c4337526a
--- /dev/null
+++ b/Core/Mapper380.h
@@ -0,0 +1,63 @@
+#pragma once
+#include "BaseMapper.h"
+
+class Mapper380 : public BaseMapper
+{
+protected:
+ uint32_t GetDipSwitchCount() override { return 4; }
+ uint16_t GetPRGPageSize() override { return 0x4000; }
+ uint16_t GetCHRPageSize() override { return 0x2000; }
+ bool AllowRegisterRead() override { return true; }
+
+ bool _mFlag;
+
+ void InitMapper() override
+ {
+ WriteRegister(0x8000, 0);
+ }
+
+ void Reset(bool softreset) override
+ {
+ WriteRegister(0x8000, 0);
+ }
+
+ void StreamState(bool saving) override
+ {
+ BaseMapper::StreamState(saving);
+ Stream(_mFlag);
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ if(_mFlag && _romInfo.SubMapperID == 0) {
+ addr |= GetDipSwitches();
+ }
+ return InternalReadRam(addr);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ uint16_t prgBank = (addr >> 2) & 0x1F;
+ bool sFlag = (addr & 0x01) == 0x01;
+ bool prgMode = ((addr >> 9) & 0x01) == 0x01;
+
+ _mFlag = ((addr >> 8) & 0x01) == 0x01;
+
+ if (prgMode) {
+ if (sFlag) {
+ SelectPRGPage(0, prgBank);
+ SelectPRGPage(1, prgBank);
+ } else {
+ SelectPrgPage2x(0, prgBank & 0xFE);
+ }
+ } else {
+ SelectPRGPage(0, prgBank);
+ SelectPRGPage(1, prgBank | 0x07 | (((_romInfo.SubMapperID == 1) && (addr & 0x100)) ? 0x08: 0x00));
+ }
+
+ // protect CHR-RAM on nrom modes
+ SetPpuMemoryMapping(0, 0x1FFF, 0, ChrMemoryType::Default, (addr & 0x80) ? MemoryAccessType::Read : MemoryAccessType::ReadWrite);
+
+ SetMirroringType((addr & 0x02) == 0x02 ? MirroringType::Horizontal : MirroringType::Vertical);
+ }
+};
\ No newline at end of file
diff --git a/Core/Mapper449.h b/Core/Mapper449.h
new file mode 100644
index 000000000..e7d5f724f
--- /dev/null
+++ b/Core/Mapper449.h
@@ -0,0 +1,66 @@
+#pragma once
+#include "BaseMapper.h"
+
+class Mapper449 : public BaseMapper
+{
+protected:
+ uint32_t GetDipSwitchCount() override { return 4; }
+ uint16_t GetPRGPageSize() override { return 0x4000; }
+ uint16_t GetCHRPageSize() override { return 0x2000; }
+ bool AllowRegisterRead() override { return true; }
+
+ bool _mFlag;
+
+ void InitMapper() override
+ {
+ WriteRegister(0x8000, 0);
+ }
+
+ void Reset(bool softreset) override
+ {
+ WriteRegister(0x8000, 0);
+ }
+
+ void StreamState(bool saving) override
+ {
+ BaseMapper::StreamState(saving);
+ Stream(_mFlag);
+ }
+
+ uint8_t ReadRegister(uint16_t addr) override
+ {
+ if(_mFlag) {
+ addr |= GetDipSwitches();
+ }
+ return InternalReadRam(addr);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ uint16_t prgBank = ((addr >> 2) & 0x1F) | ((addr >> 3) & 0x20);
+ bool sFlag = (addr & 0x01) == 0x01;
+ bool lFlag = ((addr >> 9) & 0x01) == 0x01;
+ bool prgMode = ((addr >> 7) & 0x01) == 0x01;
+
+ _mFlag = ((addr >> 9) & 0x01) == 0x01;
+
+ if(prgMode) {
+ if(sFlag) {
+ SelectPrgPage2x(0, prgBank & 0xFE);
+ } else {
+ SelectPRGPage(0, prgBank);
+ SelectPRGPage(1, prgBank);
+ }
+ } else {
+ SelectPRGPage(0, prgBank);
+ SelectPRGPage(1, prgBank | 0x07);
+ }
+
+ // protect CHR-RAM on nrom modes
+ SetPpuMemoryMapping(0, 0x1FFF, 0, ChrMemoryType::Default, (!HasBattery() && prgMode) ? MemoryAccessType::Read : MemoryAccessType::ReadWrite);
+
+ SelectCHRPage(0, value);
+
+ SetMirroringType((addr & 0x02) == 0x02 ? MirroringType::Horizontal : MirroringType::Vertical);
+ }
+};
\ No newline at end of file
diff --git a/Core/Mapper91.h b/Core/Mapper91.h
index 0cffdbcb2..17932d405 100644
--- a/Core/Mapper91.h
+++ b/Core/Mapper91.h
@@ -6,39 +6,100 @@ class Mapper91 : public MMC3
{
protected:
virtual uint16_t RegisterStartAddress() override { return 0x6000; }
- virtual uint16_t RegisterEndAddress() override { return 0x7FFF; }
+ virtual uint16_t RegisterEndAddress() override { return 0x9FFF; }
virtual uint16_t GetPRGPageSize() override { return 0x2000; }
virtual uint16_t GetCHRPageSize() override { return 0x800; }
+ uint8_t _prgBanks[2];
+ uint8_t _chrBanks[4];
+ uint8_t _outerBank;
+
+ // for Submapper 1
+ bool _verticalMirroring;
+
void InitMapper() override
{
- SelectPRGPage(2, -2);
- SelectPRGPage(3, -1);
+ UpdateState();
}
- void UpdateState() override
+ void UpdateState()
{
- //Do nothing, we are only using MMC3 code to emulate the IRQs
+ SelectPRGPage(0, ((_outerBank << 3) & 0x30) | (_prgBanks[0] & 0x0F));
+ SelectPRGPage(1, ((_outerBank << 3) & 0x30) | (_prgBanks[1] & 0x0F));
+ SelectPRGPage(2, ((_outerBank << 3) & 0x30) | 0xE);
+ SelectPRGPage(3, ((_outerBank << 3) & 0x30) | 0xF);
+
+ SelectCHRPage(0, ((_outerBank << 8) & 0x100) | _chrBanks[0]);
+ SelectCHRPage(1, ((_outerBank << 8) & 0x100) | _chrBanks[1]);
+ SelectCHRPage(2, ((_outerBank << 8) & 0x100) | _chrBanks[2]);
+ SelectCHRPage(3, ((_outerBank << 8) & 0x100) | _chrBanks[3]);
+
+ if(_romInfo.SubMapperID == 1) {
+ SetMirroringType(_verticalMirroring ? MirroringType::Vertical : MirroringType::Horizontal);
+ }
}
void WriteRegister(uint16_t addr, uint8_t value) override
{
- switch(addr & 0x7003) {
- case 0x6000: SelectCHRPage(0, value); break;
- case 0x6001: SelectCHRPage(1, value); break;
- case 0x6002: SelectCHRPage(2, value); break;
- case 0x6003: SelectCHRPage(3, value); break;
- case 0x7000: SelectPRGPage(0, value & 0x0F); break;
- case 0x7001: SelectPRGPage(1, value & 0x0F); break;
- case 0x7002:
- MMC3::WriteRegister(0xE000, value);
- break;
- case 0x7003:
- MMC3::WriteRegister(0xC000, 0x07);
- MMC3::WriteRegister(0xC001, value);
- MMC3::WriteRegister(0xE001, value);
- break;
+ if(addr <= 0x6FFF) {
+ if(_romInfo.SubMapperID == 1) {
+ switch(addr & 0x07) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ _chrBanks[addr & 0x03] = value;
+ UpdateState();
+ return;
+
+ case 0x04:
+ case 0x05:
+ _verticalMirroring = (addr & 0x01) == 0x01;
+ UpdateState();
+ return;
+
+ case 0x06:
+ return;
+
+ case 0x07:
+ return;
+
+ default:
+ return;
+ }
+ } else {
+ _chrBanks[addr & 0x03] = value;
+ UpdateState();
+ return;
+ }
}
+
+ if(addr <= 0x7FFF) {
+ switch(addr & 0x03) {
+ case 0x00:
+ case 0x01:
+ _prgBanks[addr & 0x01] = value;
+ UpdateState();
+ return;
+
+ case 0x02:
+ MMC3::WriteRegister(0xE000, value);
+ return;
+
+ case 0x03:
+ MMC3::WriteRegister(0xC000, 0x07);
+ MMC3::WriteRegister(0xC001, value);
+ MMC3::WriteRegister(0xE001, value);
+ return;
+
+ default:
+ return;
+
+ }
+ }
+
+ _outerBank = (uint8_t)addr;
+ UpdateState();
}
};
\ No newline at end of file
diff --git a/Core/MapperFactory.cpp b/Core/MapperFactory.cpp
index f46b49316..4391a4f20 100644
--- a/Core/MapperFactory.cpp
+++ b/Core/MapperFactory.cpp
@@ -157,6 +157,10 @@
#include "Mapper244.h"
#include "Mapper246.h"
#include "Mapper253.h"
+#include "Mapper319.h"
+#include "Mapper375.h"
+#include "Mapper380.h"
+#include "Mapper449.h"
#include "McAcc.h"
#include "MMC1.h"
#include "MMC1_105.h"
@@ -195,7 +199,28 @@
#include "MMC3_249.h"
#include "MMC3_250.h"
#include "MMC3_254.h"
+#include "MMC3_267.h"
+#include "MMC3_334.h"
+#include "MMC3_353.h"
+#include "MMC3_364.h"
+#include "MMC3_370.h"
+#include "MMC3_372.h"
+#include "MMC3_376.h"
+#include "MMC3_377.h"
+#include "MMC3_383.h"
+#include "MMC3_391.h"
+#include "MMC3_393.h"
+#include "MMC3_395.h"
+#include "MMC3_401.h"
+#include "MMC3_410.h"
+#include "MMC3_411.h"
+#include "MMC3_412.h"
#include "MMC3_422.h"
+#include "MMC3_430.h"
+#include "MMC3_432.h"
+#include "MMC3_441.h"
+#include "MMC3_444.h"
+#include "MMC3_445.h"
#include "MMC3_534.h"
#include "MMC3_Bmc411120C.h"
#include "MMC3_BmcF15.h"
@@ -387,6 +412,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 52: return new MMC3_52();
case 53: return new Supervision();
case 54: return new NovelDiamond();
+ case 55: return new Malee();
case 56: return new Kaiser202();
case 57: return new Mapper57();
case 58: return new Mapper58();
@@ -577,7 +603,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 264: return new Yoko();
case 265: return new T262();
case 266: return new CityFighter();
- //267
+ case 267: return new MMC3_267();
case 268:
if(romData.Info.BoardName.compare("MINDKIDS") == 0) {
romData.Info.SubMapperID = 1;
@@ -619,7 +645,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 314: return new Bmc64in1NoRepeat();
case 315: return new Bmc830134C();
//316-318
- case 319: return new Hp898f();
+ case 319: return new Mapper319();
case 320: return new Bmc830425C4391T();
//321
case 322: return new MMC3_BmcK3033();
@@ -633,7 +659,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 331: return new Bmc12in1();
case 332: return new Super40in1Ws();
case 333: return new Bmc8in1(); // + NEWSTAR-GRM070-8IN1
- //334
+ case 334: return new MMC3_334();
case 335: return new BmcCtc09();
case 336: return new BmcK3046();
case 337: return new BmcCtc12in1();
@@ -651,11 +677,39 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 349: return new BmcG146();
case 350: return new Bmc891227();
//352:
+ case 353: return new MMC3_353();
+ case 364: return new MMC3_364();
case 366: return new BmcGn45();
+ case 370: return new MMC3_370();
+ case 372: return new MMC3_372();
+ case 375: return new Mapper375();
+ case 376: return new MMC3_376();
+ case 377: return new MMC3_377();
+ //378-379
+ case 380: return new Mapper380();
+ //381-382
+ case 383: return new MMC3_383();
+ //384-390
+ case 391: return new MMC3_391();
+ case 393: return new MMC3_393();
+ //394
+ case 395: return new MMC3_395();
+ //396-400
+ case 401: return new MMC3_401();
+ case 410: return new MMC3_410();
+ case 411: return new MMC3_411();
+ case 412: return new MMC3_412();
case 422: return new MMC3_422();
+ case 430: return new MMC3_430();
+ case 432: return new MMC3_432();
case 434: return new BmcS2009();
+ case 441: return new MMC3_441();
+ case 444: return new MMC3_444();
+ case 445: return new MMC3_445();
+ case 449: return new Mapper449();
+
case 513: return new Sachen9602();
//514-517
case 518: return new Dance2000();
@@ -676,13 +730,13 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case UnifBoards::Ac08: return new Ac08(); //mapper 42?
case UnifBoards::Cc21: return new Cc21();
case UnifBoards::Ghostbusters63in1: return new Ghostbusters63in1(); //mapper 226?
- case UnifBoards::Malee: return new Malee(); //mapper 42?
case UnifBoards::SssNrom256: return new FamicomBox();
case UnifBoards::Unl255in1: return new Unl255in1();
case UnifBoards::Unl8237A: return new Unl8237A(); //mapper 215.1
case UnifBoards::UnlPuzzle: return new UnlPuzzle();
case UnifBoards::Ks106C: return new UnlKs106C(); //mapper 352, sub 1
case UnifBoards::ResetNromX1n1: return new BmcResetNromX1n1(); //352
+ case UnifBoards::Hp898f: return new Hp898f(); // Mapper 319 with the differentt bank order, specific for UNIF dump of Prima Soft 9999999-in-1
case MapperFactory::StudyBoxMapperID: return new StudyBox();
case MapperFactory::NsfMapperID: return new NsfMapper();
diff --git a/Core/UnifBoards.h b/Core/UnifBoards.h
index 2d1636db7..a750fe3c2 100644
--- a/Core/UnifBoards.h
+++ b/Core/UnifBoards.h
@@ -20,5 +20,6 @@ namespace UnifBoards {
SssNrom256,
Ks106C,
ResetNromX1n1,
+ Hp898f,
};
}
\ No newline at end of file
diff --git a/Core/UnifLoader.cpp b/Core/UnifLoader.cpp
index f0f2ed6aa..787a02f8a 100644
--- a/Core/UnifLoader.cpp
+++ b/Core/UnifLoader.cpp
@@ -73,7 +73,7 @@ std::unordered_map UnifLoader::_boardMappings = std::unordered_map<
{ "LH51", 309 },
{ "LH53", UnifBoards::UnknownBoard },
{ "MALISB", 325 },
- { "MARIO1-MALEE2", UnifBoards::Malee },
+ { "MARIO1-MALEE2", 55 },
{ "MHROM", 66 },
{ "N625092", 221 },
{ "NROM", 0 },
@@ -154,7 +154,7 @@ std::unordered_map UnifLoader::_boardMappings = std::unordered_map<
{ "158B", 258 },
{ "DRAGONFIGHTER", 292 },
{ "EH8813A", 519 },
- { "HP898F", 319 },
+ { "HP898F", UnifBoards::Hp898f },
{ "F-15", 259 },
{ "RT-01", 328 },
{ "81-01-31-C", UnifBoards::UnknownBoard },
@@ -196,4 +196,5 @@ std::unordered_map UnifLoader::_boardMappings = std::unordered_map<
{ "BS-5652", 134 },
{ "891227", 350 },
{ "CTC-12IN1", 337 },
+ { "BS-110", 444 },
};
\ No newline at end of file