MC-ACC: Update/fix behavior based on recent findings
This commit is contained in:
parent
933fa3e8ba
commit
4ca3442719
5 changed files with 83 additions and 48 deletions
|
@ -554,6 +554,7 @@
|
|||
<ClInclude Include="KeyManager.h" />
|
||||
<ClInclude Include="Lh51.h" />
|
||||
<ClInclude Include="Mapper116.h" />
|
||||
<ClInclude Include="McAcc.h" />
|
||||
<ClInclude Include="MMC3_198.h" />
|
||||
<ClInclude Include="MMC3_208.h" />
|
||||
<ClInclude Include="MMC3_224.h" />
|
||||
|
|
|
@ -1490,6 +1490,9 @@
|
|||
<ClInclude Include="TxcChip.h">
|
||||
<Filter>Nes\Mappers\Txc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="McAcc.h">
|
||||
<Filter>Nes\Mappers\MMC</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
|
65
Core/MMC3.h
65
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;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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();
|
||||
|
|
53
Core/McAcc.h
Normal file
53
Core/McAcc.h
Normal file
|
@ -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;
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue