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(); + } + } +};