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#include "gb/memory.h"
11#include "util/vfs.h"
12
13#include <time.h>
14
15mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC");
16
17static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) {
18 UNUSED(gb);
19 UNUSED(address);
20 UNUSED(value);
21
22 mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC");
23}
24
25static void _GBMBC1(struct GB*, uint16_t address, uint8_t value);
26static void _GBMBC2(struct GB*, uint16_t address, uint8_t value);
27static void _GBMBC3(struct GB*, uint16_t address, uint8_t value);
28static void _GBMBC5(struct GB*, uint16_t address, uint8_t value);
29static void _GBMBC6(struct GB*, uint16_t address, uint8_t value);
30static void _GBMBC7(struct GB*, uint16_t address, uint8_t value);
31static void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
32
33void GBMBCSwitchBank(struct GBMemory* memory, int bank) {
34 size_t bankStart = bank * GB_SIZE_CART_BANK0;
35 if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
36 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
37 bankStart &= (memory->romSize - 1);
38 bank = bankStart / GB_SIZE_CART_BANK0;
39 }
40 memory->romBank = &memory->rom[bankStart];
41 memory->currentBank = bank;
42}
43
44void GBMBCSwitchSramBank(struct GB* gb, int bank) {
45 size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
46 GBResizeSram(gb, (bank + 1) * GB_SIZE_EXTERNAL_RAM);
47 gb->memory.sramBank = &gb->memory.sram[bankStart];
48 gb->memory.sramCurrentBank = bank;
49}
50
51void GBMBCInit(struct GB* gb) {
52 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
53 switch (cart->ramSize) {
54 case 0:
55 gb->sramSize = 0;
56 break;
57 case 1:
58 gb->sramSize = 0x800;
59 break;
60 default:
61 case 2:
62 gb->sramSize = 0x2000;
63 break;
64 case 3:
65 gb->sramSize = 0x8000;
66 break;
67 }
68
69 if (gb->memory.mbcType == GB_MBC_AUTODETECT) {
70 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
71 switch (cart->type) {
72 case 0:
73 case 8:
74 case 9:
75 gb->memory.mbcType = GB_MBC_NONE;
76 break;
77 case 1:
78 case 2:
79 case 3:
80 gb->memory.mbcType = GB_MBC1;
81 break;
82 case 5:
83 case 6:
84 gb->memory.mbcType = GB_MBC2;
85 break;
86 case 0x0F:
87 case 0x10:
88 gb->memory.mbcType = GB_MBC3_RTC;
89 break;
90 case 0x11:
91 case 0x12:
92 case 0x13:
93 gb->memory.mbcType = GB_MBC3;
94 break;
95 default:
96 mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
97 // Fall through
98 case 0x19:
99 case 0x1A:
100 case 0x1B:
101 gb->memory.mbcType = GB_MBC5;
102 break;
103 case 0x1C:
104 case 0x1D:
105 case 0x1E:
106 gb->memory.mbcType = GB_MBC5_RUMBLE;
107 break;
108 case 0x20:
109 gb->memory.mbcType = GB_MBC6;
110 break;
111 case 0x22:
112 gb->memory.mbcType = GB_MBC7;
113 break;
114 case 0xFE:
115 gb->memory.mbcType = GB_HuC3;
116 break;
117 }
118 }
119 switch (gb->memory.mbcType) {
120 case GB_MBC_NONE:
121 gb->memory.mbc = _GBMBCNone;
122 break;
123 case GB_MBC1:
124 gb->memory.mbc = _GBMBC1;
125 break;
126 case GB_MBC2:
127 gb->memory.mbc = _GBMBC2;
128 gb->sramSize = 0x200;
129 break;
130 case GB_MBC3:
131 gb->memory.mbc = _GBMBC3;
132 break;
133 default:
134 mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
135 // Fall through
136 case GB_MBC5:
137 gb->memory.mbc = _GBMBC5;
138 break;
139 case GB_MBC6:
140 mLOG(GB_MBC, WARN, "unimplemented MBC: MBC6");
141 gb->memory.mbc = _GBMBC6;
142 break;
143 case GB_MBC7:
144 gb->memory.mbc = _GBMBC7;
145 break;
146 case GB_MMM01:
147 mLOG(GB_MBC, WARN, "unimplemented MBC: MMM01");
148 gb->memory.mbc = _GBMBC1;
149 break;
150 case GB_HuC1:
151 mLOG(GB_MBC, WARN, "unimplemented MBC: HuC-1");
152 gb->memory.mbc = _GBMBC1;
153 break;
154 case GB_HuC3:
155 gb->memory.mbc = _GBHuC3;
156 break;
157 case GB_MBC3_RTC:
158 memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
159 gb->memory.mbc = _GBMBC3;
160 break;
161 case GB_MBC5_RUMBLE:
162 gb->memory.mbc = _GBMBC5;
163 break;
164 }
165
166 GBResizeSram(gb, gb->sramSize);
167
168 if (gb->memory.mbcType == GB_MBC3_RTC) {
169 GBMBCRTCRead(gb);
170 }
171}
172
173static void _latchRtc(struct mRTCSource* rtc, uint8_t* rtcRegs, time_t* rtcLastLatch) {
174 time_t t;
175 if (rtc) {
176 if (rtc->sample) {
177 rtc->sample(rtc);
178 }
179 t = rtc->unixTime(rtc);
180 } else {
181 t = time(0);
182 }
183 time_t currentLatch = t;
184 t -= *rtcLastLatch;
185 *rtcLastLatch = currentLatch;
186
187 int64_t diff;
188 diff = rtcRegs[0] + t % 60;
189 if (diff < 0) {
190 diff += 60;
191 t -= 60;
192 }
193 rtcRegs[0] = diff % 60;
194 t /= 60;
195 t += diff / 60;
196
197 diff = rtcRegs[1] + t % 60;
198 if (diff < 0) {
199 diff += 60;
200 t -= 60;
201 }
202 rtcRegs[1] = diff % 60;
203 t /= 60;
204 t += diff / 60;
205
206 diff = rtcRegs[2] + t % 24;
207 if (diff < 0) {
208 diff += 24;
209 t -= 24;
210 }
211 rtcRegs[2] = diff % 24;
212 t /= 24;
213 t += diff / 24;
214
215 diff = rtcRegs[3] + ((rtcRegs[4] & 1) << 8) + (t & 0x1FF);
216 rtcRegs[3] = diff;
217 rtcRegs[4] &= 0xFE;
218 rtcRegs[4] |= (diff >> 8) & 1;
219 if (diff & 0x200) {
220 rtcRegs[4] |= 0x80;
221 }
222}
223
224void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
225 struct GBMemory* memory = &gb->memory;
226 int bank = value & 0x1F;
227 switch (address >> 13) {
228 case 0x0:
229 switch (value) {
230 case 0:
231 memory->sramAccess = false;
232 break;
233 case 0xA:
234 memory->sramAccess = true;
235 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
236 break;
237 default:
238 // TODO
239 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
240 break;
241 }
242 break;
243 case 0x1:
244 if (!bank) {
245 ++bank;
246 }
247 GBMBCSwitchBank(memory, bank | (memory->currentBank & 0x60));
248 break;
249 case 0x2:
250 bank &= 3;
251 if (!memory->mbcState.mbc1.mode) {
252 GBMBCSwitchBank(memory, (bank << 5) | (memory->currentBank & 0x1F));
253 } else {
254 GBMBCSwitchSramBank(gb, bank);
255 }
256 break;
257 case 0x3:
258 memory->mbcState.mbc1.mode = value & 1;
259 if (memory->mbcState.mbc1.mode) {
260 GBMBCSwitchBank(memory, memory->currentBank & 0x1F);
261 } else {
262 GBMBCSwitchSramBank(gb, 0);
263 }
264 break;
265 default:
266 // TODO
267 mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
268 break;
269 }
270}
271
272void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
273 struct GBMemory* memory = &gb->memory;
274 int bank = value & 0xF;
275 switch (address >> 13) {
276 case 0x0:
277 switch (value) {
278 case 0:
279 memory->sramAccess = false;
280 break;
281 case 0xA:
282 memory->sramAccess = true;
283 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
284 break;
285 default:
286 // TODO
287 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
288 break;
289 }
290 break;
291 case 0x1:
292 if (!bank) {
293 ++bank;
294 }
295 GBMBCSwitchBank(memory, bank);
296 break;
297 default:
298 // TODO
299 mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
300 break;
301 }}
302
303void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
304 struct GBMemory* memory = &gb->memory;
305 int bank = value & 0x7F;
306 switch (address >> 13) {
307 case 0x0:
308 switch (value) {
309 case 0:
310 memory->sramAccess = false;
311 break;
312 case 0xA:
313 memory->sramAccess = true;
314 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
315 break;
316 default:
317 // TODO
318 mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
319 break;
320 }
321 break;
322 case 0x1:
323 if (!bank) {
324 ++bank;
325 }
326 GBMBCSwitchBank(memory, bank);
327 break;
328 case 0x2:
329 if (value < 4) {
330 GBMBCSwitchSramBank(gb, value);
331 memory->rtcAccess = false;
332 } else if (value >= 8 && value <= 0xC) {
333 memory->activeRtcReg = value - 8;
334 memory->rtcAccess = true;
335 }
336 break;
337 case 0x3:
338 if (memory->rtcLatched && value == 0) {
339 memory->rtcLatched = false;
340 } else if (!memory->rtcLatched && value == 1) {
341 _latchRtc(gb->memory.rtc, gb->memory.rtcRegs, &gb->memory.rtcLastLatch);
342 memory->rtcLatched = true;
343 }
344 break;
345 }
346}
347
348void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
349 struct GBMemory* memory = &gb->memory;
350 int bank;
351 switch (address >> 12) {
352 case 0x0:
353 case 0x1:
354 switch (value) {
355 case 0:
356 memory->sramAccess = false;
357 break;
358 case 0xA:
359 memory->sramAccess = true;
360 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
361 break;
362 default:
363 // TODO
364 mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
365 break;
366 }
367 break;
368 case 0x2:
369 bank = (memory->currentBank & 0x100) | value;
370 GBMBCSwitchBank(memory, bank);
371 break;
372 case 0x3:
373 bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
374 GBMBCSwitchBank(memory, bank);
375 break;
376 case 0x4:
377 case 0x5:
378 if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) {
379 memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
380 value &= ~8;
381 }
382 GBMBCSwitchSramBank(gb, value & 0xF);
383 break;
384 default:
385 // TODO
386 mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
387 break;
388 }
389}
390
391void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
392 // TODO
393 mLOG(GB_MBC, STUB, "MBC6 unimplemented");
394 UNUSED(gb);
395 UNUSED(address);
396 UNUSED(value);
397}
398
399void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
400 struct GBMemory* memory = &gb->memory;
401 int bank = value & 0x7F;
402 switch (address >> 13) {
403 case 0x1:
404 GBMBCSwitchBank(memory, bank);
405 break;
406 case 0x2:
407 if (value < 0x10) {
408 GBMBCSwitchSramBank(gb, value);
409 }
410 break;
411 default:
412 // TODO
413 mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
414 break;
415 }
416}
417
418uint8_t GBMBC7Read(struct GBMemory* memory, uint16_t address) {
419 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
420 switch (address & 0xF0) {
421 case 0x00:
422 case 0x10:
423 case 0x60:
424 case 0x70:
425 return 0;
426 case 0x20:
427 if (memory->rotation && memory->rotation->readTiltX) {
428 int32_t x = -memory->rotation->readTiltX(memory->rotation);
429 x >>= 21;
430 x += 2047;
431 return x;
432 }
433 return 0xFF;
434 case 0x30:
435 if (memory->rotation && memory->rotation->readTiltX) {
436 int32_t x = -memory->rotation->readTiltX(memory->rotation);
437 x >>= 21;
438 x += 2047;
439 return x >> 8;
440 }
441 return 7;
442 case 0x40:
443 if (memory->rotation && memory->rotation->readTiltY) {
444 int32_t y = -memory->rotation->readTiltY(memory->rotation);
445 y >>= 21;
446 y += 2047;
447 return y;
448 }
449 return 0xFF;
450 case 0x50:
451 if (memory->rotation && memory->rotation->readTiltY) {
452 int32_t y = -memory->rotation->readTiltY(memory->rotation);
453 y >>= 21;
454 y += 2047;
455 return y >> 8;
456 }
457 return 7;
458 case 0x80:
459 return (mbc7->sr >> 16) & 1;
460 default:
461 return 0xFF;
462 }
463}
464
465void GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
466 if ((address & 0xF0) != 0x80) {
467 return;
468 }
469 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
470 GBMBC7Field old = memory->mbcState.mbc7.field;
471 mbc7->field = GBMBC7FieldClearIO(value);
472 if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
473 if (mbc7->state == GBMBC7_STATE_WRITE) {
474 if (mbc7->writable) {
475 memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8;
476 memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr;
477 }
478 mbc7->sr = 0x1FFFF;
479 mbc7->state = GBMBC7_STATE_NULL;
480 } else {
481 mbc7->state = GBMBC7_STATE_IDLE;
482 }
483 }
484 if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) {
485 if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) {
486 mbc7->sr <<= 1;
487 mbc7->sr |= GBMBC7FieldGetIO(value);
488 ++mbc7->srBits;
489 }
490 switch (mbc7->state) {
491 case GBMBC7_STATE_IDLE:
492 if (GBMBC7FieldIsIO(value)) {
493 mbc7->state = GBMBC7_STATE_READ_COMMAND;
494 mbc7->srBits = 0;
495 mbc7->sr = 0;
496 }
497 break;
498 case GBMBC7_STATE_READ_COMMAND:
499 if (mbc7->srBits == 2) {
500 mbc7->state = GBMBC7_STATE_READ_ADDRESS;
501 mbc7->srBits = 0;
502 mbc7->command = mbc7->sr;
503 }
504 break;
505 case GBMBC7_STATE_READ_ADDRESS:
506 if (mbc7->srBits == 8) {
507 mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command;
508 mbc7->srBits = 0;
509 mbc7->address = mbc7->sr;
510 if (mbc7->state == GBMBC7_STATE_COMMAND_0) {
511 switch (mbc7->address >> 6) {
512 case 0:
513 mbc7->writable = false;
514 mbc7->state = GBMBC7_STATE_NULL;
515 break;
516 case 3:
517 mbc7->writable = true;
518 mbc7->state = GBMBC7_STATE_NULL;
519 break;
520 }
521 }
522 }
523 break;
524 case GBMBC7_STATE_COMMAND_0:
525 if (mbc7->srBits == 16) {
526 switch (mbc7->address >> 6) {
527 case 0:
528 mbc7->writable = false;
529 mbc7->state = GBMBC7_STATE_NULL;
530 break;
531 case 1:
532 mbc7->state = GBMBC7_STATE_WRITE;
533 if (mbc7->writable) {
534 int i;
535 for (i = 0; i < 256; ++i) {
536 memory->sramBank[i * 2] = mbc7->sr >> 8;
537 memory->sramBank[i * 2 + 1] = mbc7->sr;
538 }
539 }
540 break;
541 case 2:
542 mbc7->state = GBMBC7_STATE_WRITE;
543 if (mbc7->writable) {
544 int i;
545 for (i = 0; i < 256; ++i) {
546 memory->sramBank[i * 2] = 0xFF;
547 memory->sramBank[i * 2 + 1] = 0xFF;
548 }
549 }
550 break;
551 case 3:
552 mbc7->writable = true;
553 mbc7->state = GBMBC7_STATE_NULL;
554 break;
555 }
556 }
557 break;
558 case GBMBC7_STATE_COMMAND_SR_WRITE:
559 if (mbc7->srBits == 16) {
560 mbc7->srBits = 0;
561 mbc7->state = GBMBC7_STATE_WRITE;
562 }
563 break;
564 case GBMBC7_STATE_COMMAND_SR_READ:
565 if (mbc7->srBits == 1) {
566 mbc7->sr = memory->sramBank[mbc7->address * 2] << 8;
567 mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1];
568 mbc7->srBits = 0;
569 mbc7->state = GBMBC7_STATE_READ;
570 }
571 break;
572 case GBMBC7_STATE_COMMAND_SR_FILL:
573 if (mbc7->srBits == 16) {
574 mbc7->sr = 0xFFFF;
575 mbc7->srBits = 0;
576 mbc7->state = GBMBC7_STATE_WRITE;
577 }
578 break;
579 default:
580 break;
581 }
582 } else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) {
583 if (mbc7->state == GBMBC7_STATE_READ) {
584 mbc7->sr <<= 1;
585 ++mbc7->srBits;
586 if (mbc7->srBits == 16) {
587 mbc7->srBits = 0;
588 mbc7->state = GBMBC7_STATE_NULL;
589 }
590 }
591 }
592}
593
594void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) {
595 struct GBMemory* memory = &gb->memory;
596 int bank = value & 0x3F;
597 if (address & 0x1FFF) {
598 mLOG(GB_MBC, STUB, "HuC-3 unknown value %04X:%02X", address, value);
599 }
600
601 switch (address >> 13) {
602 case 0x0:
603 switch (value) {
604 case 0xA:
605 memory->sramAccess = true;
606 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
607 break;
608 default:
609 memory->sramAccess = false;
610 break;
611 }
612 break;
613 case 0x1:
614 GBMBCSwitchBank(memory, bank);
615 break;
616 case 0x2:
617 GBMBCSwitchSramBank(gb, bank);
618 break;
619 default:
620 // TODO
621 mLOG(GB_MBC, STUB, "HuC-3 unknown address: %04X:%02X", address, value);
622 break;
623 }
624}
625
626void GBMBCRTCRead(struct GB* gb) {
627 struct GBMBCRTCSaveBuffer rtcBuffer;
628 struct VFile* vf = gb->sramVf;
629 ssize_t end = vf->seek(vf, -sizeof(rtcBuffer), SEEK_END);
630 switch (end & 0x1FFF) {
631 case 0:
632 break;
633 case 0x1FFC:
634 vf->seek(vf, -sizeof(rtcBuffer) - 4, SEEK_END);
635 break;
636 default:
637 return;
638 }
639 vf->read(vf, &rtcBuffer, sizeof(rtcBuffer));
640
641 LOAD_32LE(gb->memory.rtcRegs[0], 0, &rtcBuffer.latchedSec);
642 LOAD_32LE(gb->memory.rtcRegs[1], 0, &rtcBuffer.latchedMin);
643 LOAD_32LE(gb->memory.rtcRegs[2], 0, &rtcBuffer.latchedHour);
644 LOAD_32LE(gb->memory.rtcRegs[3], 0, &rtcBuffer.latchedDays);
645 LOAD_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
646 LOAD_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime);
647}
648
649void GBMBCRTCWrite(struct GB* gb) {
650 uint8_t rtcRegs[5];
651 memcpy(rtcRegs, gb->memory.rtcRegs, sizeof(rtcRegs));
652 time_t rtcLastLatch = gb->memory.rtcLastLatch;
653 _latchRtc(gb->memory.rtc, rtcRegs, &rtcLastLatch);
654
655 struct GBMBCRTCSaveBuffer rtcBuffer;
656 STORE_32LE(rtcRegs[0], 0, &rtcBuffer.sec);
657 STORE_32LE(rtcRegs[1], 0, &rtcBuffer.min);
658 STORE_32LE(rtcRegs[2], 0, &rtcBuffer.hour);
659 STORE_32LE(rtcRegs[3], 0, &rtcBuffer.days);
660 STORE_32LE(rtcRegs[4], 0, &rtcBuffer.daysHi);
661 STORE_32LE(gb->memory.rtcRegs[0], 0, &rtcBuffer.latchedSec);
662 STORE_32LE(gb->memory.rtcRegs[1], 0, &rtcBuffer.latchedMin);
663 STORE_32LE(gb->memory.rtcRegs[2], 0, &rtcBuffer.latchedHour);
664 STORE_32LE(gb->memory.rtcRegs[3], 0, &rtcBuffer.latchedDays);
665 STORE_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
666 STORE_64LE(rtcLastLatch, 0, &rtcBuffer.unixTime);
667
668 struct VFile* vf = gb->sramVf;
669 vf->seek(vf, gb->sramSize, SEEK_SET);
670 vf->write(vf, &rtcBuffer, sizeof(rtcBuffer));
671}