mirror of
https://github.com/SourMesen/Mesen.git
synced 2025-04-02 10:52:48 -04:00
NES 2.0: Additional submapper support for mappers 1, 2, 3, 7, 32, 34, 71, 78, 232
This commit is contained in:
parent
4cb8ae7076
commit
3630395d6e
12 changed files with 74 additions and 46 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -13,6 +13,10 @@ protected:
|
|||
|
||||
void InitMapper()
|
||||
{
|
||||
if(_subMapperID == 1) {
|
||||
_bf9097Mode = true;
|
||||
}
|
||||
|
||||
//First and last PRG page
|
||||
SelectPRGPage(0, 0);
|
||||
SelectPRGPage(1, -1);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
};
|
30
Core/MMC1.h
30
Core/MMC1.h
|
@ -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);
|
||||
|
|
31
Core/MMC3.h
31
Core/MMC3.h
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue