diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 3524739b..8e7a0ba0 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -25,6 +25,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 7cf8063e..115894ba 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -2973,6 +2973,9 @@
SNES\Coprocessors\SufamiTurbo
+
+ NES\Mappers\Unlicensed
+
diff --git a/Core/NES/MapperFactory.cpp b/Core/NES/MapperFactory.cpp
index 9ddfb6c2..1545daf6 100644
--- a/Core/NES/MapperFactory.cpp
+++ b/Core/NES/MapperFactory.cpp
@@ -243,6 +243,7 @@
#include "NES/Mappers/Unlicensed/Mapper60.h"
#include "NES/Mappers/Unlicensed/Mapper62.h"
#include "NES/Mappers/Unlicensed/Mapper83.h"
+#include "NES/Mappers/Unlicensed/Mapper487.h"
#include "NES/Mappers/Unlicensed/Nanjing.h"
#include "NES/Mappers/Unlicensed/Nina01.h"
#include "NES/Mappers/Unlicensed/Nina03_06.h"
@@ -601,6 +602,8 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 366: return new BmcGn45();
+ case 487: return new Mapper487();
+
case 513: return new Sachen9602();
//514-517
case 518: return new Dance2000();
diff --git a/Core/NES/Mappers/Unlicensed/Mapper234.h b/Core/NES/Mappers/Unlicensed/Mapper234.h
index 0e35c4d9..e2b80a25 100644
--- a/Core/NES/Mappers/Unlicensed/Mapper234.h
+++ b/Core/NES/Mappers/Unlicensed/Mapper234.h
@@ -22,6 +22,12 @@ protected:
UpdateState();
}
+ void Serialize(Serializer& s) override
+ {
+ BaseMapper::Serialize(s);
+ SVArray(_regs, 2);
+ }
+
void UpdateState()
{
if(_regs[0] & 0x40) {
@@ -63,6 +69,6 @@ protected:
} else {
_regs[1] = value & 0x71;
UpdateState();
- }
+ }
}
};
\ No newline at end of file
diff --git a/Core/NES/Mappers/Unlicensed/Mapper487.h b/Core/NES/Mappers/Unlicensed/Mapper487.h
new file mode 100644
index 00000000..a5a5c0a9
--- /dev/null
+++ b/Core/NES/Mappers/Unlicensed/Mapper487.h
@@ -0,0 +1,83 @@
+#pragma once
+#include "pch.h"
+#include "NES/BaseMapper.h"
+
+class Mapper487 : public BaseMapper
+{
+private:
+ uint8_t _regs[2] = {};
+
+protected:
+ uint16_t RegisterStartAddress() override { return 0x4100; }
+ uint16_t RegisterEndAddress() override { return 0x5FFF; }
+ uint16_t GetPrgPageSize() override { return 0x8000; }
+ uint16_t GetChrPageSize() override { return 0x2000; }
+
+ void InitMapper() override
+ {
+ AddRegisterRange(0x8000, 0xFFFF, MemoryOperation::Write);
+ UpdateState();
+ }
+
+ void Reset(bool softReset) override
+ {
+ _regs[0] = 0;
+ _regs[1] = 0;
+ UpdateState();
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseMapper::Serialize(s);
+ SVArray(_regs, 2);
+ }
+
+ void UpdateState()
+ {
+ uint8_t prg = _regs[1] & 0x1E;
+ uint8_t chr = (
+ ((_regs[1] & 0x1E) << 2) |
+ (_regs[0] & 0x03)
+ );
+
+ if(_regs[1] & 0x40) {
+ //64kb banks, use inner bank for A15
+ prg |= (_regs[0] & 0x08) >> 3;
+ chr |= _regs[0] & 0x04;
+ } else {
+ //32kb banks, use outer bank LSB as A15
+ prg |= _regs[1] & 0x01;
+ chr |= (_regs[1] & 0x01) << 2;
+ }
+
+ if(_regs[1] & 0x20) {
+ //Skip first 512kb of PRG/CHR when using 2nd set of prg/chr roms
+ prg += 0x10;
+ chr += 0x40;
+ }
+
+ SelectPrgPage(0, prg);
+ SelectChrPage(0, chr);
+
+ SetMirroringType(_regs[1] & 0x80 ? MirroringType::Horizontal : MirroringType::Vertical);
+ }
+
+ void WriteRegister(uint16_t addr, uint8_t value) override
+ {
+ if(addr < 0x6000) {
+ if(addr & 0x100) {
+ if(addr & 0x80) {
+ _regs[1] = value;
+ } else if(!(_regs[1] & 0x20)) {
+ //NINA03-style register
+ _regs[0] = value & 0x0F;
+ }
+ UpdateState();
+ }
+ } else if(_regs[1] & 0x20) {
+ //Color dreams-style register
+ _regs[0] = ((value & 0x01) << 3) | ((value & 0x70) >> 4);
+ UpdateState();
+ }
+ }
+};