From 4a315e4144fb0ce28f56ff7dd56b4610daefb138 Mon Sep 17 00:00:00 2001 From: Souryo Date: Wed, 15 Jun 2016 22:01:15 -0400 Subject: [PATCH] VRC2/4: Implemented submapper support + fixed a bug with address decoding (no mask applied) + fixed a bug with VRC2a/b mirroring --- Core/MapperFactory.cpp | 10 +- Core/VRC2_4.h | 205 ++++++++++++++++++++++++++++++----------- 2 files changed, 154 insertions(+), 61 deletions(-) diff --git a/Core/MapperFactory.cpp b/Core/MapperFactory.cpp index b6d1d3b2..e27091b4 100644 --- a/Core/MapperFactory.cpp +++ b/Core/MapperFactory.cpp @@ -123,13 +123,13 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData) case 17: return new FrontFareast(); case 18: return new JalecoSs88006(); case 19: return new Namco163(); - case 21: return new VRC2_4(VRCVariant::VRC4a); //Conflicts: VRC4c - case 22: return new VRC2_4(VRCVariant::VRC2a); - case 23: return new VRC2_4(VRCVariant::VRC2b); //Conflicts: VRC4e + case 21: return new VRC2_4(); + case 22: return new VRC2_4(); + case 23: return new VRC2_4(); case 24: return new VRC6(VRCVariant::VRC6a); - case 25: return new VRC2_4(VRCVariant::VRC4b); //Conflicts: VRC2c, VRC4d + case 25: return new VRC2_4(); case 26: return new VRC6(VRCVariant::VRC6b); - case 27: return new VRC2_4(VRCVariant::VRC4_27); //Untested + case 27: return new VRC2_4(); case 32: return new IremG101(); case 33: return new TaitoTc0190(); case 34: diff --git a/Core/VRC2_4.h b/Core/VRC2_4.h index 3186ba99..19efe676 100644 --- a/Core/VRC2_4.h +++ b/Core/VRC2_4.h @@ -23,6 +23,7 @@ class VRC2_4 : public BaseMapper private: VrcIrq _irq; VRCVariant _variant; + bool _useHeuristics; uint8_t _prgReg0; uint8_t _prgReg1; @@ -33,12 +34,57 @@ class VRC2_4 : public BaseMapper bool _hasIRQ; + void DetectVariant() + { + switch(_mapperID) { + default: + case 21: + //Conflicts: VRC4c + switch(_subMapperID) { + default: + case 0: _variant = VRCVariant::VRC4a; break; + case 1: _variant = VRCVariant::VRC4a; break; + case 2: _variant = VRCVariant::VRC4c; break; + } + break; + + case 22: _variant = VRCVariant::VRC2a; break; + + case 23: + //Conflicts: VRC4e + switch(_subMapperID) { + default: + case 0: _variant = VRCVariant::VRC2b; break; + case 2: _variant = VRCVariant::VRC4e; break; + case 3: _variant = VRCVariant::VRC2b; break; + } + break; + + case 25: + //Conflicts: VRC2c, VRC4d + switch(_subMapperID) { + default: + case 0: _variant = VRCVariant::VRC4b; break; + case 1: _variant = VRCVariant::VRC4b; break; + case 2: _variant = VRCVariant::VRC4d; break; + case 3: _variant = VRCVariant::VRC2c; break; + } + break; + + case 27: _variant = VRCVariant::VRC4_27; break; //Untested + } + + _useHeuristics = (_subMapperID == 0) && _mapperID != 22 && _mapperID != 27; + } + protected: virtual uint16_t GetPRGPageSize() { return 0x2000; } virtual uint16_t GetCHRPageSize() { return 0x0400; } void InitMapper() { + DetectVariant(); + _prgMode = 0; _prgReg0 = 0; _prgReg1 = 0; @@ -80,11 +126,17 @@ class VRC2_4 : public BaseMapper void WriteRegister(uint16_t addr, uint8_t value) { - addr = TranslateAddress(addr); + addr = TranslateAddress(addr) & 0xF00F; + if(addr >= 0x8000 && addr <= 0x8006) { _prgReg0 = value & 0x1F; } else if(addr == 0x9000 || addr == 0x9002) { - switch(value & 0x03) { + uint8_t mask = 0x03; + if(_variant == VRCVariant::VRC2a || _variant == VRCVariant::VRC2b) { + mask = 0x01; + } + + switch(value & mask) { case 0: SetMirroringType(MirroringType::Vertical); break; case 1: SetMirroringType(MirroringType::Horizontal); break; case 2: SetMirroringType(MirroringType::ScreenAOnly); break; @@ -120,67 +172,108 @@ class VRC2_4 : public BaseMapper } public: - VRC2_4(VRCVariant variant) - { - _variant = variant; - } - uint16_t TranslateAddress(uint16_t addr) { - uint32_t A0 = addr & 0x01; - uint32_t A1 = (addr >> 1) & 0x01; + uint32_t A0, A1; - switch(_variant) { - case VRCVariant::VRC2a: - //Mapper 22 - A0 = (addr >> 1) & 0x01; - A1 = (addr & 0x01); - break; + if(_useHeuristics) { + switch(_variant) { + case VRCVariant::VRC2c: + case VRCVariant::VRC4b: + case VRCVariant::VRC4d: + //Mapper 25 + //ORing both values should make most games work. + //VRC2c & VRC4b (Both uses the same bits) + A0 = (addr >> 1) & 0x01; + A1 = (addr & 0x01); - case VRCVariant::VRC4_27: - A0 = addr & 0x01; - A1 = (addr >> 1) & 0x01; - break; + //VRC4d + A0 |= (addr >> 3) & 0x01; + A1 |= (addr >> 2) & 0x01; + break; + case VRCVariant::VRC4a: + case VRCVariant::VRC4c: + //Mapper 21 + //VRC4a + A0 = (addr >> 1) & 0x01; + A1 = (addr >> 2) & 0x01; - case VRCVariant::VRC2c: - case VRCVariant::VRC4b: - case VRCVariant::VRC4d: - //Mapper 25 - //ORing both values should make most games work. - //VRC2c & VRC4b (Both uses the same bits) - A0 = (addr >> 1) & 0x01; - A1 = (addr & 0x01); - - //VRC4d - A0 |= (addr >> 3) & 0x01; - A1 |= (addr >> 2) & 0x01; - break; - case VRCVariant::VRC4a: - case VRCVariant::VRC4c: - //Mapper 21 - //VRC4a - A0 = (addr >> 1) & 0x01; - A1 = (addr >> 2) & 0x01; + //VRC4c + A0 |= (addr >> 6) & 0x01; + A1 |= (addr >> 7) & 0x01; + break; - //VRC4c - A0 |= (addr >> 6) & 0x01; - A1 |= (addr >> 7) & 0x01; - break; - - case VRCVariant::VRC2b: - case VRCVariant::VRC4e: - //Mapper 23 - //VRC2b - A0 = addr & 0x01; - A1 = (addr >> 1) & 0x01; + case VRCVariant::VRC2b: + case VRCVariant::VRC4e: + //Mapper 23 + //VRC2b + A0 = addr & 0x01; + A1 = (addr >> 1) & 0x01; + + //VRC4e + A0 |= (addr >> 2) & 0x01; + A1 |= (addr >> 3) & 0x01; + break; + default: + throw std::runtime_error("not supported"); + break; + } + } else { + switch(_variant) { + case VRCVariant::VRC2a: + //Mapper 22 + A0 = (addr >> 1) & 0x01; + A1 = (addr & 0x01); + break; + + case VRCVariant::VRC4_27: + //Mapper 27 + A0 = addr & 0x01; + A1 = (addr >> 1) & 0x01; + break; + + case VRCVariant::VRC2c: + case VRCVariant::VRC4b: + //Mapper 25 + A0 = (addr >> 1) & 0x01; + A1 = (addr & 0x01); + break; + + case VRCVariant::VRC4d: + //Mapper 25 + A0 = (addr >> 3) & 0x01; + A1 = (addr >> 2) & 0x01; + break; + + case VRCVariant::VRC4a: + //Mapper 21 + A0 = (addr >> 1) & 0x01; + A1 = (addr >> 2) & 0x01; + break; + + case VRCVariant::VRC4c: + //Mapper 21 + A0 = (addr >> 6) & 0x01; + A1 = (addr >> 7) & 0x01; + break; + + case VRCVariant::VRC2b: + //Mapper 23 + A0 = addr & 0x01; + A1 = (addr >> 1) & 0x01; + break; + + case VRCVariant::VRC4e: + //Mapper 23 + A0 = (addr >> 2) & 0x01; + A1 = (addr >> 3) & 0x01; + break; + + default: + throw std::runtime_error("not supported"); + break; + } - //VRC4e - A0 |= (addr >> 2) & 0x01; - A1 |= (addr >> 3) & 0x01; - break; - default: - throw std::runtime_error("not supported"); - break; } return (addr & 0xFF00) | (A1 << 1) | A0;