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