Skip to content

Commit f260070

Browse files
Add Mapper 556
1 parent 4522a24 commit f260070

File tree

4 files changed

+302
-0
lines changed

4 files changed

+302
-0
lines changed

Core/Core.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,7 @@
808808
<ClInclude Include="Mapper452.h" />
809809
<ClInclude Include="Mapper538.h" />
810810
<ClInclude Include="Mapper540.h" />
811+
<ClInclude Include="Mapper556.h" />
811812
<ClInclude Include="MMC1_155.h" />
812813
<ClInclude Include="MMC1_297.h" />
813814
<ClInclude Include="MMC3_114.h" />

Core/Core.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,6 +1561,9 @@
15611561
<ClInclude Include="Mapper540.h">
15621562
<Filter>Nes\Mappers\Unnamed</Filter>
15631563
</ClInclude>
1564+
<ClInclude Include="Mapper556.h">
1565+
<Filter>Nes\Mappers\Unnamed</Filter>
1566+
</ClInclude>
15641567
<ClInclude Include="MMC3_208.h">
15651568
<Filter>Nes\Mappers\MMC</Filter>
15661569
</ClInclude>

Core/Mapper556.h

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
#pragma once
2+
#include "stdafx.h"
3+
#include "BaseMapper.h"
4+
#include "CPU.h"
5+
#include "A12Watcher.h"
6+
#include "VrcIrq.h"
7+
8+
class Mapper556 : public BaseMapper
9+
{
10+
private:
11+
A12Watcher _a12Watcher;
12+
unique_ptr<VrcIrq> _VrcIrq;
13+
14+
uint8_t _vrc2Chr[8];
15+
uint8_t _vrc2Prg[2];
16+
uint8_t _vrc2Mirroring;
17+
18+
uint8_t _mmc3Regs[10];
19+
uint8_t _mmc3Ctrl;
20+
uint8_t _mmc3Mirroring;
21+
22+
uint8_t _irqCounter;
23+
uint8_t _irqReloadValue;
24+
bool _irqReload;
25+
bool _irqEnabled;
26+
27+
uint8_t _regIndex;
28+
29+
uint16_t _prgMask;
30+
uint16_t _outerPrg;
31+
uint16_t _chrMask;
32+
uint16_t _outerChr;
33+
34+
bool _Vrc4Mode;
35+
bool _locked;
36+
37+
protected:
38+
virtual uint16_t GetPRGPageSize() override { return 0x2000; }
39+
virtual uint16_t GetCHRPageSize() override { return 0x400; }
40+
41+
void InitMapper() override
42+
{
43+
_VrcIrq.reset(new VrcIrq(_console));
44+
45+
_vrc2Chr[0] = -1;
46+
_vrc2Chr[1] = -1;
47+
_vrc2Chr[2] = -1;
48+
_vrc2Chr[3] = -1;
49+
_vrc2Chr[4] = 4;
50+
_vrc2Chr[5] = 5;
51+
_vrc2Chr[6] = 6;
52+
_vrc2Chr[7] = 7;
53+
_vrc2Prg[0] = 0;
54+
_vrc2Prg[1] = 1;
55+
_vrc2Mirroring = 0;
56+
57+
_mmc3Regs[0] = 0;
58+
_mmc3Regs[1] = 2;
59+
_mmc3Regs[2] = 4;
60+
_mmc3Regs[3] = 5;
61+
_mmc3Regs[4] = 6;
62+
_mmc3Regs[5] = 7;
63+
_mmc3Regs[6] = -4;
64+
_mmc3Regs[7] = -3;
65+
_mmc3Regs[8] = -2;
66+
_mmc3Regs[9] = -1;
67+
_mmc3Ctrl = 0;
68+
_mmc3Mirroring = 0;
69+
_irqCounter = 0;
70+
_irqReloadValue = 0;
71+
_irqEnabled = false;
72+
_irqReload = false;
73+
74+
_Vrc4Mode = false;
75+
_regIndex = 0;
76+
_prgMask = 0x3F;
77+
_outerPrg = 0x00;
78+
_chrMask = 0xFF;
79+
_outerChr = 0x00;
80+
_locked = false;
81+
82+
UpdateState();
83+
84+
AddRegisterRange(0x5000, 0x5FFF, MemoryOperation::Write);
85+
}
86+
87+
void Reset(bool softReset) override
88+
{
89+
_Vrc4Mode = false;
90+
_regIndex = 0;
91+
_prgMask = 0x3F;
92+
_outerPrg = 0x00;
93+
_chrMask = 0xFF;
94+
_outerChr = 0x00;
95+
_locked = false;
96+
97+
UpdateState();
98+
}
99+
100+
void StreamState(bool saving) override
101+
{
102+
BaseMapper::StreamState(saving);
103+
104+
SnapshotInfo a12Watcher { &_a12Watcher };
105+
ArrayInfo<uint8_t> vrc2Chr { _vrc2Chr, 8 };
106+
ArrayInfo<uint8_t> vrc2Prg { _vrc2Prg, 2 };
107+
ArrayInfo<uint8_t> mmc3Regs { _mmc3Regs, 10 };
108+
109+
Stream(a12Watcher,
110+
_Vrc4Mode, _regIndex, _prgMask, _outerPrg, _chrMask, _outerChr,
111+
vrc2Chr, vrc2Prg, _vrc2Mirroring,
112+
mmc3Regs, _mmc3Ctrl, _mmc3Mirroring, _irqCounter, _irqEnabled, _irqReload, _irqReloadValue
113+
);
114+
}
115+
116+
virtual void ProcessCpuClock() override
117+
{
118+
if(_Vrc4Mode) {
119+
_VrcIrq->ProcessCpuClock();
120+
}
121+
}
122+
123+
virtual void NotifyVRAMAddressChange(uint16_t addr) override
124+
{
125+
if(!_Vrc4Mode) {
126+
switch(_a12Watcher.UpdateVramAddress(addr, _console->GetPpu()->GetFrameCycle())) {
127+
case A12StateChange::None:
128+
case A12StateChange::Fall:
129+
break;
130+
131+
case A12StateChange::Rise:
132+
if(_irqCounter == 0 || _irqReload) {
133+
_irqCounter = _irqReloadValue;
134+
} else {
135+
_irqCounter--;
136+
}
137+
138+
if(_irqCounter == 0 && _irqEnabled) {
139+
_console->GetCpu()->SetIrqSource(IRQSource::External);
140+
}
141+
_irqReload = false;
142+
break;
143+
}
144+
}
145+
}
146+
147+
void UpdatePrg()
148+
{
149+
if(_Vrc4Mode) {
150+
SelectPRGPage(0, _outerPrg | (_vrc2Prg[0] & _prgMask));
151+
SelectPRGPage(1, _outerPrg | (_vrc2Prg[1] & _prgMask));
152+
SelectPRGPage(2, _outerPrg | ((-2) & _prgMask));
153+
SelectPRGPage(3, _outerPrg | ((-1) & _prgMask));
154+
} else {
155+
uint32_t prgMode = (_mmc3Ctrl >> 5) & 0x02;
156+
SelectPRGPage(0, _outerPrg | (_mmc3Regs[6 + prgMode] & _prgMask));
157+
SelectPRGPage(1, _outerPrg | (_mmc3Regs[7] & _prgMask));
158+
SelectPRGPage(2, _outerPrg | (_mmc3Regs[6 + (prgMode ^ 0x02)] & _prgMask));
159+
SelectPRGPage(3, _outerPrg | (_mmc3Regs[9] & _prgMask));
160+
}
161+
}
162+
163+
void UpdateChr()
164+
{
165+
if(_Vrc4Mode) {
166+
for(int i = 0; i < 8; i++) {
167+
SelectCHRPage(i, _outerChr | (_vrc2Chr[i] & _chrMask));
168+
}
169+
} else {
170+
uint32_t slotSwap = (_mmc3Ctrl & 0x80) ? 4 : 0;
171+
SelectCHRPage(0 ^ slotSwap, _outerChr | (((_mmc3Regs[0]) & 0xFE) & _chrMask));
172+
SelectCHRPage(1 ^ slotSwap, _outerChr | ((_mmc3Regs[0] | 1) & _chrMask));
173+
SelectCHRPage(2 ^ slotSwap, _outerChr | (((_mmc3Regs[1]) & 0xFE) & _chrMask));
174+
SelectCHRPage(3 ^ slotSwap, _outerChr | ((_mmc3Regs[1] | 1) & _chrMask));
175+
SelectCHRPage(4 ^ slotSwap, _outerChr | (_mmc3Regs[2] & _chrMask));
176+
SelectCHRPage(5 ^ slotSwap, _outerChr | (_mmc3Regs[3] & _chrMask));
177+
SelectCHRPage(6 ^ slotSwap, _outerChr | (_mmc3Regs[4] & _chrMask));
178+
SelectCHRPage(7 ^ slotSwap, _outerChr | (_mmc3Regs[5] & _chrMask));
179+
}
180+
}
181+
182+
void UpdateMirroring()
183+
{
184+
if(_Vrc4Mode) {
185+
SetMirroringType((_vrc2Mirroring & 0x01) ? MirroringType::Horizontal : MirroringType::Vertical);
186+
} else {
187+
SetMirroringType((_mmc3Mirroring & 0x01) ? MirroringType::Horizontal : MirroringType::Vertical);
188+
}
189+
}
190+
191+
void UpdateState()
192+
{
193+
UpdatePrg();
194+
UpdateChr();
195+
UpdateMirroring();
196+
}
197+
198+
void WriteVrc2Register(uint16_t addr, uint8_t value)
199+
{
200+
addr = (addr & 0xFF00) | ((addr >> 2) & 3);
201+
202+
if(addr >= 0xB000 && addr <= 0xE003) {
203+
int32_t regIndex = ((((addr & 0x02) | (addr >> 10)) >> 1) + 2) & 0x07;
204+
int32_t lowHighNibble = ((addr & 1) << 2);
205+
_vrc2Chr[regIndex] = (_vrc2Chr[regIndex] & (0xF0 >> lowHighNibble)) | ((value & 0x0F) << lowHighNibble);
206+
UpdateChr();
207+
} else {
208+
switch(addr & 0xF000) {
209+
case 0x8000: _vrc2Prg[0] = value; UpdatePrg(); break;
210+
case 0xA000: _vrc2Prg[1] = value; UpdatePrg(); break;
211+
case 0x9000: _vrc2Mirroring = value; UpdateMirroring(); break;
212+
case 0xF000:
213+
if(addr == 0xF000) {
214+
_VrcIrq->SetReloadValueNibble(value, false);
215+
} else if(addr == 0xF001) {
216+
_VrcIrq->SetReloadValueNibble(value, true);
217+
} else if(addr == 0xF002) {
218+
_VrcIrq->SetControlValue(value);
219+
} else if(addr == 0xF003) {
220+
_VrcIrq->AcknowledgeIrq();
221+
}
222+
break;
223+
}
224+
}
225+
}
226+
227+
void WriteMmc3Register(uint16_t addr, uint8_t value)
228+
{
229+
switch(addr & 0xE001) {
230+
case 0x8000:
231+
_mmc3Ctrl = value;
232+
UpdateState();
233+
break;
234+
235+
case 0x8001:
236+
_mmc3Regs[_mmc3Ctrl & 0x07] = value;
237+
UpdateState();
238+
break;
239+
240+
case 0xA000:
241+
_mmc3Mirroring = value;
242+
UpdateState();
243+
break;
244+
245+
case 0xC000: _irqReloadValue = value; break;
246+
case 0xC001: _irqReload = true; break;
247+
248+
case 0xE000:
249+
_console->GetCpu()->ClearIrqSource(IRQSource::External);
250+
_irqEnabled = false;
251+
break;
252+
253+
case 0xE001: _irqEnabled = true; break;
254+
}
255+
}
256+
257+
void WriteRegister(uint16_t addr, uint8_t value) override
258+
{
259+
if(addr < 0x8000) {
260+
if(!_locked) {
261+
switch(_regIndex) {
262+
case 0:
263+
_outerChr &= 0xFF00;
264+
_outerChr |= value;
265+
break;
266+
267+
case 1:
268+
_outerPrg &= 0xFF00;
269+
_outerPrg |= value;
270+
break;
271+
272+
case 2:
273+
_chrMask = 0xFF >> (~value & 0xF);
274+
_outerChr = _outerChr & ~0x0F00 | ((value & 0xF0) << 4);
275+
_Vrc4Mode = (value & 0x80) == 0x80;
276+
break;
277+
278+
case 3:
279+
_prgMask = ~value & 0x3F;
280+
_outerPrg = _outerPrg & ~0x0100 | ((value & 0x40) << 2);
281+
_outerChr = _outerChr & ~0x1000 | ((value & 0x40) << 6);
282+
_locked = (value & 0x80) == 0x80;
283+
break;
284+
}
285+
_regIndex = (_regIndex + 1) & 0x03;
286+
UpdateState();
287+
}
288+
} else {
289+
if(_Vrc4Mode) {
290+
WriteVrc2Register(addr, value);
291+
} else {
292+
WriteMmc3Register(addr, value);
293+
}
294+
}
295+
}
296+
};

Core/MapperFactory.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@
195195
#include "Mapper452.h"
196196
#include "Mapper538.h"
197197
#include "Mapper540.h"
198+
#include "Mapper556.h"
198199
#include "McAcc.h"
199200
#include "MMC1.h"
200201
#include "MMC1_105.h"
@@ -831,6 +832,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
831832
case 552: return new TaitoX1017();
832833
case 553: return new Sachen3013();
833834
case 554: return new Kaiser7010();
835+
case 556: return new Mapper556();
834836

835837
case UnifBoards::Ac08: return new Ac08(); //mapper 42?
836838
case UnifBoards::Cc21: return new Cc21();

0 commit comments

Comments
 (0)