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