/
Mapper4.cpp
160 lines (145 loc) · 3.68 KB
/
Mapper4.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include "Mapper4.h"
#include <iostream>
using namespace std;
const int CHR_2KB_FIRST = 0;
const int CHR_2KB_LAST = 1;
const int PRG_SWITCH_FIRST = 0;
const int PRG_SWITCH_MID = 1;
Mapper4::Mapper4(char* file) : Mapper(file, 8, 1)
{
cout << "using mapper 4...";
lastPpuAddr = -1;
irqCounter = 1;
prgIndexes[2] = nPrgBanks - 2;
prgIndexes[3] = nPrgBanks - 1;
}
Mapper4::~Mapper4(void)
{
}
void Mapper4::writeByteTo(int address, int value)
{
//cout << "Mapper 4: 0x" << address << " = 0x" << value << "\n";
value &= 0xFF;
switch (address)
{
case 0x8000:
targetBank = value & 0x7;
chrMode = (value & 0x80) >> 7;
prgMode = (value & 0x40) >> 6;
break;
case 0x8001:
bankSwitch(value);
break;
case 0xA000:
mirroring = value & 0x01;
break;
case 0xA001:
prgRamEnabled = value & 0x80;
prgRamWritable = value & 0x40;
break;
case 0xC000:
irqLatch = value;
if (!counter_latched)
irqCounter = irqLatch;
break;
case 0xC001:
irqCounter = irqLatch;
counter_latched = false;
break;
case 0xE000:
fireIRQs = false;
if (!counter_latched)
irqCounter = irqLatch;
break;
case 0xE001:
fireIRQs = true;
if (!counter_latched)
irqCounter = irqLatch;
break;
}
}
void Mapper4::bankSwitch(int value)
{
if (targetBank < 2)
{
chrIndexes[2*targetBank] = value;
chrIndexes[2*targetBank+1] = value+1;
}
else if (targetBank < 6)
chrIndexes[targetBank+2] = value;
else
prgIndexes[targetBank-6] = value;
}
////////////////////////////////////////////////////////////////////////////////
// CHR Bank switching //
////////////////////////////////////////////////////////////////////////////////
inline int Mapper4::chrBankNumber(int address)
{
int bankNumber = address / 0x400;
if (chrMode == CHR_2KB_LAST)
{
bankNumber += 4;
bankNumber %= 8;
}
return bankNumber;
}
int Mapper4::ppuReadByteFrom(int address)
{
int bankAddress = address % 0x400;
return chrBanks[chrIndexes[chrBankNumber(address)]][bankAddress];
}
void Mapper4::ppuWriteByteTo(int address, int value)
{
if (nChrBanks != 0)
return;
int bankAddress = address % 0x400;
chrBanks[chrIndexes[chrBankNumber(address)]][bankAddress] = value;
}
////////////////////////////////////////////////////////////////////////////////
// PRG Bank switching //
////////////////////////////////////////////////////////////////////////////////
inline int Mapper4::prgBankNumber(int address)
{
int bankNumber = (address-0x8000) / 0x2000;
if (prgMode == PRG_SWITCH_MID && bankNumber == 0)
bankNumber = 2;
else if (prgMode == PRG_SWITCH_MID && bankNumber == 2)
bankNumber = 0;
return bankNumber;
}
int Mapper4::readByteFrom(int address)
{
if (address < 0x6000)
{
return 0;
}
else if (address >= 0x6000 && address < 0x8000)
{
if (prgRamEnabled)
return prgRam[address-0x6000];
else
return 0;
}
else if (nPrgBanks == 0)
{
return 0;
}
int bankAddress = address % 0x2000;
int bank = prgBankNumber(address);
return prgBanks[prgIndexes[bank]][bankAddress];
}
////////////////////////////////////////////////////////////////////////////////
// IRQ Counter //
////////////////////////////////////////////////////////////////////////////////
void Mapper4::scanlineCounter()
{
counter_latched = true;
if (irqCounter--)
return;
irqCounter = irqLatch;
if (fireIRQs)
{
cpu->doIRQ();
counter_latched = false;
}
}