1 #pragma once 2 #include "stdafx.h" 3 #include "MMC3.h" 4 5 class BmcHpxx : public MMC3 6 { 7 private: 8 uint8_t _exRegs[5]; 9 bool _locked; 10 11 protected: GetDipSwitchCount()12 uint32_t GetDipSwitchCount() override { return 4; } AllowRegisterRead()13 bool AllowRegisterRead() override { return true; } 14 InitMapper()15 void InitMapper() override 16 { 17 memset(_exRegs, 0, sizeof(_exRegs)); 18 _locked = false; 19 20 MMC3::InitMapper(); 21 AddRegisterRange(0x5000, 0x5FFF, MemoryOperation::Any); 22 RemoveRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read); 23 } 24 Reset(bool softReset)25 void Reset(bool softReset) override 26 { 27 MMC3::Reset(softReset); 28 memset(_exRegs, 0, sizeof(_exRegs)); 29 _locked = false; 30 MMC3::ResetMmc3(); 31 UpdateState(); 32 } 33 StreamState(bool saving)34 void StreamState(bool saving) override 35 { 36 MMC3::StreamState(saving); 37 Stream(_exRegs[0], _exRegs[1], _exRegs[2], _exRegs[3], _exRegs[4], _locked); 38 } 39 40 void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default) override 41 { 42 if(_exRegs[0] & 0x04) { 43 switch(_exRegs[0] & 0x03) { 44 case 0: 45 case 1: SelectChrPage8x(0, (_exRegs[2] & 0x3F) << 3); break; 46 case 2: SelectChrPage8x(0, ((_exRegs[2] & 0x3E) | (_exRegs[4] & 0x01)) << 3); break; 47 case 3: SelectChrPage8x(0, ((_exRegs[2] & 0x3C) | (_exRegs[4] & 0x03)) << 3); break; 48 } 49 } else { 50 uint8_t base, mask; 51 if(_exRegs[0] & 0x01) { 52 base = _exRegs[2] & 0x30; 53 mask = 0x7F; 54 } else { 55 base = _exRegs[2] & 0x20; 56 mask = 0xFF; 57 } 58 MMC3::SelectCHRPage(slot, (page & mask) | (base << 3)); 59 } 60 } 61 62 void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom) override 63 { 64 if(_exRegs[0] & 0x04) { 65 if((_exRegs[0] & 0x0F) == 0x04) { 66 SelectPrgPage2x(0, (_exRegs[1] & 0x1F) << 1); 67 SelectPrgPage2x(1, (_exRegs[1] & 0x1F) << 1); 68 } else { 69 SelectPrgPage4x(0, (_exRegs[1] & 0x1E) << 1); 70 } 71 } else { 72 uint8_t base, mask; 73 if(_exRegs[0] & 0x02) { 74 base = _exRegs[1] & 0x18; 75 mask = 0x0F; 76 } else { 77 base = _exRegs[1] & 0x10; 78 mask = 0x1F; 79 } 80 MMC3::SelectPRGPage(slot, (page & mask) | (base << 1)); 81 } 82 } 83 UpdateMirroring()84 void UpdateMirroring() override 85 { 86 if(_exRegs[0] & 0x04) { 87 SetMirroringType(_exRegs[4] & 0x04 ? MirroringType::Vertical : MirroringType::Horizontal); 88 } else { 89 MMC3::UpdateMirroring(); 90 } 91 } 92 ReadRegister(uint16_t addr)93 uint8_t ReadRegister(uint16_t addr) override 94 { 95 return GetDipSwitches(); 96 } 97 WriteRegister(uint16_t addr,uint8_t value)98 void WriteRegister(uint16_t addr, uint8_t value) override 99 { 100 if(addr < 0x8000) { 101 if(!_locked) { 102 _exRegs[addr & 0x03] = value; 103 _locked = (value & 0x80) != 0; 104 UpdatePrgMapping(); 105 UpdateChrMapping(); 106 } 107 } else { 108 if(_exRegs[0] & 0x04) { 109 _exRegs[4] = value; 110 UpdateChrMapping(); 111 } else { 112 MMC3::WriteRegister(addr, value); 113 } 114 } 115 } 116 };