NES 2.0: Additional submapper support for mappers 1, 2, 3, 7, 32, 34, 71, 78, 232

This commit is contained in:
Souryo 2016-06-03 19:16:31 -04:00
parent 4cb8ae7076
commit 3630395d6e
12 changed files with 74 additions and 46 deletions

View file

@ -14,6 +14,8 @@ class AXROM : public BaseMapper
SelectCHRPage(0, 0);
}
bool HasBusConflicts() { return _subMapperID == 2; }
void WriteRegister(uint16_t addr, uint8_t value)
{
SelectPRGPage(0, value & 0x07);

View file

@ -28,9 +28,15 @@ protected:
if(addr >= 0xC000) {
_prgPage = value & 0x03;
} else if(addr < 0xC000) {
//Some cartridges appear to expect the bits for the block selection to be inverted.
//Different wiring on board?
_prgBlock = (value >> 3) & 0x03;
if(_subMapperID == 1) {
//"232: 1 Aladdin Deck Enhancer"
//"Aladdin Deck Enhancer variation.Swap the bits of the outer bank number."
//But this seems to match the Pegasus 4-in-1 behavior? Wiki wrong?
_prgBlock = ((value >> 4) & 0x01) | ((value >> 2) & 0x02);
} else {
_prgBlock = (value >> 3) & 0x03;
}
}
SelectPRGPage(0, (_prgBlock << 2) | _prgPage);

View file

@ -13,6 +13,10 @@ protected:
void InitMapper()
{
if(_subMapperID == 1) {
_bf9097Mode = true;
}
//First and last PRG page
SelectPRGPage(0, 0);
SelectPRGPage(1, -1);

View file

@ -306,6 +306,9 @@ void BaseMapper::StreamState(bool saving)
void BaseMapper::Initialize(RomData &romData)
{
_mapperID = romData.MapperID;
_subMapperID = romData.SubMapperID;
_romFilename = romData.Filename;
_batteryFilename = GetBatteryFilename();
_saveRamSize = GetSaveRamSize(); //Needed because we need to call SaveBattery() in the destructor (and calling virtual functions in the destructor doesn't work correctly)

View file

@ -67,6 +67,9 @@ private:
vector<uint8_t> _originalPrgRom;
protected:
uint8_t _mapperID;
uint8_t _subMapperID;
uint8_t* _prgRom = nullptr;
uint8_t* _chrRom = nullptr;
uint8_t* _chrRam = nullptr;

View file

@ -16,6 +16,8 @@ protected:
SelectPRGPage(0, 0);
SelectCHRPage(0, 0);
}
bool HasBusConflicts() { return _mapperID == 3 && _subMapperID == 2; }
void WriteRegister(uint16_t addr, uint8_t value)
{

View file

@ -18,6 +18,12 @@ class IremG101 : public BaseMapper
SelectPRGPage(2, -2);
SelectPRGPage(3, -1);
if(_subMapperID == 1) {
//032: 1 Major League
//CIRAM A10 is tied high (fixed one-screen mirroring) and PRG banking style is fixed as 8+8+16F
SetMirroringType(MirroringType::ScreenAOnly);
}
}
virtual void StreamState(bool saving)
@ -51,6 +57,9 @@ class IremG101 : public BaseMapper
break;
case 0x9000:
_prgMode = (value & 0x02) >> 1;
if(_subMapperID == 1) {
_prgMode = 0;
}
UpdatePrgMode();
SetMirroringType((value & 0x01) == 0x01 ? MirroringType::Horizontal : MirroringType::Vertical);
break;

View file

@ -4,9 +4,6 @@
class JalecoJf16 : public BaseMapper
{
private:
bool _isIremHolyDiver;
protected:
virtual uint16_t GetPRGPageSize() { return 0x4000; }
virtual uint16_t GetCHRPageSize() { return 0x2000; }
@ -24,15 +21,11 @@ protected:
{
SelectPRGPage(0, value & 0x07);
SelectCHRPage(0, (value >> 4) & 0x0F);
if(_isIremHolyDiver) {
if(_subMapperID == 3) {
//078: 3 Holy Diver
SetMirroringType(value & 0x08 ? MirroringType::Vertical : MirroringType::Horizontal);
} else {
SetMirroringType(value & 0x08 ? MirroringType::ScreenBOnly : MirroringType::ScreenAOnly);
}
}
public:
JalecoJf16(bool isIremHolyDiver) : _isIremHolyDiver(isIremHolyDiver)
{
}
};

View file

@ -104,21 +104,27 @@ class MMC1 : public BaseMapper
_chrReg1 = _state.RegC000 & 0x1F;
_prgReg = _state.RegE000 & 0x0F;
//This is used for SUROM (Dragon Warrior 3/4, Dragon Quest 4)
uint8_t prgPageAdjust = (_state.RegA000 & 0x10);
if(_subMapperID == 5) {
//SubMapper 5
//"001: 5 Fixed PRG SEROM, SHROM, SH1ROM use a fixed 32k PRG ROM with no banking support.
SelectPrgPage2x(0, 0);
} else {
//This is used for SUROM (Dragon Warrior 3/4, Dragon Quest 4)
uint8_t prgPageAdjust = (_state.RegA000 & 0x10);
if(_prgMode == PrgMode::_32k) {
SelectPRGPage(0, _prgReg + prgPageAdjust);
SelectPRGPage(1, _prgReg + prgPageAdjust + 1);
} else if(_prgMode == PrgMode::_16k) {
if(_slotSelect == SlotSelect::x8000) {
if(_prgMode == PrgMode::_32k) {
SelectPRGPage(0, _prgReg + prgPageAdjust);
SelectPRGPage(1, 0xF + prgPageAdjust);
} else if(_slotSelect == SlotSelect::xC000) {
SelectPRGPage(0, prgPageAdjust);
SelectPRGPage(1, _prgReg + prgPageAdjust);
SelectPRGPage(1, _prgReg + prgPageAdjust + 1);
} else if(_prgMode == PrgMode::_16k) {
if(_slotSelect == SlotSelect::x8000) {
SelectPRGPage(0, _prgReg + prgPageAdjust);
SelectPRGPage(1, 0xF + prgPageAdjust);
} else if(_slotSelect == SlotSelect::xC000) {
SelectPRGPage(0, prgPageAdjust);
SelectPRGPage(1, _prgReg + prgPageAdjust);
}
}
}
}
if(_chrMode == ChrMode::_8k) {
SelectCHRPage(0, _chrReg0 & 0x1E);

View file

@ -21,8 +21,6 @@ class MMC3 : public BaseMapper
RegE001 = 0xE001
};
uint8_t _subMapperID;
uint8_t _currentRegister;
uint8_t _chrMode;
uint8_t _prgMode;
@ -69,6 +67,11 @@ class MMC3 : public BaseMapper
_needIrq = false;
}
bool IsMcAcc()
{
return _mapperID == 4 && _subMapperID == 3;
}
protected:
uint8_t GetCurrentRegister()
{
@ -217,35 +220,25 @@ class MMC3 : public BaseMapper
void TriggerIrq()
{
if(_subMapperID != 3) {
CPU::SetIRQSource(IRQSource::External);
} else {
//MM-ACC (Acclaim copy of the MMC3)
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 {
CPU::SetIRQSource(IRQSource::External);
}
}
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
//Used by MC-ACC (Acclaim copy of the MMC3), see TriggerIrq above
CPU::SetIRQSource(IRQSource::External);
_needIrq = false;
}
@ -269,8 +262,8 @@ class MMC3 : public BaseMapper
_irqCounter--;
}
//SubMapper 2 = MM-ACC (Acclaim MMC3 clone)
if(_subMapperID != 2 && (ForceMmc3RevAIrqs() || EmulationSettings::CheckFlag(EmulationFlags::Mmc3IrqAltBehavior))) {
//SubMapper 2 = MC-ACC (Acclaim MMC3 clone)
if(!IsMcAcc() && (ForceMmc3RevAIrqs() || EmulationSettings::CheckFlag(EmulationFlags::Mmc3IrqAltBehavior))) {
//MMC3 Revision A behavior
if((count > 0 || _irqReload) && _irqCounter == 0 && _irqEnabled) {
TriggerIrq();

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(romData.SubMapperID);
case 4: return new MMC3();
case 5: return new MMC5();
case 7: return new AXROM();
case 9: return new MMC2();
@ -125,7 +125,12 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 27: return new VRC2_4(VRCVariant::VRC4_27); //Untested
case 32: return new IremG101();
case 33: return new TaitoTc0190();
case 34: return (romData.ChrRom.size() > 0) ? (BaseMapper*)new Nina01() : (BaseMapper*)new BnRom(); //BnROM uses CHR RAM (so no CHR rom in the .NES file)
case 34:
switch(romData.SubMapperID) {
case 0: return (romData.ChrRom.size() > 0) ? (BaseMapper*)new Nina01() : (BaseMapper*)new BnRom(); //BnROM uses CHR RAM (so no CHR rom in the .NES file)
case 1: return new Nina01();
case 2: return new BnRom();
}
case 37: return new MMC3_37();
case 38: return new UnlPci556();
case 44: return new MMC3_44();
@ -151,7 +156,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
case 75: return new VRC1();
case 76: return new Namco108_76();
case 77: return new IremLrog017();
case 78: return new JalecoJf16(romData.SubMapperID == 3);
case 78: return new JalecoJf16();
case 79: return new Nina03_06(false);
case 80: return new TaitoX1005(false);
case 82: return new TaitoX1017();

View file

@ -17,6 +17,8 @@ class UNROM : public BaseMapper
SelectCHRPage(0, 0);
}
bool HasBusConflicts() { return _subMapperID == 2; }
void WriteRegister(uint16_t addr, uint8_t value)
{
SelectPRGPage(0, value);