1 #pragma once 2 #include "stdafx.h" 3 #include "BaseMapper.h" 4 5 class Mapper253 : public BaseMapper 6 { 7 private: 8 uint8_t _chrLow[8]; 9 uint8_t _chrHigh[8]; 10 bool _forceChrRom; 11 uint8_t _irqReloadValue; 12 uint8_t _irqCounter; 13 bool _irqEnabled; 14 uint16_t _irqScaler; 15 16 protected: GetPRGPageSize()17 virtual uint16_t GetPRGPageSize() override { return 0x2000; } GetCHRPageSize()18 virtual uint16_t GetCHRPageSize() override { return 0x400; } GetChrRamSize()19 virtual uint32_t GetChrRamSize() override { return 0x800; } GetChrRamPageSize()20 virtual uint16_t GetChrRamPageSize() override { return 0x400; } 21 InitMapper()22 void InitMapper() override 23 { 24 memset(_chrLow, 0, sizeof(_chrLow)); 25 memset(_chrHigh, 0, sizeof(_chrHigh)); 26 _forceChrRom = false; 27 _irqReloadValue = 0; 28 _irqScaler = 0; 29 _irqCounter = 0; 30 _irqEnabled = false; 31 32 SelectPRGPage(2, -2); 33 SelectPRGPage(3, -1); 34 } 35 StreamState(bool saving)36 void StreamState(bool saving) override 37 { 38 BaseMapper::StreamState(saving); 39 40 ArrayInfo<uint8_t> chrLow{ _chrLow, 8 }; 41 ArrayInfo<uint8_t> chrHigh{ _chrHigh, 8 }; 42 Stream(_forceChrRom, _irqReloadValue, _irqCounter, _irqEnabled, _irqScaler, chrLow, chrHigh); 43 44 if(!saving) { 45 UpdateChr(); 46 } 47 } 48 UpdateChr()49 void UpdateChr() 50 { 51 for(uint16_t i = 0; i < 8; i++) { 52 uint16_t page = _chrLow[i] | (_chrHigh[i] << 8); 53 if((_chrLow[i] == 4 || _chrLow[i] == 5) && !_forceChrRom) { 54 SelectCHRPage(i, page & 0x01, ChrMemoryType::ChrRam); 55 } else { 56 SelectCHRPage(i, page); 57 } 58 } 59 } 60 ProcessCpuClock()61 void ProcessCpuClock() override 62 { 63 if(_irqEnabled) { 64 _irqScaler++; 65 if(_irqScaler >= 114) { 66 _irqScaler = 0; 67 _irqCounter++; 68 if(_irqCounter == 0) { 69 _irqCounter = _irqReloadValue; 70 _console->GetCpu()->SetIrqSource(IRQSource::External); 71 } 72 } 73 } 74 } 75 WriteRegister(uint16_t addr,uint8_t value)76 void WriteRegister(uint16_t addr, uint8_t value) override 77 { 78 if(addr >= 0xB000 && addr <= 0xE00C) { 79 uint8_t slot = ((((addr & 0x08) | (addr >> 8)) >> 3) + 2) & 0x07; 80 uint8_t shift = addr & 0x04; 81 uint8_t chrLow = (_chrLow[slot] & (0xF0 >> shift)) | (value << shift); 82 _chrLow[slot] = chrLow; 83 if(slot == 0) { 84 if(chrLow == 0xc8) { 85 _forceChrRom = false; 86 } else if(chrLow == 0x88) { 87 _forceChrRom = true; 88 } 89 } 90 if(shift) { 91 _chrHigh[slot] = value >> 4; 92 } 93 UpdateChr(); 94 } else { 95 switch(addr) { 96 case 0x8010: SelectPRGPage(0, value); break; 97 case 0xA010: SelectPRGPage(1, value); break; 98 case 0x9400: 99 switch(value & 0x03) { 100 case 0: SetMirroringType(MirroringType::Vertical); break; 101 case 1: SetMirroringType(MirroringType::Horizontal); break; 102 case 2: SetMirroringType(MirroringType::ScreenAOnly); break; 103 case 3: SetMirroringType(MirroringType::ScreenBOnly); break; 104 } 105 break; 106 107 case 0xF000: 108 _irqReloadValue = (_irqReloadValue & 0xF0) | (value & 0x0F); 109 _console->GetCpu()->ClearIrqSource(IRQSource::External); 110 break; 111 112 case 0xF004: 113 _irqReloadValue = (_irqReloadValue & 0x0F) | (value << 4); 114 _console->GetCpu()->ClearIrqSource(IRQSource::External); 115 break; 116 117 case 0xF008: 118 _irqCounter = _irqReloadValue; 119 _irqEnabled = (value & 0x02) == 0x02; 120 _irqScaler = 0; 121 _console->GetCpu()->ClearIrqSource(IRQSource::External); 122 break; 123 } 124 } 125 } 126 };