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:
parent
4a784ff87a
commit
53f1808f73
4 changed files with 48 additions and 8 deletions
44
Core/MMC3.h
44
Core/MMC3.h
|
@ -21,6 +21,8 @@ class MMC3 : public BaseMapper
|
||||||
RegE001 = 0xE001
|
RegE001 = 0xE001
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint8_t _subMapperID;
|
||||||
|
|
||||||
uint8_t _currentRegister;
|
uint8_t _currentRegister;
|
||||||
uint8_t _chrMode;
|
uint8_t _chrMode;
|
||||||
uint8_t _prgMode;
|
uint8_t _prgMode;
|
||||||
|
@ -36,6 +38,8 @@ class MMC3 : public BaseMapper
|
||||||
bool _wramEnabled;
|
bool _wramEnabled;
|
||||||
bool _wramWriteProtected;
|
bool _wramWriteProtected;
|
||||||
|
|
||||||
|
bool _needIrq;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t Reg8000;
|
uint8_t Reg8000;
|
||||||
uint8_t RegA000;
|
uint8_t RegA000;
|
||||||
|
@ -61,6 +65,8 @@ class MMC3 : public BaseMapper
|
||||||
|
|
||||||
_wramEnabled = false;
|
_wramEnabled = false;
|
||||||
_wramWriteProtected = false;
|
_wramWriteProtected = false;
|
||||||
|
|
||||||
|
_needIrq = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -145,7 +151,7 @@ class MMC3 : public BaseMapper
|
||||||
BaseMapper::StreamState(saving);
|
BaseMapper::StreamState(saving);
|
||||||
Stream(_state.Reg8000, _state.RegA000, _state.RegA001, _currentRegister, _chrMode, _prgMode,
|
Stream(_state.Reg8000, _state.RegA000, _state.RegA001, _currentRegister, _chrMode, _prgMode,
|
||||||
_irqReloadValue, _irqCounter, _irqReload, _irqEnabled, _lastCycle, _cyclesDown,
|
_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; }
|
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:
|
public:
|
||||||
|
MMC3(uint8_t subMapperID)
|
||||||
|
{
|
||||||
|
_subMapperID = subMapperID;
|
||||||
|
}
|
||||||
|
|
||||||
|
MMC3()
|
||||||
|
{
|
||||||
|
_subMapperID = 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void NotifyVRAMAddressChange(uint16_t addr)
|
virtual void NotifyVRAMAddressChange(uint16_t addr)
|
||||||
{
|
{
|
||||||
uint32_t cycle = PPU::GetFrameCycle();
|
uint32_t cycle = PPU::GetFrameCycle();
|
||||||
|
|
||||||
if((addr & 0x1000) == 0) {
|
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) {
|
if(_cyclesDown == 0) {
|
||||||
_cyclesDown = 1;
|
_cyclesDown = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -233,14 +268,15 @@ class MMC3 : public BaseMapper
|
||||||
_irqCounter--;
|
_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
|
//MMC3 Revision A behavior
|
||||||
if((count > 0 || _irqReload) && _irqCounter == 0 && _irqEnabled) {
|
if((count > 0 || _irqReload) && _irqCounter == 0 && _irqEnabled) {
|
||||||
CPU::SetIRQSource(IRQSource::External);
|
TriggerIrq();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(_irqCounter == 0 && _irqEnabled) {
|
if(_irqCounter == 0 && _irqEnabled) {
|
||||||
CPU::SetIRQSource(IRQSource::External);
|
TriggerIrq();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_irqReload = false;
|
_irqReload = false;
|
||||||
|
|
|
@ -104,7 +104,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
|
||||||
case 1: return new MMC1();
|
case 1: return new MMC1();
|
||||||
case 2: return new UNROM();
|
case 2: return new UNROM();
|
||||||
case 3: return new CNROM(false);
|
case 3: return new CNROM(false);
|
||||||
case 4: return new MMC3();
|
case 4: return new MMC3(romData.SubMapperID);
|
||||||
case 5: return new MMC5();
|
case 5: return new MMC5();
|
||||||
case 7: return new AXROM();
|
case 7: return new AXROM();
|
||||||
case 9: return new MMC2();
|
case 9: return new MMC2();
|
||||||
|
|
|
@ -644,10 +644,14 @@ void PPU::ProcessPreVBlankScanline()
|
||||||
if((_cycle - 260) % 8 == 0) {
|
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))
|
//Cycle 260, 268, etc. This is an approximation (each tile is actually loaded in 8 steps (e.g from 257 to 264))
|
||||||
LoadSpriteTileInfo();
|
LoadSpriteTileInfo();
|
||||||
} else if(_cycle == 257) {
|
} 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;
|
_spriteIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if(_cycle == 321 && IsRenderingEnabled()) {
|
} else if(_cycle == 321 && IsRenderingEnabled()) {
|
||||||
_oamCopybuffer = _secondarySpriteRAM[0];
|
_oamCopybuffer = _secondarySpriteRAM[0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ struct NESHeader
|
||||||
{
|
{
|
||||||
switch(GetRomHeaderVersion()) {
|
switch(GetRomHeaderVersion()) {
|
||||||
case RomHeaderVersion::Nes2_0:
|
case RomHeaderVersion::Nes2_0:
|
||||||
return (Byte8 & 0x0F << 4) | (Byte7 & 0xF0) | (Byte6 >> 4);
|
return ((Byte8 & 0x0F) << 4) | (Byte7 & 0xF0) | (Byte6 >> 4);
|
||||||
default:
|
default:
|
||||||
case RomHeaderVersion::iNes:
|
case RomHeaderVersion::iNes:
|
||||||
return (Byte7 & 0xF0) | (Byte6 >> 4);
|
return (Byte7 & 0xF0) | (Byte6 >> 4);
|
||||||
|
|
Loading…
Add table
Reference in a new issue