diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 366ae5b7..446e2de3 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -554,6 +554,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index d5c2da20..c5dcf53a 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1490,6 +1490,9 @@ Nes\Mappers\Txc + + Nes\Mappers\MMC + diff --git a/Core/MMC3.h b/Core/MMC3.h index 42566e45..ac4e9a9d 100644 --- a/Core/MMC3.h +++ b/Core/MMC3.h @@ -27,7 +27,6 @@ class MMC3 : public BaseMapper bool _wramWriteProtected; A12Watcher _a12Watcher; - bool _needIrq; bool _forceMmc3RevAIrqs; @@ -37,11 +36,6 @@ class MMC3 : public BaseMapper uint8_t RegA001; } _state; - bool IsMcAcc() - { - return _romInfo.MapperID == 4 && _romInfo.SubMapperID == 3; - } - protected: uint8_t _irqReloadValue; uint8_t _irqCounter; @@ -93,8 +87,6 @@ class MMC3 : public BaseMapper _wramEnabled = GetPowerOnByte() & 0x01; _wramWriteProtected = GetPowerOnByte() & 0x01; - - _needIrq = false; } virtual bool ForceMmc3RevAIrqs() { return _forceMmc3RevAIrqs; } @@ -192,7 +184,7 @@ class MMC3 : public BaseMapper SnapshotInfo a12Watcher{ &_a12Watcher }; Stream(_state.Reg8000, _state.RegA000, _state.RegA001, _currentRegister, _chrMode, _prgMode, _irqReloadValue, _irqCounter, _irqReload, _irqEnabled, a12Watcher, - _wramEnabled, _wramWriteProtected, registers, _needIrq); + _wramEnabled, _wramWriteProtected, registers); } virtual uint16_t GetPRGPageSize() override { return 0x2000; } @@ -261,52 +253,31 @@ class MMC3 : public BaseMapper virtual void TriggerIrq() { - if(IsMcAcc()) { - //MC-ACC (Acclaim copy of the MMC3) - //IRQ will be triggered on the next falling edge of A12 instead of on the rising edge like normal MMC3 behavior - //This adds a 4 ppu cycle delay (until the PPU fetches the next garbage NT tile between sprites) - _needIrq = true; - } else { - _console->GetCpu()->SetIrqSource(IRQSource::External); - } + _console->GetCpu()->SetIrqSource(IRQSource::External); } - public: virtual void NotifyVRAMAddressChange(uint16_t addr) override { - switch(_a12Watcher.UpdateVramAddress(addr, _console->GetPpu()->GetFrameCycle())) { - case A12StateChange::None: - break; + if(_a12Watcher.UpdateVramAddress(addr, _console->GetPpu()->GetFrameCycle()) == A12StateChange::Rise) { + uint32_t count = _irqCounter; + if(_irqCounter == 0 || _irqReload) { + _irqCounter = _irqReloadValue; + } else { + _irqCounter--; + } - case A12StateChange::Fall: - if(_needIrq) { - //Used by MC-ACC (Acclaim copy of the MMC3), see TriggerIrq above - _console->GetCpu()->SetIrqSource(IRQSource::External); - _needIrq = false; + if(ForceMmc3RevAIrqs() || _console->GetSettings()->CheckFlag(EmulationFlags::Mmc3IrqAltBehavior)) { + //MMC3 Revision A behavior + if((count > 0 || _irqReload) && _irqCounter == 0 && _irqEnabled) { + TriggerIrq(); } - break; - case A12StateChange::Rise: - uint32_t count = _irqCounter; - if(_irqCounter == 0 || _irqReload) { - _irqCounter = _irqReloadValue; - } else { - _irqCounter--; + } else { + if(_irqCounter == 0 && _irqEnabled) { + TriggerIrq(); } - - //SubMapper 2 = MC-ACC (Acclaim MMC3 clone) - if(!IsMcAcc() && (ForceMmc3RevAIrqs() || _console->GetSettings()->CheckFlag(EmulationFlags::Mmc3IrqAltBehavior))) { - //MMC3 Revision A behavior - if((count > 0 || _irqReload) && _irqCounter == 0 && _irqEnabled) { - TriggerIrq(); - } - } else { - if(_irqCounter == 0 && _irqEnabled) { - TriggerIrq(); - } - } - _irqReload = false; - break; + } + _irqReload = false; } } }; \ No newline at end of file diff --git a/Core/MapperFactory.cpp b/Core/MapperFactory.cpp index 72e9fcbe..08dacf08 100644 --- a/Core/MapperFactory.cpp +++ b/Core/MapperFactory.cpp @@ -145,6 +145,7 @@ #include "Mapper244.h" #include "Mapper246.h" #include "Mapper253.h" +#include "McAcc.h" #include "MMC1.h" #include "MMC1_105.h" #include "MMC1_155.h" @@ -306,7 +307,13 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData) case 1: return new MMC1(); case 2: return new UNROM(); case 3: return new CNROM(false); - case 4: return new MMC3(); + case 4: + if(romData.Info.SubMapperID == 3) { + return new McAcc(); + } else { + return new MMC3(); + } + case 5: return new MMC5(); case 6: return new FrontFareast(); case 7: return new AXROM(); diff --git a/Core/McAcc.h b/Core/McAcc.h new file mode 100644 index 00000000..5b0b6067 --- /dev/null +++ b/Core/McAcc.h @@ -0,0 +1,53 @@ +#pragma once + +#include "stdafx.h" +#include "MMC3.h" + +//Based on krikzz's research: https://forums.nesdev.com/viewtopic.php?p=242427#p242427 +class McAcc : public MMC3 +{ +private: + uint32_t _counter = 0; + uint16_t _prevAddr = 0; + +protected: + void StreamState(bool saving) override + { + MMC3::StreamState(saving); + Stream(_counter, _prevAddr); + } + + void WriteRegister(uint16_t addr, uint8_t value) override + { + if((addr & 0xE001) == 0xC001) { + //"Writing to $C001 resets pulse counter." + _counter = 0; + } + MMC3::WriteRegister(addr, value); + } + + void NotifyVRAMAddressChange(uint16_t addr) override + { + if(!(addr & 0x1000) && (_prevAddr & 0x1000)) { + _counter++; + + if(_counter == 1) { + //"Counter clocking happens once per 8 A12 cycles at first cycle" + if(_irqCounter == 0 || _irqReload) { + _irqCounter = _irqReloadValue; + } else { + _irqCounter--; + } + + if(_irqCounter == 0 && _irqEnabled) { + _console->GetCpu()->SetIrqSource(IRQSource::External); + } + + _irqReload = false; + } else if(_counter == 8) { + _counter = 0; + } + } + _prevAddr = addr; + } +}; \ No newline at end of file