-
Notifications
You must be signed in to change notification settings - Fork 100
/
sfc_mapper_001_mmc1.c
253 lines (232 loc) · 7.39 KB
/
sfc_mapper_001_mmc1.c
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#include "sfc_cpu.h"
#include "sfc_famicom.h"
#include "sfc_mapper_helper.h"
#include <assert.h>
#include <string.h>
#ifndef NDEBUG
#include <stdio.h>
#endif
/// <summary>
///
/// </summary>
typedef struct {
// 移位寄存器
uint8_t shifter;
// RPG-ROM 切换模式
uint8_t prmode;
// CHR-ROM 切换模式
uint8_t crmode;
// 控制寄存器
uint8_t control;
} sfc_mapper01_t;
/// <summary>
/// SFCs the mapper.
/// </summary>
/// <param name="famicom">The famicom.</param>
/// <returns></returns>
static inline sfc_mapper01_t* sfc_mapper(sfc_famicom_t* famicom) {
return (sfc_mapper01_t*)famicom->mapper_buffer.mapper01;
}
#define MAPPER sfc_mapper01_t* const mapper = sfc_mapper(famicom);
// ------------------------------- MAPPER 001 - MMC1 - SxROM
/// <summary>
/// SFCs the mapper 01 write control.
/// </summary>
/// <param name="famicom">The famicom.</param>
static void sfc_mapper_01_write_control(sfc_famicom_t* famicom, uint8_t data) {
MAPPER;
mapper->control = data;
// D0D1 - 镜像模式
const sfc_nametable_mirroring_mode mode = data & (uint8_t)0x3;
sfc_switch_nametable_mirroring(famicom, mode);
// D2D3 - PRG ROM bank 模式
const uint8_t prmode = (data >> 2) & (uint8_t)0x3;
mapper->prmode = prmode;
// D5 - CHR ROM bank 模式
const uint8_t crmode = data >> 4;
mapper->crmode = crmode;
}
/// <summary>
/// SFCs the mapper 01 write chrbank0.
/// </summary>
/// <param name="famicom">The famicom.</param>
static void sfc_mapper_01_write_chrbank0(sfc_famicom_t* famicom) {
MAPPER;
const uint8_t data = mapper->shifter;
const uint8_t mode = mapper->crmode;
// 8KB模式?
if (!mode) {
const int bank = (data & (uint8_t)0x0E) * 4;
sfc_load_chrrom_1k(famicom, 0, bank + 0);
sfc_load_chrrom_1k(famicom, 1, bank + 1);
sfc_load_chrrom_1k(famicom, 2, bank + 2);
sfc_load_chrrom_1k(famicom, 3, bank + 3);
sfc_load_chrrom_1k(famicom, 4, bank + 4);
sfc_load_chrrom_1k(famicom, 5, bank + 5);
sfc_load_chrrom_1k(famicom, 6, bank + 6);
sfc_load_chrrom_1k(famicom, 7, bank + 7);
}
// 4KB模式
else {
const int bank = data * 4;
sfc_load_chrrom_1k(famicom, 0, bank + 0);
sfc_load_chrrom_1k(famicom, 1, bank + 1);
sfc_load_chrrom_1k(famicom, 2, bank + 2);
sfc_load_chrrom_1k(famicom, 3, bank + 3);
}
}
/// <summary>
/// SFCs the mapper 01 write chrbank1.
/// </summary>
/// <param name="famicom">The famicom.</param>
static void sfc_mapper_01_write_chrbank1(sfc_famicom_t* famicom) {
MAPPER;
const uint8_t data = mapper->shifter;
const uint8_t mode = mapper->crmode;
// 8KB模式?
if (!mode) return;
// 4KB模式
const int bank = data * 4;
sfc_load_chrrom_1k(famicom, 4, bank + 0);
sfc_load_chrrom_1k(famicom, 5, bank + 1);
sfc_load_chrrom_1k(famicom, 6, bank + 2);
sfc_load_chrrom_1k(famicom, 7, bank + 3);
}
/// <summary>
/// SFCs the mapper 01 write prgbank.
/// </summary>
/// <param name="famicom">The famicom.</param>
static void sfc_mapper_01_write_prgbank(sfc_famicom_t* famicom) {
MAPPER;
const uint8_t data = mapper->shifter;
const uint8_t mode = mapper->prmode;
// PRG RAM使能
// TODO: PRG-RAM
const uint8_t prgram = data & (uint8_t)0x10;
const uint8_t bankid = data & (uint8_t)0x0f;
switch (mode)
{
int bank;
int last;
case 0: case 1:
// 32KB 模式
bank = (bankid & (uint8_t)0xE) * 2;
sfc_load_prgrom_8k(famicom, 0, bank + 0);
sfc_load_prgrom_8k(famicom, 1, bank + 1);
sfc_load_prgrom_8k(famicom, 2, bank + 2);
sfc_load_prgrom_8k(famicom, 3, bank + 3);
#ifndef NDEBUG
//printf("switch: PRG-ROM 32KB to:$%02X\n", bank / 2);
#endif
break;
case 2:
// 固定低16KB到最后 切换高16KB
bank = bankid * 2;
sfc_load_prgrom_8k(famicom, 0, 0);
sfc_load_prgrom_8k(famicom, 1, 1);
sfc_load_prgrom_8k(famicom, 2, bank + 0);
sfc_load_prgrom_8k(famicom, 3, bank + 1);
#ifndef NDEBUG
//printf("switch: HI-PRG-ROM 16KB to:$%02X\n", bank / 2);
#endif
break;
case 3:
// 固定高16KB到最后 切换低16KB
bank = bankid * 2;
last = famicom->rom_info.count_prgrom16kb * 2;
sfc_load_prgrom_8k(famicom, 0, bank + 0);
sfc_load_prgrom_8k(famicom, 1, bank + 1);
sfc_load_prgrom_8k(famicom, 2, last - 2);
sfc_load_prgrom_8k(famicom, 3, last - 1);
#ifndef NDEBUG
//printf("switch: LO-PRG-ROM 16KB to:$%02X\n", bank / 2);
#endif
break;
}
}
/// <summary>
/// SFCs the mapper 01 write register.
/// </summary>
/// <param name="famicom">The famicom.</param>
/// <param name="address">The address.</param>
static void sfc_mapper_01_write_register(sfc_famicom_t* famicom, uint16_t address) {
switch ((address & (uint16_t)0x7FFF) >> 13)
{
case 0:
// $8000-$9FFF Control
sfc_mapper_01_write_control(famicom, sfc_mapper(famicom)->shifter);
break;
case 1:
// $A000-$BFFF CHR bank 0
sfc_mapper_01_write_chrbank0(famicom);
break;
case 2:
// $C000-$DFFF CHR bank 1
sfc_mapper_01_write_chrbank1(famicom);
break;
case 3:
// $E000-$FFFF PRG bank
sfc_mapper_01_write_prgbank(famicom);
break;
}
}
/// <summary>
/// StepFC: MAPPER 001 - SxROM 重置
/// </summary>
/// <param name="famicom">The famicom.</param>
/// <returns></returns>
static sfc_ecode sfc_mapper_01_reset(sfc_famicom_t* famicom) {
// 你用MMC1居然没有32KB PRG-ROM?
assert(famicom->rom_info.count_prgrom16kb > 2 && "bad count");
// PRG-ROM
sfc_load_prgrom_8k(famicom, 0, 0);
sfc_load_prgrom_8k(famicom, 1, 1);
const int last = famicom->rom_info.count_prgrom16kb * 2;
sfc_load_prgrom_8k(famicom, 2, last-2);
sfc_load_prgrom_8k(famicom, 3, last-1);
// CHR-ROM
for (int i = 0; i != 8; ++i)
sfc_load_chrrom_1k(famicom, i, i);
return SFC_ERROR_OK;
}
/// <summary>
/// SFCs the mapper 01 write high.
/// </summary>
/// <param name="famicom">The famicom.</param>
/// <param name="address">The address.</param>
/// <param name="value">The value.</param>
static void sfc_mapper_01_write_high(sfc_famicom_t* famicom, uint16_t address, uint8_t value) {
MAPPER;
// D7 = 1 -> 重置移位寄存器
if (value & (uint8_t)0x80) {
mapper->shifter = 0x10;
sfc_mapper_01_write_control(famicom, mapper->control | (uint8_t)0x0C);
}
// D7 = 0 -> 写入D0到移位寄存器
else {
const uint8_t finished = mapper->shifter & 1;
mapper->shifter >>= 1;
mapper->shifter |= (value & 1) << 4;
if (finished) {
sfc_mapper_01_write_register(famicom, address);
mapper->shifter = 0x10;
}
}
}
/// <summary>
/// SFCs the load mapper 01.
/// </summary>
/// <param name="famicom">The famicom.</param>
/// <returns></returns>
extern inline sfc_ecode sfc_load_mapper_01(sfc_famicom_t* famicom) {
enum { MAPPER_01_SIZE_IMPL = sizeof(sfc_mapper01_t) };
static_assert(SFC_MAPPER_01_SIZE == MAPPER_01_SIZE_IMPL, "SAME");
// 初始化回调接口
famicom->mapper.reset = sfc_mapper_01_reset;
famicom->mapper.write_high = sfc_mapper_01_write_high;
// 初始化数据
MAPPER;
memset(mapper, 0, MAPPER_01_SIZE_IMPL);
mapper->shifter = 0x10;
return SFC_ERROR_OK;
}