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