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 };