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