MMC3: Implemented submapper 3 (MM-ACC) - fixes Incredible Crash Dummies

-Also fixed a bug in NES 2.0 mapper ID code
This commit is contained in:
Souryo 2016-06-02 20:35:08 -04:00
parent 4a784ff87a
commit 53f1808f73
4 changed files with 48 additions and 8 deletions

View File

@ -21,6 +21,8 @@ class MMC3 : public BaseMapper
RegE001 = 0xE001
};
uint8_t _subMapperID;
uint8_t _currentRegister;
uint8_t _chrMode;
uint8_t _prgMode;
@ -36,6 +38,8 @@ class MMC3 : public BaseMapper
bool _wramEnabled;
bool _wramWriteProtected;
bool _needIrq;
struct {
uint8_t Reg8000;
uint8_t RegA000;
@ -61,6 +65,8 @@ class MMC3 : public BaseMapper
_wramEnabled = false;
_wramWriteProtected = false;
_needIrq = false;
}
protected:
@ -145,7 +151,7 @@ class MMC3 : public BaseMapper
BaseMapper::StreamState(saving);
Stream(_state.Reg8000, _state.RegA000, _state.RegA001, _currentRegister, _chrMode, _prgMode,
_irqReloadValue, _irqCounter, _irqReload, _irqEnabled, _lastCycle, _cyclesDown,
_wramEnabled, _wramWriteProtected, ArrayInfo<uint8_t>{_registers, 8});
_wramEnabled, _wramWriteProtected, ArrayInfo<uint8_t>{_registers, 8}, _needIrq);
}
virtual uint16_t GetPRGPageSize() { return 0x2000; }
@ -208,12 +214,41 @@ class MMC3 : public BaseMapper
}
}
void TriggerIrq()
{
if(_subMapperID != 3) {
CPU::SetIRQSource(IRQSource::External);
} else {
//MM-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;
}
}
public:
MMC3(uint8_t subMapperID)
{
_subMapperID = subMapperID;
}
MMC3()
{
_subMapperID = 0;
}
virtual void NotifyVRAMAddressChange(uint16_t addr)
{
uint32_t cycle = PPU::GetFrameCycle();
if((addr & 0x1000) == 0) {
if(_needIrq) {
//Used by MM-ACC (Acclaim copy of the MMC3), see TriggerIrq above
CPU::SetIRQSource(IRQSource::External);
_needIrq = false;
}
if(_cyclesDown == 0) {
_cyclesDown = 1;
} else {
@ -233,14 +268,15 @@ class MMC3 : public BaseMapper
_irqCounter--;
}
if(ForceMmc3RevAIrqs() || EmulationSettings::CheckFlag(EmulationFlags::Mmc3IrqAltBehavior)) {
//SubMapper 2 = MM-ACC (Acclaim MMC3 clone)
if(_subMapperID != 2 && (ForceMmc3RevAIrqs() || EmulationSettings::CheckFlag(EmulationFlags::Mmc3IrqAltBehavior))) {
//MMC3 Revision A behavior
if((count > 0 || _irqReload) && _irqCounter == 0 && _irqEnabled) {
CPU::SetIRQSource(IRQSource::External);
TriggerIrq();
}
} else {
if(_irqCounter == 0 && _irqEnabled) {
CPU::SetIRQSource(IRQSource::External);
TriggerIrq();
}
}
_irqReload = false;

View File

@ -104,7 +104,7 @@ 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: return new MMC3(romData.SubMapperID);
case 5: return new MMC5();
case 7: return new AXROM();
case 9: return new MMC2();

View File

@ -644,8 +644,12 @@ void PPU::ProcessPreVBlankScanline()
if((_cycle - 260) % 8 == 0) {
//Cycle 260, 268, etc. This is an approximation (each tile is actually loaded in 8 steps (e.g from 257 to 264))
LoadSpriteTileInfo();
} else if(_cycle == 257) {
_spriteIndex = 0;
} else if((_cycle - 257) % 8 == 0) {
//Garbage NT sprite fetch (257, 265, 273, etc.) - Required for proper MC-ACC IRQs (MMC3 clone)
_memoryManager->ReadVRAM(GetNameTableAddr());
if(_cycle == 257) {
_spriteIndex = 0;
}
}
}
} else if(_cycle == 321 && IsRenderingEnabled()) {

View File

@ -71,7 +71,7 @@ struct NESHeader
{
switch(GetRomHeaderVersion()) {
case RomHeaderVersion::Nes2_0:
return (Byte8 & 0x0F << 4) | (Byte7 & 0xF0) | (Byte6 >> 4);
return ((Byte8 & 0x0F) << 4) | (Byte7 & 0xF0) | (Byte6 >> 4);
default:
case RomHeaderVersion::iNes:
return (Byte7 & 0xF0) | (Byte6 >> 4);