diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 0aec08bd..313758b9 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -489,6 +489,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index bc208c8f..ebdd126f 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -437,6 +437,9 @@ Nes\Mappers + + Nes\Mappers + diff --git a/Core/MapperFactory.cpp b/Core/MapperFactory.cpp index 5fb3661e..cef632e8 100644 --- a/Core/MapperFactory.cpp +++ b/Core/MapperFactory.cpp @@ -72,6 +72,7 @@ #include "UnRom_180.h" #include "VRC1.h" #include "VRC2_4.h" +#include "VRC3.h" BaseMapper* MapperFactory::GetMapperFromID(ROMLoader &romLoader) { @@ -118,6 +119,7 @@ BaseMapper* MapperFactory::GetMapperFromID(ROMLoader &romLoader) case 70: return new Bandai74161_7432(false); case 71: return new BF909x(); case 72: return new JalecoJf17_19(false); + case 73: return new VRC3(); case 74: return new MMC3_ChrRam(0x08, 0x09, 2); case 75: return new VRC1(); case 76: return new Namco108_76(); diff --git a/Core/VRC3.h b/Core/VRC3.h new file mode 100644 index 00000000..977d7f97 --- /dev/null +++ b/Core/VRC3.h @@ -0,0 +1,80 @@ +#pragma once +#include "stdafx.h" +#include "BaseMapper.h" +#include "CPU.h" + +class VRC3 : public BaseMapper +{ +private: + bool _irqEnableOnAck = false; + bool _irqEnabled = false; + bool _smallCounter = false; + uint16_t _irqReload = 0; + uint16_t _irqCounter = 0; + +protected: + virtual uint16_t GetPRGPageSize() { return 0x4000; } + virtual uint16_t GetCHRPageSize() { return 0x2000; } + + void InitMapper() + { + SelectPRGPage(1, -1); + SelectCHRPage(0, 0); + } + + virtual void StreamState(bool saving) + { + BaseMapper::StreamState(saving); + Stream(_irqEnableOnAck); + Stream(_smallCounter); + Stream(_irqEnabled); + Stream(_irqCounter); + Stream(_irqReload); + } + + virtual void ProcessCpuClock() + { + if(_irqEnabled) { + if(_smallCounter) { + uint8_t smallCounter = _irqCounter & 0xFF; + smallCounter++; + if(_smallCounter == 0) { + smallCounter = _irqReload & 0xFF; + CPU::SetIRQSource(IRQSource::External); + } + _irqCounter = (_irqCounter & 0xFF00) | smallCounter; + } else { + _irqCounter++; + if(_irqCounter == 0) { + _irqCounter = _irqReload; + CPU::SetIRQSource(IRQSource::External); + } + } + } + } + + void WriteRegister(uint16_t addr, uint8_t value) + { + switch(addr & 0xF000) { + case 0x8000: _irqReload = (_irqReload & 0xFFF0) | (value & 0x0F); break; + case 0x9000: _irqReload = (_irqReload & 0xFF0F) | ((value & 0x0F) << 4); break; + case 0xA000: _irqReload = (_irqReload & 0xF0FF) | ((value & 0x0F) << 8); break; + case 0xB000: _irqReload = (_irqReload & 0x0FFF) | ((value & 0x0F) << 12); break; + case 0xC000: + _irqEnabled = (value & 0x02) == 0x02; + if(_irqEnabled) { + _irqCounter = _irqReload; + } + _smallCounter = (value & 0x04) == 0x04; + _irqEnableOnAck = (value & 0x01) == 0x01; + CPU::ClearIRQSource(IRQSource::External); + break; + case 0xD000: + CPU::ClearIRQSource(IRQSource::External); + _irqEnabled = _irqEnableOnAck; + break; + case 0xF000: SelectPRGPage(0, value & 0x07); break; + } + } +}; +#pragma once