src/gb/mbc.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "mbc.h"
7
8#include "gb/gb.h"
9#include "gb/memory.h"
10
11#include <time.h>
12
13mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC");
14
15static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) {
16 UNUSED(gb);
17 UNUSED(address);
18 UNUSED(value);
19
20 mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC");
21}
22
23static void _GBMBC1(struct GB*, uint16_t address, uint8_t value);
24static void _GBMBC2(struct GB*, uint16_t address, uint8_t value);
25static void _GBMBC3(struct GB*, uint16_t address, uint8_t value);
26static void _GBMBC5(struct GB*, uint16_t address, uint8_t value);
27static void _GBMBC6(struct GB*, uint16_t address, uint8_t value);
28static void _GBMBC7(struct GB*, uint16_t address, uint8_t value);
29static void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
30
31void GBMBCSwitchBank(struct GBMemory* memory, int bank) {
32 size_t bankStart = bank * GB_SIZE_CART_BANK0;
33 if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
34 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
35 bankStart &= (memory->romSize - 1);
36 bank = bankStart / GB_SIZE_CART_BANK0;
37 }
38 memory->romBank = &memory->rom[bankStart];
39 memory->currentBank = bank;
40}
41
42void GBMBCSwitchSramBank(struct GB* gb, int bank) {
43 size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
44 GBResizeSram(gb, (bank + 1) * GB_SIZE_EXTERNAL_RAM + (gb->sramSize & 0xFF));
45 gb->memory.sramBank = &gb->memory.sram[bankStart];
46 gb->memory.sramCurrentBank = bank;
47}
48
49void GBMBCInit(struct GB* gb) {
50 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
51 switch (cart->type) {
52 case 0:
53 case 8:
54 case 9:
55 gb->memory.mbc = _GBMBCNone;
56 gb->memory.mbcType = GB_MBC_NONE;
57 gb->sramSize = 0;
58 return;
59 case 1:
60 case 2:
61 case 3:
62 gb->memory.mbc = _GBMBC1;
63 gb->memory.mbcType = GB_MBC1;
64 gb->sramSize = 0x2000;
65 break;
66 case 5:
67 case 6:
68 gb->memory.mbc = _GBMBC2;
69 gb->memory.mbcType = GB_MBC2;
70 gb->sramSize = 0x200;
71 break;
72 case 0x0F:
73 case 0x10:
74 case 0x11:
75 case 0x12:
76 case 0x13:
77 gb->memory.mbc = _GBMBC3;
78 gb->memory.mbcType = GB_MBC3;
79 gb->sramSize = 0x2048;
80 break;
81 default:
82 mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
83 // Fall through
84 case 0x19:
85 case 0x1A:
86 case 0x1B:
87 gb->memory.mbc = _GBMBC5;
88 gb->memory.mbcType = GB_MBC5;
89 gb->sramSize = 0x2000;
90 break;
91 case 0x1C:
92 case 0x1D:
93 case 0x1E:
94 gb->memory.mbc = _GBMBC5;
95 gb->memory.mbcType = GB_MBC5_RUMBLE;
96 gb->sramSize = 0x2000;
97 break;
98 case 0x20:
99 gb->memory.mbc = _GBMBC6;
100 gb->memory.mbcType = GB_MBC6;
101 gb->sramSize = 0; // TODO
102 break;
103 case 0x22:
104 gb->memory.mbc = _GBMBC7;
105 gb->memory.mbcType = GB_MBC7;
106 gb->sramSize = 0x2000;
107 break;
108 case 0xFE:
109 gb->memory.mbc = _GBHuC3;
110 gb->memory.mbcType = GB_HuC3;
111 gb->sramSize = 0x2000;
112 break;
113 }
114
115 GBResizeSram(gb, gb->sramSize);
116}
117
118static void _latchRtc(struct GBMemory* memory) {
119 time_t t;
120 struct mRTCSource* rtc = memory->rtc;
121 if (rtc) {
122 if (rtc->sample) {
123 rtc->sample(rtc);
124 }
125 t = rtc->unixTime(rtc);
126 } else {
127 t = time(0);
128 }
129 struct tm date;
130 localtime_r(&t, &date);
131 memory->rtcRegs[0] = date.tm_sec;
132 memory->rtcRegs[1] = date.tm_min;
133 memory->rtcRegs[2] = date.tm_hour;
134 memory->rtcRegs[3] = date.tm_yday; // TODO: Persist day counter
135 memory->rtcRegs[4] &= 0xF0;
136 memory->rtcRegs[4] |= date.tm_yday >> 8;
137}
138
139void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
140 struct GBMemory* memory = &gb->memory;
141 int bank = value & 0x1F;
142 switch (address >> 13) {
143 case 0x0:
144 switch (value) {
145 case 0:
146 memory->sramAccess = false;
147 break;
148 case 0xA:
149 memory->sramAccess = true;
150 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
151 break;
152 default:
153 // TODO
154 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
155 break;
156 }
157 break;
158 case 0x1:
159 if (!bank) {
160 ++bank;
161 }
162 GBMBCSwitchBank(memory, bank | (memory->currentBank & 0x60));
163 break;
164 case 0x2:
165 bank &= 3;
166 if (!memory->mbcState.mbc1.mode) {
167 GBMBCSwitchBank(memory, (bank << 5) | (memory->currentBank & 0x1F));
168 } else {
169 GBMBCSwitchSramBank(gb, bank);
170 }
171 break;
172 case 0x3:
173 memory->mbcState.mbc1.mode = value & 1;
174 if (memory->mbcState.mbc1.mode) {
175 GBMBCSwitchBank(memory, memory->currentBank & 0x1F);
176 } else {
177 GBMBCSwitchSramBank(gb, 0);
178 }
179 break;
180 default:
181 // TODO
182 mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
183 break;
184 }
185}
186
187void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
188 struct GBMemory* memory = &gb->memory;
189 int bank = value & 0xF;
190 switch (address >> 13) {
191 case 0x0:
192 switch (value) {
193 case 0:
194 memory->sramAccess = false;
195 break;
196 case 0xA:
197 memory->sramAccess = true;
198 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
199 break;
200 default:
201 // TODO
202 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
203 break;
204 }
205 break;
206 case 0x1:
207 if (!bank) {
208 ++bank;
209 }
210 GBMBCSwitchBank(memory, bank);
211 break;
212 default:
213 // TODO
214 mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
215 break;
216 }}
217
218void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
219 struct GBMemory* memory = &gb->memory;
220 int bank = value & 0x7F;
221 switch (address >> 13) {
222 case 0x0:
223 switch (value) {
224 case 0:
225 memory->sramAccess = false;
226 break;
227 case 0xA:
228 memory->sramAccess = true;
229 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
230 break;
231 default:
232 // TODO
233 mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
234 break;
235 }
236 break;
237 case 0x1:
238 if (!bank) {
239 ++bank;
240 }
241 GBMBCSwitchBank(memory, bank);
242 break;
243 case 0x2:
244 if (value < 4) {
245 GBMBCSwitchSramBank(gb, value);
246 memory->rtcAccess = false;
247 } else if (value >= 8 && value <= 0xC) {
248 memory->activeRtcReg = value - 8;
249 memory->rtcAccess = true;
250 }
251 break;
252 case 0x3:
253 if (memory->rtcLatched && value == 0) {
254 memory->rtcLatched = false;
255 } else if (!memory->rtcLatched && value == 1) {
256 _latchRtc(memory);
257 memory->rtcLatched = true;
258 }
259 break;
260 }
261}
262
263void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
264 struct GBMemory* memory = &gb->memory;
265 int bank;
266 switch (address >> 12) {
267 case 0x0:
268 case 0x1:
269 switch (value) {
270 case 0:
271 memory->sramAccess = false;
272 break;
273 case 0xA:
274 memory->sramAccess = true;
275 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
276 break;
277 default:
278 // TODO
279 mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
280 break;
281 }
282 break;
283 case 0x2:
284 bank = (memory->currentBank & 0x100) | value;
285 GBMBCSwitchBank(memory, bank);
286 break;
287 case 0x3:
288 bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
289 GBMBCSwitchBank(memory, bank);
290 break;
291 case 0x4:
292 case 0x5:
293 if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) {
294 memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
295 value &= ~8;
296 }
297 GBMBCSwitchSramBank(gb, value & 0xF);
298 break;
299 default:
300 // TODO
301 mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
302 break;
303 }
304}
305
306void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
307 // TODO
308 mLOG(GB_MBC, STUB, "MBC6 unimplemented");
309 UNUSED(gb);
310 UNUSED(address);
311 UNUSED(value);
312}
313
314void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
315 struct GBMemory* memory = &gb->memory;
316 int bank = value & 0x7F;
317 switch (address >> 13) {
318 case 0x1:
319 GBMBCSwitchBank(memory, bank);
320 break;
321 case 0x2:
322 if (value < 0x10) {
323 GBMBCSwitchSramBank(gb, value);
324 }
325 break;
326 default:
327 // TODO
328 mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
329 break;
330 }
331}
332
333uint8_t GBMBC7Read(struct GBMemory* memory, uint16_t address) {
334 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
335 switch (address & 0xF0) {
336 case 0x00:
337 case 0x10:
338 case 0x60:
339 case 0x70:
340 return 0;
341 case 0x20:
342 if (memory->rotation && memory->rotation->readTiltX) {
343 int32_t x = -memory->rotation->readTiltX(memory->rotation);
344 x >>= 21;
345 x += 2047;
346 return x;
347 }
348 return 0xFF;
349 case 0x30:
350 if (memory->rotation && memory->rotation->readTiltX) {
351 int32_t x = -memory->rotation->readTiltX(memory->rotation);
352 x >>= 21;
353 x += 2047;
354 return x >> 8;
355 }
356 return 7;
357 case 0x40:
358 if (memory->rotation && memory->rotation->readTiltY) {
359 int32_t y = -memory->rotation->readTiltY(memory->rotation);
360 y >>= 21;
361 y += 2047;
362 return y;
363 }
364 return 0xFF;
365 case 0x50:
366 if (memory->rotation && memory->rotation->readTiltY) {
367 int32_t y = -memory->rotation->readTiltY(memory->rotation);
368 y >>= 21;
369 y += 2047;
370 return y >> 8;
371 }
372 return 7;
373 case 0x80:
374 return (mbc7->sr >> 16) & 1;
375 default:
376 return 0xFF;
377 }
378}
379
380void GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
381 if ((address & 0xF0) != 0x80) {
382 return;
383 }
384 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
385 GBMBC7Field old = memory->mbcState.mbc7.field;
386 mbc7->field = GBMBC7FieldClearIO(value);
387 if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
388 if (mbc7->state == GBMBC7_STATE_WRITE) {
389 if (mbc7->writable) {
390 memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8;
391 memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr;
392 }
393 mbc7->sr = 0x1FFFF;
394 mbc7->state = GBMBC7_STATE_NULL;
395 } else {
396 mbc7->state = GBMBC7_STATE_IDLE;
397 }
398 }
399 if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) {
400 if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) {
401 mbc7->sr <<= 1;
402 mbc7->sr |= GBMBC7FieldGetIO(value);
403 ++mbc7->srBits;
404 }
405 switch (mbc7->state) {
406 case GBMBC7_STATE_IDLE:
407 if (GBMBC7FieldIsIO(value)) {
408 mbc7->state = GBMBC7_STATE_READ_COMMAND;
409 mbc7->srBits = 0;
410 mbc7->sr = 0;
411 }
412 break;
413 case GBMBC7_STATE_READ_COMMAND:
414 if (mbc7->srBits == 2) {
415 mbc7->state = GBMBC7_STATE_READ_ADDRESS;
416 mbc7->srBits = 0;
417 mbc7->command = mbc7->sr;
418 }
419 break;
420 case GBMBC7_STATE_READ_ADDRESS:
421 if (mbc7->srBits == 8) {
422 mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command;
423 mbc7->srBits = 0;
424 mbc7->address = mbc7->sr;
425 if (mbc7->state == GBMBC7_STATE_COMMAND_0) {
426 switch (mbc7->address >> 6) {
427 case 0:
428 mbc7->writable = false;
429 mbc7->state = GBMBC7_STATE_NULL;
430 break;
431 case 3:
432 mbc7->writable = true;
433 mbc7->state = GBMBC7_STATE_NULL;
434 break;
435 }
436 }
437 }
438 break;
439 case GBMBC7_STATE_COMMAND_0:
440 if (mbc7->srBits == 16) {
441 switch (mbc7->address >> 6) {
442 case 0:
443 mbc7->writable = false;
444 mbc7->state = GBMBC7_STATE_NULL;
445 break;
446 case 1:
447 mbc7->state = GBMBC7_STATE_WRITE;
448 if (mbc7->writable) {
449 int i;
450 for (i = 0; i < 256; ++i) {
451 memory->sramBank[i * 2] = mbc7->sr >> 8;
452 memory->sramBank[i * 2 + 1] = mbc7->sr;
453 }
454 }
455 break;
456 case 2:
457 mbc7->state = GBMBC7_STATE_WRITE;
458 if (mbc7->writable) {
459 int i;
460 for (i = 0; i < 256; ++i) {
461 memory->sramBank[i * 2] = 0xFF;
462 memory->sramBank[i * 2 + 1] = 0xFF;
463 }
464 }
465 break;
466 case 3:
467 mbc7->writable = true;
468 mbc7->state = GBMBC7_STATE_NULL;
469 break;
470 }
471 }
472 break;
473 case GBMBC7_STATE_COMMAND_SR_WRITE:
474 if (mbc7->srBits == 16) {
475 mbc7->srBits = 0;
476 mbc7->state = GBMBC7_STATE_WRITE;
477 }
478 break;
479 case GBMBC7_STATE_COMMAND_SR_READ:
480 if (mbc7->srBits == 1) {
481 mbc7->sr = memory->sramBank[mbc7->address * 2] << 8;
482 mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1];
483 mbc7->srBits = 0;
484 mbc7->state = GBMBC7_STATE_READ;
485 }
486 break;
487 case GBMBC7_STATE_COMMAND_SR_FILL:
488 if (mbc7->srBits == 16) {
489 mbc7->sr = 0xFFFF;
490 mbc7->srBits = 0;
491 mbc7->state = GBMBC7_STATE_WRITE;
492 }
493 break;
494 default:
495 break;
496 }
497 } else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) {
498 if (mbc7->state == GBMBC7_STATE_READ) {
499 mbc7->sr <<= 1;
500 ++mbc7->srBits;
501 if (mbc7->srBits == 16) {
502 mbc7->srBits = 0;
503 mbc7->state = GBMBC7_STATE_NULL;
504 }
505 }
506 }
507}
508
509void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) {
510 struct GBMemory* memory = &gb->memory;
511 int bank = value & 0x3F;
512 if (address & 0x1FFF) {
513 mLOG(GB_MBC, STUB, "HuC-3 unknown value %04X:%02X", address, value);
514 }
515
516 switch (address >> 13) {
517 case 0x0:
518 switch (value) {
519 case 0xA:
520 memory->sramAccess = true;
521 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
522 break;
523 default:
524 memory->sramAccess = false;
525 break;
526 }
527 break;
528 case 0x1:
529 GBMBCSwitchBank(memory, bank);
530 break;
531 case 0x2:
532 GBMBCSwitchSramBank(gb, bank);
533 break;
534 default:
535 // TODO
536 mLOG(GB_MBC, STUB, "HuC-3 unknown address: %04X:%02X", address, value);
537 break;
538 }
539}