1 #pragma once 2 #include "stdafx.h" 3 #include "BaseMapper.h" 4 #include "MemoryManager.h" 5 #include "CPU.h" 6 7 class CityFighter : public BaseMapper 8 { 9 private: 10 uint8_t _prgReg; 11 uint8_t _prgMode; 12 uint8_t _mirroring; 13 uint8_t _chrRegs[8]; 14 bool _irqEnabled; 15 uint16_t _irqCounter; 16 17 protected: GetPRGPageSize()18 uint16_t GetPRGPageSize() override { return 0x2000; } GetCHRPageSize()19 uint16_t GetCHRPageSize() override { return 0x400; } 20 InitMapper()21 void InitMapper() override 22 { 23 _prgReg = 0; 24 _prgMode = 0; 25 _mirroring = 0; 26 _irqCounter = 0; 27 _irqEnabled = false; 28 memset(_chrRegs, 0, sizeof(_chrRegs)); 29 30 UpdateState(); 31 } 32 StreamState(bool saving)33 void StreamState(bool saving) override 34 { 35 BaseMapper::StreamState(saving); 36 ArrayInfo<uint8_t> chrRegs { _chrRegs, 8 }; 37 Stream(_prgReg, _prgMode, _mirroring, _irqEnabled, _irqCounter, chrRegs); 38 } 39 UpdateState()40 void UpdateState() 41 { 42 SelectPrgPage4x(0x8000, _prgReg); 43 if(!_prgMode) { 44 SelectPRGPage(2, _prgReg); 45 } 46 47 for(int i = 0; i < 8; i++) { 48 SelectCHRPage(i, _chrRegs[i]); 49 } 50 51 switch(_mirroring) { 52 case 0: SetMirroringType(MirroringType::Vertical); break; 53 case 1: SetMirroringType(MirroringType::Horizontal); break; 54 case 2: SetMirroringType(MirroringType::ScreenAOnly); break; 55 case 3: SetMirroringType(MirroringType::ScreenBOnly); break; 56 } 57 } 58 ProcessCpuClock()59 void ProcessCpuClock() override 60 { 61 if(_irqEnabled) { 62 _irqCounter--; 63 if(_irqCounter == 0) { 64 _console->GetCpu()->SetIrqSource(IRQSource::External); 65 } 66 } 67 } 68 WriteRegister(uint16_t addr,uint8_t value)69 void WriteRegister(uint16_t addr, uint8_t value) override 70 { 71 switch(addr & 0xF00C) { 72 case 0x9000: 73 _prgReg = value & 0x0C; 74 _mirroring = value & 0x03; 75 break; 76 77 case 0x9004: case 0x9008: case 0x900C: 78 if(addr & 0x800) { 79 _console->GetMemoryManager()->Write(0x4011, (value & 0x0F) << 3, MemoryOperationType::Write); 80 } else { 81 _prgReg = value & 0x0C; 82 } 83 break; 84 85 case 0xC000: case 0xC004: case 0xC008: case 0xC00C: 86 _prgMode = value & 0x01; 87 break; 88 89 case 0xD000: _chrRegs[0] = (_chrRegs[0] & 0xF0) | (value & 0x0F); break; 90 case 0xD004: _chrRegs[0] = (_chrRegs[0] & 0x0F) | (value << 4); break; 91 case 0xD008: _chrRegs[1] = (_chrRegs[1] & 0xF0) | (value & 0x0F); break; 92 case 0xD00C: _chrRegs[1] = (_chrRegs[1] & 0x0F) | (value << 4); break; 93 case 0xA000: _chrRegs[2] = (_chrRegs[2] & 0xF0) | (value & 0x0F); break; 94 case 0xA004: _chrRegs[2] = (_chrRegs[2] & 0x0F) | (value << 4); break; 95 case 0xA008: _chrRegs[3] = (_chrRegs[3] & 0xF0) | (value & 0x0F); break; 96 case 0xA00C: _chrRegs[3] = (_chrRegs[3] & 0x0F) | (value << 4); break; 97 case 0xB000: _chrRegs[4] = (_chrRegs[4] & 0xF0) | (value & 0x0F); break; 98 case 0xB004: _chrRegs[4] = (_chrRegs[4] & 0x0F) | (value << 4); break; 99 case 0xB008: _chrRegs[5] = (_chrRegs[5] & 0xF0) | (value & 0x0F); break; 100 case 0xB00C: _chrRegs[5] = (_chrRegs[5] & 0x0F) | (value << 4); break; 101 case 0xE000: _chrRegs[6] = (_chrRegs[6] & 0xF0) | (value & 0x0F); break; 102 case 0xE004: _chrRegs[6] = (_chrRegs[6] & 0x0F) | (value << 4); break; 103 case 0xE008: _chrRegs[7] = (_chrRegs[7] & 0xF0) | (value & 0x0F); break; 104 case 0xE00C: _chrRegs[7] = (_chrRegs[7] & 0x0F) | (value << 4); break; 105 case 0xF000: _irqCounter = ((_irqCounter & 0x1E0) | ((value & 0x0F) << 1)); break; 106 case 0xF004: _irqCounter = ((_irqCounter & 0x1E) | ((value & 0x0F) << 5)); break; 107 case 0xF008: 108 _irqEnabled = (value & 0x02) != 0; 109 _console->GetCpu()->ClearIrqSource(IRQSource::External); 110 break; 111 } 112 113 UpdateState(); 114 } 115 };