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 <mgba/internal/gb/mbc.h>
7
8#include <mgba/core/interface.h>
9#include <mgba/internal/sm83/sm83.h>
10#include <mgba/internal/gb/gb.h>
11#include <mgba/internal/gb/memory.h>
12#include <mgba-util/crc32.h>
13#include <mgba-util/vfs.h>
14
15const uint32_t GB_LOGO_HASH = 0x46195417;
16
17mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC", "gb.mbc");
18
19static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) {
20 UNUSED(gb);
21 UNUSED(address);
22 UNUSED(value);
23
24 mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC");
25}
26
27static void _GBMBC1(struct GB*, uint16_t address, uint8_t value);
28static void _GBMBC2(struct GB*, uint16_t address, uint8_t value);
29static void _GBMBC3(struct GB*, uint16_t address, uint8_t value);
30static void _GBMBC5(struct GB*, uint16_t address, uint8_t value);
31static void _GBMBC6(struct GB*, uint16_t address, uint8_t value);
32static void _GBMBC7(struct GB*, uint16_t address, uint8_t value);
33static void _GBMMM01(struct GB*, uint16_t address, uint8_t value);
34static void _GBHuC1(struct GB*, uint16_t address, uint8_t value);
35static void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
36static void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);
37static void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value);
38static void _GBWisdomTree(struct GB* gb, uint16_t address, uint8_t value);
39static void _GBPKJD(struct GB* gb, uint16_t address, uint8_t value);
40static void _GBBBD(struct GB* gb, uint16_t address, uint8_t value);
41static void _GBHitek(struct GB* gb, uint16_t address, uint8_t value);
42
43static uint8_t _GBMBC2Read(struct GBMemory*, uint16_t address);
44static uint8_t _GBMBC6Read(struct GBMemory*, uint16_t address);
45static uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address);
46static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value);
47
48static uint8_t _GBTAMA5Read(struct GBMemory*, uint16_t address);
49static uint8_t _GBPKJDRead(struct GBMemory*, uint16_t address);
50static uint8_t _GBBBDRead(struct GBMemory*, uint16_t address);
51static uint8_t _GBHitekRead(struct GBMemory*, uint16_t address);
52
53static uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address);
54static void _GBPocketCamCapture(struct GBMemory*);
55
56void GBMBCSwitchBank(struct GB* gb, int bank) {
57 size_t bankStart = bank * GB_SIZE_CART_BANK0;
58 if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) {
59 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
60 bankStart &= (gb->memory.romSize - 1);
61 bank = bankStart / GB_SIZE_CART_BANK0;
62 }
63 gb->memory.romBank = &gb->memory.rom[bankStart];
64 gb->memory.currentBank = bank;
65 if (gb->cpu->pc < GB_BASE_VRAM) {
66 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
67 }
68}
69
70void GBMBCSwitchBank0(struct GB* gb, int bank) {
71 size_t bankStart = bank * GB_SIZE_CART_BANK0;
72 if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) {
73 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
74 bankStart &= (gb->memory.romSize - 1);
75 }
76 gb->memory.romBase = &gb->memory.rom[bankStart];
77 if (gb->cpu->pc < GB_SIZE_CART_BANK0) {
78 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
79 }
80}
81
82void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank) {
83 size_t bankStart = bank * GB_SIZE_CART_HALFBANK;
84 if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) {
85 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
86 bankStart &= (gb->memory.romSize - 1);
87 bank = bankStart / GB_SIZE_CART_HALFBANK;
88 if (!bank) {
89 ++bank;
90 }
91 }
92 if (!half) {
93 gb->memory.romBank = &gb->memory.rom[bankStart];
94 gb->memory.currentBank = bank;
95 } else {
96 gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart];
97 gb->memory.mbcState.mbc6.currentBank1 = bank;
98 }
99 if (gb->cpu->pc < GB_BASE_VRAM) {
100 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
101 }
102}
103
104static bool _isMulticart(const uint8_t* mem) {
105 bool success;
106 struct VFile* vf;
107
108 vf = VFileFromConstMemory(&mem[GB_SIZE_CART_BANK0 * 0x10], 1024);
109 success = GBIsROM(vf);
110 vf->close(vf);
111
112 if (!success) {
113 return false;
114 }
115
116 vf = VFileFromConstMemory(&mem[GB_SIZE_CART_BANK0 * 0x20], 1024);
117 success = GBIsROM(vf);
118 vf->close(vf);
119
120 if (!success) {
121 vf = VFileFromConstMemory(&mem[GB_SIZE_CART_BANK0 * 0x30], 1024);
122 success = GBIsROM(vf);
123 vf->close(vf);
124 }
125
126 return success;
127}
128
129static bool _isWisdomTree(const uint8_t* mem, size_t size) {
130 size_t i;
131 for (i = 0x134; i < 0x14C; i += 4) {
132 if (*(uint32_t*) &mem[i] != 0) {
133 return false;
134 }
135 }
136 for (i = 0xF0; i < 0x100; i += 4) {
137 if (*(uint32_t*) &mem[i] != 0) {
138 return false;
139 }
140 }
141 if (mem[0x14D] != 0xE7) {
142 return false;
143 }
144 for (i = 0x300; i < size - 11; ++i) {
145 if (memcmp(&mem[i], "WISDOM", 6) == 0 && memcmp(&mem[i + 7], "TREE", 4) == 0) {
146 return true;
147 }
148 }
149 return false;
150}
151
152static enum GBMemoryBankControllerType _detectUnlMBC(const uint8_t* mem, size_t size) {
153 const struct GBCartridge* cart = (const struct GBCartridge*) &mem[0x100];
154
155 switch (cart->type) {
156 case 0:
157 if (_isWisdomTree(mem, size)) {
158 return GB_UNL_WISDOM_TREE;
159 }
160 break;
161 }
162
163 uint32_t secondaryLogo = doCrc32(&mem[0x184], 0x30);
164 switch (secondaryLogo) {
165 case 0x4fdab691:
166 return GB_UNL_HITEK;
167 case 0xc7d8c1df:
168 case 0x6d1ea662: // Garou
169 if (mem[0x7FFF] != 0x01) { // Make sure we're not using a "fixed" version
170 return GB_UNL_BBD;
171 }
172 }
173
174 return GB_MBC_AUTODETECT;
175}
176
177void GBMBCSwitchSramBank(struct GB* gb, int bank) {
178 size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
179 if (bankStart + GB_SIZE_EXTERNAL_RAM > gb->sramSize) {
180 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid RAM bank: %0X", bank);
181 bankStart &= (gb->sramSize - 1);
182 bank = bankStart / GB_SIZE_EXTERNAL_RAM;
183 }
184 gb->memory.sramBank = &gb->memory.sram[bankStart];
185 gb->memory.sramCurrentBank = bank;
186}
187
188void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank) {
189 size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM_HALFBANK;
190 if (bankStart + GB_SIZE_EXTERNAL_RAM_HALFBANK > gb->sramSize) {
191 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid RAM bank: %0X", bank);
192 bankStart &= (gb->sramSize - 1);
193 bank = bankStart / GB_SIZE_EXTERNAL_RAM_HALFBANK;
194 }
195 if (!half) {
196 gb->memory.sramBank = &gb->memory.sram[bankStart];
197 gb->memory.sramCurrentBank = bank;
198 } else {
199 gb->memory.mbcState.mbc6.sramBank1 = &gb->memory.sram[bankStart];
200 gb->memory.mbcState.mbc6.currentSramBank1 = bank;
201 }
202}
203
204void GBMBCInit(struct GB* gb) {
205 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
206 if (gb->memory.rom) {
207 if (gb->memory.romSize >= 0x8000) {
208 const struct GBCartridge* cartFooter = (const struct GBCartridge*) &gb->memory.rom[gb->memory.romSize - 0x7F00];
209 if (doCrc32(cartFooter->logo, sizeof(cartFooter->logo)) == GB_LOGO_HASH && cartFooter->type >= 0x0B && cartFooter->type <= 0x0D) {
210 cart = cartFooter;
211 }
212 }
213 switch (cart->ramSize) {
214 case 0:
215 gb->sramSize = 0;
216 break;
217 case 1:
218 gb->sramSize = 0x800;
219 break;
220 default:
221 case 2:
222 gb->sramSize = 0x2000;
223 break;
224 case 3:
225 gb->sramSize = 0x8000;
226 break;
227 case 4:
228 gb->sramSize = 0x20000;
229 break;
230 case 5:
231 gb->sramSize = 0x10000;
232 break;
233 }
234 if (gb->memory.mbcType == GB_MBC_AUTODETECT) {
235 gb->memory.mbcType = _detectUnlMBC(gb->memory.rom, gb->memory.romSize);
236 }
237
238 if (gb->memory.mbcType == GB_MBC_AUTODETECT) {
239 switch (cart->type) {
240 case 0:
241 case 8:
242 case 9:
243 gb->memory.mbcType = GB_MBC_NONE;
244 break;
245 case 1:
246 case 2:
247 case 3:
248 gb->memory.mbcType = GB_MBC1;
249 break;
250 case 5:
251 case 6:
252 gb->memory.mbcType = GB_MBC2;
253 break;
254 case 0x0B:
255 case 0x0C:
256 case 0x0D:
257 gb->memory.mbcType = GB_MMM01;
258 break;
259 case 0x0F:
260 case 0x10:
261 gb->memory.mbcType = GB_MBC3_RTC;
262 break;
263 case 0x11:
264 case 0x12:
265 case 0x13:
266 gb->memory.mbcType = GB_MBC3;
267 break;
268 default:
269 mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
270 // Fall through
271 case 0x19:
272 case 0x1A:
273 case 0x1B:
274 gb->memory.mbcType = GB_MBC5;
275 break;
276 case 0x1C:
277 case 0x1D:
278 case 0x1E:
279 gb->memory.mbcType = GB_MBC5_RUMBLE;
280 break;
281 case 0x20:
282 gb->memory.mbcType = GB_MBC6;
283 break;
284 case 0x22:
285 gb->memory.mbcType = GB_MBC7;
286 break;
287 case 0xFC:
288 gb->memory.mbcType = GB_POCKETCAM;
289 break;
290 case 0xFD:
291 gb->memory.mbcType = GB_TAMA5;
292 break;
293 case 0xFE:
294 gb->memory.mbcType = GB_HuC3;
295 break;
296 case 0xFF:
297 gb->memory.mbcType = GB_HuC1;
298 break;
299 }
300 }
301 } else {
302 gb->memory.mbcType = GB_MBC_NONE;
303 }
304 gb->memory.mbcRead = NULL;
305 gb->memory.directSramAccess = true;
306 switch (gb->memory.mbcType) {
307 case GB_MBC_NONE:
308 gb->memory.mbcWrite = _GBMBCNone;
309 break;
310 case GB_MBC1:
311 gb->memory.mbcWrite = _GBMBC1;
312 if (gb->memory.romSize >= GB_SIZE_CART_BANK0 * 0x31 && _isMulticart(gb->memory.rom)) {
313 gb->memory.mbcState.mbc1.multicartStride = 4;
314 } else {
315 gb->memory.mbcState.mbc1.multicartStride = 5;
316 }
317 break;
318 case GB_MBC2:
319 gb->memory.mbcWrite = _GBMBC2;
320 gb->memory.mbcRead = _GBMBC2Read;
321 gb->memory.directSramAccess = false;
322 gb->sramSize = 0x100;
323 break;
324 case GB_MBC3:
325 gb->memory.mbcWrite = _GBMBC3;
326 break;
327 default:
328 mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
329 // Fall through
330 case GB_MBC5:
331 gb->memory.mbcWrite = _GBMBC5;
332 break;
333 case GB_MBC6:
334 gb->memory.mbcWrite = _GBMBC6;
335 gb->memory.mbcRead = _GBMBC6Read;
336 gb->memory.directSramAccess = false;
337 break;
338 case GB_MBC7:
339 gb->memory.mbcWrite = _GBMBC7;
340 gb->memory.mbcRead = _GBMBC7Read;
341 gb->sramSize = 0x100;
342 break;
343 case GB_MMM01:
344 gb->memory.mbcWrite = _GBMMM01;
345 break;
346 case GB_HuC1:
347 gb->memory.mbcWrite = _GBHuC1;
348 break;
349 case GB_HuC3:
350 gb->memory.mbcWrite = _GBHuC3;
351 break;
352 case GB_TAMA5:
353 mLOG(GB_MBC, WARN, "unimplemented MBC: TAMA5");
354 memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
355 gb->memory.mbcWrite = _GBTAMA5;
356 gb->memory.mbcRead = _GBTAMA5Read;
357 gb->sramSize = 0x20;
358 break;
359 case GB_MBC3_RTC:
360 memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
361 gb->memory.mbcWrite = _GBMBC3;
362 break;
363 case GB_MBC5_RUMBLE:
364 gb->memory.mbcWrite = _GBMBC5;
365 break;
366 case GB_POCKETCAM:
367 gb->memory.mbcWrite = _GBPocketCam;
368 gb->memory.mbcRead = _GBPocketCamRead;
369 if (gb->memory.cam && gb->memory.cam->startRequestImage) {
370 gb->memory.cam->startRequestImage(gb->memory.cam, GBCAM_WIDTH, GBCAM_HEIGHT, mCOLOR_ANY);
371 }
372 break;
373 case GB_UNL_WISDOM_TREE:
374 gb->memory.mbcWrite = _GBWisdomTree;
375 break;
376 case GB_UNL_BBD:
377 gb->memory.mbcWrite = _GBBBD;
378 gb->memory.mbcRead = _GBBBDRead;
379 break;
380 case GB_UNL_HITEK:
381 gb->memory.mbcWrite = _GBHitek;
382 gb->memory.mbcRead = _GBHitekRead;
383 gb->memory.mbcState.bbd.dataSwapMode = 7;
384 gb->memory.mbcState.bbd.bankSwapMode = 7;
385 break;
386 case GB_UNL_PKJD:
387 gb->memory.mbcWrite = _GBPKJD;
388 gb->memory.mbcRead = _GBPKJDRead;
389 break;
390 }
391
392 gb->memory.currentBank = 1;
393 gb->memory.sramCurrentBank = 0;
394 gb->memory.sramAccess = false;
395 gb->memory.rtcAccess = false;
396 gb->memory.activeRtcReg = 0;
397 gb->memory.rtcLatched = false;
398 gb->memory.rtcLastLatch = 0;
399 if (gb->memory.rtc) {
400 if (gb->memory.rtc->sample) {
401 gb->memory.rtc->sample(gb->memory.rtc);
402 }
403 gb->memory.rtcLastLatch = gb->memory.rtc->unixTime(gb->memory.rtc);
404 } else {
405 gb->memory.rtcLastLatch = time(0);
406 }
407 memset(&gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
408
409 GBResizeSram(gb, gb->sramSize);
410
411 if (gb->memory.mbcType == GB_MBC3_RTC) {
412 GBMBCRTCRead(gb);
413 }
414}
415
416static void _latchRtc(struct mRTCSource* rtc, uint8_t* rtcRegs, time_t* rtcLastLatch) {
417 time_t t;
418 if (rtc) {
419 if (rtc->sample) {
420 rtc->sample(rtc);
421 }
422 t = rtc->unixTime(rtc);
423 } else {
424 t = time(0);
425 }
426 time_t currentLatch = t;
427 t -= *rtcLastLatch;
428 *rtcLastLatch = currentLatch;
429
430 int64_t diff;
431 diff = rtcRegs[0] + t % 60;
432 if (diff < 0) {
433 diff += 60;
434 t -= 60;
435 }
436 rtcRegs[0] = diff % 60;
437 t /= 60;
438 t += diff / 60;
439
440 diff = rtcRegs[1] + t % 60;
441 if (diff < 0) {
442 diff += 60;
443 t -= 60;
444 }
445 rtcRegs[1] = diff % 60;
446 t /= 60;
447 t += diff / 60;
448
449 diff = rtcRegs[2] + t % 24;
450 if (diff < 0) {
451 diff += 24;
452 t -= 24;
453 }
454 rtcRegs[2] = diff % 24;
455 t /= 24;
456 t += diff / 24;
457
458 diff = rtcRegs[3] + ((rtcRegs[4] & 1) << 8) + (t & 0x1FF);
459 rtcRegs[3] = diff;
460 rtcRegs[4] &= 0xFE;
461 rtcRegs[4] |= (diff >> 8) & 1;
462 if (diff & 0x200) {
463 rtcRegs[4] |= 0x80;
464 }
465}
466
467static void _GBMBC1Update(struct GB* gb) {
468 struct GBMBC1State* state = &gb->memory.mbcState.mbc1;
469 int bank = state->bankLo;
470 bank &= (1 << state->multicartStride) - 1;
471 bank |= state->bankHi << state->multicartStride;
472 if (state->mode) {
473 GBMBCSwitchBank0(gb, state->bankHi << state->multicartStride);
474 GBMBCSwitchSramBank(gb, state->bankHi & 3);
475 } else {
476 GBMBCSwitchBank0(gb, 0);
477 GBMBCSwitchSramBank(gb, 0);
478 }
479 if (!(state->bankLo & 0x1F)) {
480 ++state->bankLo;
481 ++bank;
482 }
483 GBMBCSwitchBank(gb, bank);
484}
485
486void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
487 struct GBMemory* memory = &gb->memory;
488 int bank = value & 0x1F;
489 switch (address >> 13) {
490 case 0x0:
491 switch (value & 0xF) {
492 case 0:
493 memory->sramAccess = false;
494 break;
495 case 0xA:
496 memory->sramAccess = true;
497 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
498 break;
499 default:
500 // TODO
501 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
502 break;
503 }
504 break;
505 case 0x1:
506 memory->mbcState.mbc1.bankLo = bank;
507 _GBMBC1Update(gb);
508 break;
509 case 0x2:
510 bank &= 3;
511 memory->mbcState.mbc1.bankHi = bank;
512 _GBMBC1Update(gb);
513 break;
514 case 0x3:
515 memory->mbcState.mbc1.mode = value & 1;
516 _GBMBC1Update(gb);
517 break;
518 default:
519 // TODO
520 mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
521 break;
522 }
523}
524
525void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
526 struct GBMemory* memory = &gb->memory;
527 int shift = (address & 1) * 4;
528 int bank = value & 0xF;
529 switch ((address & 0xC100) >> 8) {
530 case 0x0:
531 switch (value & 0x0F) {
532 case 0:
533 memory->sramAccess = false;
534 break;
535 case 0xA:
536 memory->sramAccess = true;
537 break;
538 default:
539 // TODO
540 mLOG(GB_MBC, STUB, "MBC2 unknown value %02X", value);
541 break;
542 }
543 break;
544 case 0x1:
545 if (!bank) {
546 ++bank;
547 }
548 GBMBCSwitchBank(gb, bank);
549 break;
550 case 0x80:
551 case 0x81:
552 case 0x82:
553 case 0x83:
554 if (!memory->sramAccess) {
555 return;
556 }
557 address &= 0x1FF;
558 memory->sramBank[(address >> 1)] &= 0xF0 >> shift;
559 memory->sramBank[(address >> 1)] |= (value & 0xF) << shift;
560 break;
561 default:
562 // TODO
563 mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
564 break;
565 }
566}
567
568static uint8_t _GBMBC2Read(struct GBMemory* memory, uint16_t address) {
569 if (!memory->sramAccess) {
570 return 0xFF;
571 }
572 address &= 0x1FF;
573 int shift = (address & 1) * 4;
574 return (memory->sramBank[(address >> 1)] >> shift) | 0xF0;
575}
576
577void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
578 struct GBMemory* memory = &gb->memory;
579 int bank = value;
580 switch (address >> 13) {
581 case 0x0:
582 switch (value) {
583 case 0:
584 memory->sramAccess = false;
585 break;
586 case 0xA:
587 memory->sramAccess = true;
588 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
589 break;
590 default:
591 // TODO
592 mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
593 break;
594 }
595 break;
596 case 0x1:
597 if (gb->memory.romSize < GB_SIZE_CART_BANK0 * 0x80) {
598 bank &= 0x7F;
599 }
600 if (!bank) {
601 ++bank;
602 }
603 GBMBCSwitchBank(gb, bank);
604 break;
605 case 0x2:
606 if (value < 8) {
607 GBMBCSwitchSramBank(gb, value);
608 memory->rtcAccess = false;
609 } else if (value <= 0xC) {
610 memory->activeRtcReg = value - 8;
611 memory->rtcAccess = true;
612 }
613 break;
614 case 0x3:
615 if (memory->rtcLatched && value == 0) {
616 memory->rtcLatched = false;
617 } else if (!memory->rtcLatched && value == 1) {
618 _latchRtc(gb->memory.rtc, gb->memory.rtcRegs, &gb->memory.rtcLastLatch);
619 memory->rtcLatched = true;
620 }
621 break;
622 }
623}
624
625void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
626 struct GBMemory* memory = &gb->memory;
627 int bank;
628 switch (address >> 12) {
629 case 0x0:
630 case 0x1:
631 switch (value) {
632 case 0:
633 memory->sramAccess = false;
634 break;
635 case 0xA:
636 memory->sramAccess = true;
637 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
638 break;
639 default:
640 // TODO
641 mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
642 break;
643 }
644 break;
645 case 0x2:
646 bank = (memory->currentBank & 0x100) | value;
647 GBMBCSwitchBank(gb, bank);
648 break;
649 case 0x3:
650 bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
651 GBMBCSwitchBank(gb, bank);
652 break;
653 case 0x4:
654 case 0x5:
655 if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) {
656 memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
657 value &= ~8;
658 }
659 GBMBCSwitchSramBank(gb, value & 0xF);
660 break;
661 default:
662 // TODO
663 mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
664 break;
665 }
666}
667
668void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
669 struct GBMemory* memory = &gb->memory;
670 int bank = value;
671 switch (address >> 10) {
672 case 0:
673 switch (value) {
674 case 0:
675 memory->sramAccess = false;
676 break;
677 case 0xA:
678 memory->sramAccess = true;
679 break;
680 default:
681 // TODO
682 mLOG(GB_MBC, STUB, "MBC6 unknown value %02X", value);
683 break;
684 }
685 break;
686 case 0x1:
687 GBMBCSwitchSramHalfBank(gb, 0, bank);
688 break;
689 case 0x2:
690 GBMBCSwitchSramHalfBank(gb, 1, bank);
691 break;
692 case 0x8:
693 case 0x9:
694 GBMBCSwitchHalfBank(gb, 0, bank);
695 break;
696 case 0xC:
697 case 0xD:
698 GBMBCSwitchHalfBank(gb, 1, bank);
699 break;
700 case 0x28:
701 case 0x29:
702 case 0x2A:
703 case 0x2B:
704 if (memory->sramAccess) {
705 memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value;
706 }
707 break;
708 case 0x2C:
709 case 0x2D:
710 case 0x2E:
711 case 0x2F:
712 if (memory->sramAccess) {
713 memory->mbcState.mbc6.sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value;
714 }
715 break;
716 default:
717 mLOG(GB_MBC, STUB, "MBC6 unknown address: %04X:%02X", address, value);
718 break;
719 }
720}
721
722uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) {
723 if (!memory->sramAccess) {
724 return 0xFF;
725 }
726 switch (address >> 12) {
727 case 0xA:
728 return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)];
729 case 0xB:
730 return memory->mbcState.mbc6.sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)];
731 }
732 return 0xFF;
733}
734
735void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
736 int bank = value & 0x7F;
737 switch (address >> 13) {
738 case 0x0:
739 switch (value) {
740 default:
741 case 0:
742 gb->memory.mbcState.mbc7.access = 0;
743 break;
744 case 0xA:
745 gb->memory.mbcState.mbc7.access |= 1;
746 break;
747 }
748 break;
749 case 0x1:
750 GBMBCSwitchBank(gb, bank);
751 break;
752 case 0x2:
753 if (value == 0x40) {
754 gb->memory.mbcState.mbc7.access |= 2;
755 } else {
756 gb->memory.mbcState.mbc7.access &= ~2;
757 }
758 break;
759 case 0x5:
760 _GBMBC7Write(&gb->memory, address, value);
761 break;
762 default:
763 // TODO
764 mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
765 break;
766 }
767}
768
769uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) {
770 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
771 if (mbc7->access != 3) {
772 return 0xFF;
773 }
774 switch (address & 0xF0) {
775 case 0x20:
776 if (memory->rotation && memory->rotation->readTiltX) {
777 int32_t x = -memory->rotation->readTiltX(memory->rotation);
778 x >>= 21;
779 x += 0x81D0;
780 return x;
781 }
782 return 0xFF;
783 case 0x30:
784 if (memory->rotation && memory->rotation->readTiltX) {
785 int32_t x = -memory->rotation->readTiltX(memory->rotation);
786 x >>= 21;
787 x += 0x81D0;
788 return x >> 8;
789 }
790 return 7;
791 case 0x40:
792 if (memory->rotation && memory->rotation->readTiltY) {
793 int32_t y = -memory->rotation->readTiltY(memory->rotation);
794 y >>= 21;
795 y += 0x81D0;
796 return y;
797 }
798 return 0xFF;
799 case 0x50:
800 if (memory->rotation && memory->rotation->readTiltY) {
801 int32_t y = -memory->rotation->readTiltY(memory->rotation);
802 y >>= 21;
803 y += 0x81D0;
804 return y >> 8;
805 }
806 return 7;
807 case 0x60:
808 return 0;
809 case 0x80:
810 return mbc7->eeprom;
811 default:
812 return 0xFF;
813 }
814}
815
816static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
817 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
818 if (mbc7->access != 3) {
819 return;
820 }
821 switch (address & 0xF0) {
822 case 0x00:
823 mbc7->latch = (value & 0x55) == 0x55;
824 return;
825 case 0x10:
826 mbc7->latch |= (value & 0xAA);
827 if (mbc7->latch == 0xAB && memory->rotation && memory->rotation->sample) {
828 memory->rotation->sample(memory->rotation);
829 }
830 mbc7->latch = 0;
831 return;
832 default:
833 mLOG(GB_MBC, STUB, "MBC7 unknown register: %04X:%02X", address, value);
834 return;
835 case 0x80:
836 break;
837 }
838 GBMBC7Field old = memory->mbcState.mbc7.eeprom;
839 value = GBMBC7FieldFillDO(value); // Hi-Z
840 if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
841 mbc7->state = GBMBC7_STATE_IDLE;
842 }
843 if (!GBMBC7FieldIsCLK(old) && GBMBC7FieldIsCLK(value)) {
844 if (mbc7->state == GBMBC7_STATE_READ_COMMAND || mbc7->state == GBMBC7_STATE_EEPROM_WRITE || mbc7->state == GBMBC7_STATE_EEPROM_WRAL) {
845 mbc7->sr <<= 1;
846 mbc7->sr |= GBMBC7FieldGetDI(value);
847 ++mbc7->srBits;
848 }
849 switch (mbc7->state) {
850 case GBMBC7_STATE_IDLE:
851 if (GBMBC7FieldIsDI(value)) {
852 mbc7->state = GBMBC7_STATE_READ_COMMAND;
853 mbc7->srBits = 0;
854 mbc7->sr = 0;
855 }
856 break;
857 case GBMBC7_STATE_READ_COMMAND:
858 if (mbc7->srBits == 10) {
859 mbc7->state = 0x10 | (mbc7->sr >> 6);
860 if (mbc7->state & 0xC) {
861 mbc7->state &= ~0x3;
862 }
863 mbc7->srBits = 0;
864 mbc7->address = mbc7->sr & 0x7F;
865 }
866 break;
867 case GBMBC7_STATE_DO:
868 value = GBMBC7FieldSetDO(value, mbc7->sr >> 15);
869 mbc7->sr <<= 1;
870 --mbc7->srBits;
871 if (!mbc7->srBits) {
872 mbc7->state = GBMBC7_STATE_IDLE;
873 }
874 break;
875 default:
876 break;
877 }
878 switch (mbc7->state) {
879 case GBMBC7_STATE_EEPROM_EWEN:
880 mbc7->writable = true;
881 mbc7->state = GBMBC7_STATE_IDLE;
882 break;
883 case GBMBC7_STATE_EEPROM_EWDS:
884 mbc7->writable = false;
885 mbc7->state = GBMBC7_STATE_IDLE;
886 break;
887 case GBMBC7_STATE_EEPROM_WRITE:
888 if (mbc7->srBits == 16) {
889 if (mbc7->writable) {
890 memory->sram[mbc7->address * 2] = mbc7->sr >> 8;
891 memory->sram[mbc7->address * 2 + 1] = mbc7->sr;
892 }
893 mbc7->state = GBMBC7_STATE_IDLE;
894 }
895 break;
896 case GBMBC7_STATE_EEPROM_ERASE:
897 if (mbc7->writable) {
898 memory->sram[mbc7->address * 2] = 0xFF;
899 memory->sram[mbc7->address * 2 + 1] = 0xFF;
900 }
901 mbc7->state = GBMBC7_STATE_IDLE;
902 break;
903 case GBMBC7_STATE_EEPROM_READ:
904 mbc7->srBits = 16;
905 mbc7->sr = memory->sram[mbc7->address * 2] << 8;
906 mbc7->sr |= memory->sram[mbc7->address * 2 + 1];
907 mbc7->state = GBMBC7_STATE_DO;
908 value = GBMBC7FieldClearDO(value);
909 break;
910 case GBMBC7_STATE_EEPROM_WRAL:
911 if (mbc7->srBits == 16) {
912 if (mbc7->writable) {
913 int i;
914 for (i = 0; i < 128; ++i) {
915 memory->sram[i * 2] = mbc7->sr >> 8;
916 memory->sram[i * 2 + 1] = mbc7->sr;
917 }
918 }
919 mbc7->state = GBMBC7_STATE_IDLE;
920 }
921 break;
922 case GBMBC7_STATE_EEPROM_ERAL:
923 if (mbc7->writable) {
924 int i;
925 for (i = 0; i < 128; ++i) {
926 memory->sram[i * 2] = 0xFF;
927 memory->sram[i * 2 + 1] = 0xFF;
928 }
929 }
930 mbc7->state = GBMBC7_STATE_IDLE;
931 break;
932 default:
933 break;
934 }
935 } else if (GBMBC7FieldIsCS(value) && GBMBC7FieldIsCLK(old) && !GBMBC7FieldIsCLK(value)) {
936 value = GBMBC7FieldSetDO(value, GBMBC7FieldGetDO(old));
937 }
938 mbc7->eeprom = value;
939}
940
941void _GBMMM01(struct GB* gb, uint16_t address, uint8_t value) {
942 struct GBMemory* memory = &gb->memory;
943 if (!memory->mbcState.mmm01.locked) {
944 switch (address >> 13) {
945 case 0x0:
946 memory->mbcState.mmm01.locked = true;
947 GBMBCSwitchBank0(gb, memory->mbcState.mmm01.currentBank0);
948 break;
949 case 0x1:
950 memory->mbcState.mmm01.currentBank0 &= ~0x7F;
951 memory->mbcState.mmm01.currentBank0 |= value & 0x7F;
952 break;
953 case 0x2:
954 memory->mbcState.mmm01.currentBank0 &= ~0x180;
955 memory->mbcState.mmm01.currentBank0 |= (value & 0x30) << 3;
956 break;
957 default:
958 // TODO
959 mLOG(GB_MBC, STUB, "MMM01 unknown address: %04X:%02X", address, value);
960 break;
961 }
962 return;
963 }
964 switch (address >> 13) {
965 case 0x0:
966 switch (value) {
967 case 0xA:
968 memory->sramAccess = true;
969 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
970 break;
971 default:
972 memory->sramAccess = false;
973 break;
974 }
975 break;
976 case 0x1:
977 GBMBCSwitchBank(gb, value + memory->mbcState.mmm01.currentBank0);
978 break;
979 case 0x2:
980 GBMBCSwitchSramBank(gb, value);
981 break;
982 default:
983 // TODO
984 mLOG(GB_MBC, STUB, "MMM01 unknown address: %04X:%02X", address, value);
985 break;
986 }
987}
988
989void _GBHuC1(struct GB* gb, uint16_t address, uint8_t value) {
990 struct GBMemory* memory = &gb->memory;
991 int bank = value & 0x3F;
992 switch (address >> 13) {
993 case 0x0:
994 switch (value) {
995 case 0xE:
996 memory->sramAccess = false;
997 break;
998 default:
999 memory->sramAccess = true;
1000 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
1001 break;
1002 }
1003 break;
1004 case 0x1:
1005 GBMBCSwitchBank(gb, bank);
1006 break;
1007 case 0x2:
1008 GBMBCSwitchSramBank(gb, value);
1009 break;
1010 default:
1011 // TODO
1012 mLOG(GB_MBC, STUB, "HuC-1 unknown address: %04X:%02X", address, value);
1013 break;
1014 }
1015}
1016
1017void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) {
1018 struct GBMemory* memory = &gb->memory;
1019 int bank = value & 0x3F;
1020 if (address & 0x1FFF) {
1021 mLOG(GB_MBC, STUB, "HuC-3 unknown value %04X:%02X", address, value);
1022 }
1023
1024 switch (address >> 13) {
1025 case 0x0:
1026 switch (value) {
1027 case 0xA:
1028 memory->sramAccess = true;
1029 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
1030 break;
1031 default:
1032 memory->sramAccess = false;
1033 break;
1034 }
1035 break;
1036 case 0x1:
1037 GBMBCSwitchBank(gb, bank);
1038 break;
1039 case 0x2:
1040 GBMBCSwitchSramBank(gb, bank);
1041 break;
1042 default:
1043 // TODO
1044 mLOG(GB_MBC, STUB, "HuC-3 unknown address: %04X:%02X", address, value);
1045 break;
1046 }
1047}
1048
1049void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value) {
1050 struct GBMemory* memory = &gb->memory;
1051 int bank = value & 0x3F;
1052 switch (address >> 13) {
1053 case 0x0:
1054 switch (value) {
1055 case 0:
1056 memory->sramAccess = false;
1057 break;
1058 case 0xA:
1059 memory->sramAccess = true;
1060 GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
1061 break;
1062 default:
1063 // TODO
1064 mLOG(GB_MBC, STUB, "Pocket Cam unknown value %02X", value);
1065 break;
1066 }
1067 break;
1068 case 0x1:
1069 GBMBCSwitchBank(gb, bank);
1070 break;
1071 case 0x2:
1072 if (value < 0x10) {
1073 GBMBCSwitchSramBank(gb, value);
1074 memory->mbcState.pocketCam.registersActive = false;
1075 } else {
1076 memory->mbcState.pocketCam.registersActive = true;
1077 }
1078 break;
1079 case 0x5:
1080 address &= 0x7F;
1081 if (address == 0 && value & 1) {
1082 value &= 6; // TODO: Timing
1083 _GBPocketCamCapture(memory);
1084 }
1085 if (address < sizeof(memory->mbcState.pocketCam.registers)) {
1086 memory->mbcState.pocketCam.registers[address] = value;
1087 }
1088 break;
1089 default:
1090 mLOG(GB_MBC, STUB, "Pocket Cam unknown address: %04X:%02X", address, value);
1091 break;
1092 }
1093}
1094
1095uint8_t _GBPocketCamRead(struct GBMemory* memory, uint16_t address) {
1096 if (memory->mbcState.pocketCam.registersActive) {
1097 if ((address & 0x7F) == 0) {
1098 return memory->mbcState.pocketCam.registers[0];
1099 }
1100 return 0;
1101 }
1102 return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
1103}
1104
1105void _GBPocketCamCapture(struct GBMemory* memory) {
1106 if (!memory->cam) {
1107 return;
1108 }
1109 const void* image = NULL;
1110 size_t stride;
1111 enum mColorFormat format;
1112 memory->cam->requestImage(memory->cam, &image, &stride, &format);
1113 if (!image) {
1114 return;
1115 }
1116 memset(&memory->sram[0x100], 0, GBCAM_HEIGHT * GBCAM_WIDTH / 4);
1117 struct GBPocketCamState* pocketCam = &memory->mbcState.pocketCam;
1118 size_t x, y;
1119 for (y = 0; y < GBCAM_HEIGHT; ++y) {
1120 for (x = 0; x < GBCAM_WIDTH; ++x) {
1121 uint32_t gray;
1122 uint32_t color;
1123 switch (format) {
1124 case mCOLOR_XBGR8:
1125 case mCOLOR_XRGB8:
1126 case mCOLOR_ARGB8:
1127 case mCOLOR_ABGR8:
1128 color = ((const uint32_t*) image)[y * stride + x];
1129 gray = (color & 0xFF) + ((color >> 8) & 0xFF) + ((color >> 16) & 0xFF);
1130 break;
1131 case mCOLOR_BGRX8:
1132 case mCOLOR_RGBX8:
1133 case mCOLOR_RGBA8:
1134 case mCOLOR_BGRA8:
1135 color = ((const uint32_t*) image)[y * stride + x];
1136 gray = ((color >> 8) & 0xFF) + ((color >> 16) & 0xFF) + ((color >> 24) & 0xFF);
1137 break;
1138 case mCOLOR_BGR5:
1139 case mCOLOR_RGB5:
1140 case mCOLOR_ARGB5:
1141 case mCOLOR_ABGR5:
1142 color = ((const uint16_t*) image)[y * stride + x];
1143 gray = ((color << 3) & 0xF8) + ((color >> 2) & 0xF8) + ((color >> 7) & 0xF8);
1144 break;
1145 case mCOLOR_BGR565:
1146 case mCOLOR_RGB565:
1147 color = ((const uint16_t*) image)[y * stride + x];
1148 gray = ((color << 3) & 0xF8) + ((color >> 3) & 0xFC) + ((color >> 8) & 0xF8);
1149 break;
1150 case mCOLOR_BGRA5:
1151 case mCOLOR_RGBA5:
1152 color = ((const uint16_t*) image)[y * stride + x];
1153 gray = ((color << 2) & 0xF8) + ((color >> 3) & 0xF8) + ((color >> 8) & 0xF8);
1154 break;
1155 default:
1156 mLOG(GB_MBC, WARN, "Unsupported pixel format: %X", format);
1157 return;
1158 }
1159 uint16_t exposure = (pocketCam->registers[2] << 8) | (pocketCam->registers[3]);
1160 gray = (gray + 1) * exposure / 0x300;
1161 // TODO: Additional processing
1162 int matrixEntry = 3 * ((x & 3) + 4 * (y & 3));
1163 if (gray < pocketCam->registers[matrixEntry + 6]) {
1164 gray = 0x101;
1165 } else if (gray < pocketCam->registers[matrixEntry + 7]) {
1166 gray = 0x100;
1167 } else if (gray < pocketCam->registers[matrixEntry + 8]) {
1168 gray = 0x001;
1169 } else {
1170 gray = 0;
1171 }
1172 int coord = (((x >> 3) & 0xF) * 8 + (y & 0x7)) * 2 + (y & ~0x7) * 0x20;
1173 uint16_t existing;
1174 LOAD_16LE(existing, coord + 0x100, memory->sram);
1175 existing |= gray << (7 - (x & 7));
1176 STORE_16LE(existing, coord + 0x100, memory->sram);
1177 }
1178 }
1179}
1180
1181void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value) {
1182 struct GBMemory* memory = &gb->memory;
1183 struct GBTAMA5State* tama5 = &memory->mbcState.tama5;
1184 switch (address >> 13) {
1185 case 0x5:
1186 if (address & 1) {
1187 tama5->reg = value;
1188 } else {
1189 value &= 0xF;
1190 if (tama5->reg < GBTAMA5_MAX) {
1191 tama5->registers[tama5->reg] = value;
1192 uint8_t address = ((tama5->registers[GBTAMA5_CS] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
1193 uint8_t out = (tama5->registers[GBTAMA5_WRITE_HI] << 4) | tama5->registers[GBTAMA5_WRITE_LO];
1194 switch (tama5->reg) {
1195 case GBTAMA5_BANK_LO:
1196 case GBTAMA5_BANK_HI:
1197 GBMBCSwitchBank(gb, tama5->registers[GBTAMA5_BANK_LO] | (tama5->registers[GBTAMA5_BANK_HI] << 4));
1198 break;
1199 case GBTAMA5_WRITE_LO:
1200 case GBTAMA5_WRITE_HI:
1201 case GBTAMA5_CS:
1202 break;
1203 case GBTAMA5_ADDR_LO:
1204 switch (tama5->registers[GBTAMA5_CS] >> 1) {
1205 case 0x0: // RAM write
1206 memory->sram[address] = out;
1207 break;
1208 case 0x1: // RAM read
1209 break;
1210 default:
1211 mLOG(GB_MBC, STUB, "TAMA5 unknown address: %X-%02X:%02X", tama5->registers[GBTAMA5_CS] >> 1, address, out);
1212 }
1213 break;
1214 default:
1215 mLOG(GB_MBC, STUB, "TAMA5 unknown write: %02X:%X", tama5->reg, value);
1216 break;
1217 }
1218 } else {
1219 mLOG(GB_MBC, STUB, "TAMA5 unknown write: %02X", tama5->reg);
1220 }
1221 }
1222 break;
1223 default:
1224 mLOG(GB_MBC, STUB, "TAMA5 unknown address: %04X:%02X", address, value);
1225 }
1226}
1227
1228uint8_t _GBTAMA5Read(struct GBMemory* memory, uint16_t address) {
1229 struct GBTAMA5State* tama5 = &memory->mbcState.tama5;
1230 if ((address & 0x1FFF) > 1) {
1231 mLOG(GB_MBC, STUB, "TAMA5 unknown address: %04X", address);
1232 }
1233 if (address & 1) {
1234 return 0xFF;
1235 } else {
1236 uint8_t value = 0xF0;
1237 uint8_t address = ((tama5->registers[GBTAMA5_CS] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
1238 switch (tama5->reg) {
1239 case GBTAMA5_ACTIVE:
1240 return 0xF1;
1241 case GBTAMA5_READ_LO:
1242 case GBTAMA5_READ_HI:
1243 switch (tama5->registers[GBTAMA5_CS] >> 1) {
1244 case 1:
1245 value = memory->sram[address];
1246 break;
1247 default:
1248 mLOG(GB_MBC, STUB, "TAMA5 unknown read: %02X", tama5->reg);
1249 break;
1250 }
1251 if (tama5->reg == GBTAMA5_READ_HI) {
1252 value >>= 4;
1253 }
1254 value |= 0xF0;
1255 return value;
1256 default:
1257 mLOG(GB_MBC, STUB, "TAMA5 unknown read: %02X", tama5->reg);
1258 return 0xF1;
1259 }
1260 }
1261}
1262
1263void _GBWisdomTree(struct GB* gb, uint16_t address, uint8_t value) {
1264 UNUSED(value);
1265 int bank = address & 0x3F;
1266 switch (address >> 14) {
1267 case 0x0:
1268 GBMBCSwitchBank0(gb, bank * 2);
1269 GBMBCSwitchBank(gb, bank * 2 + 1);
1270 break;
1271 default:
1272 // TODO
1273 mLOG(GB_MBC, STUB, "Wisdom Tree unknown address: %04X:%02X", address, value);
1274 break;
1275 }
1276}
1277
1278void _GBPKJD(struct GB* gb, uint16_t address, uint8_t value) {
1279 struct GBMemory* memory = &gb->memory;
1280 switch (address >> 13) {
1281 case 0x2:
1282 if (value < 8) {
1283 memory->directSramAccess = true;
1284 memory->activeRtcReg = 0;
1285 } else if (value >= 0xD && value <= 0xF) {
1286 memory->directSramAccess = false;
1287 memory->rtcAccess = false;
1288 memory->activeRtcReg = value - 8;
1289 }
1290 break;
1291 case 0x5:
1292 if (!memory->sramAccess) {
1293 return;
1294 }
1295 switch (memory->activeRtcReg) {
1296 case 0:
1297 memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
1298 break;
1299 case 5:
1300 case 6:
1301 memory->mbcState.pkjd.reg[memory->activeRtcReg - 5] = value;
1302 break;
1303 case 7:
1304 switch (value) {
1305 case 0x11:
1306 memory->mbcState.pkjd.reg[0]--;
1307 break;
1308 case 0x12:
1309 memory->mbcState.pkjd.reg[1]--;
1310 break;
1311 case 0x41:
1312 memory->mbcState.pkjd.reg[0] += memory->mbcState.pkjd.reg[1];
1313 break;
1314 case 0x42:
1315 memory->mbcState.pkjd.reg[1] += memory->mbcState.pkjd.reg[0];
1316 break;
1317 case 0x51:
1318 memory->mbcState.pkjd.reg[0]++;
1319 break;
1320 case 0x52:
1321 memory->mbcState.pkjd.reg[1]--;
1322 break;
1323 }
1324 break;
1325 }
1326 return;
1327 }
1328 _GBMBC3(gb, address, value);
1329}
1330
1331static uint8_t _GBPKJDRead(struct GBMemory* memory, uint16_t address) {
1332 if (!memory->sramAccess) {
1333 return 0xFF;
1334 }
1335 switch (memory->activeRtcReg) {
1336 case 0:
1337 return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
1338 case 5:
1339 case 6:
1340 return memory->mbcState.pkjd.reg[memory->activeRtcReg - 5];
1341 default:
1342 return 0;
1343 }
1344}
1345
1346static uint8_t _reorderBits(uint8_t input, const uint8_t* reorder) {
1347 uint8_t newbyte = 0;
1348 int i;
1349 for(i = 0; i < 8; ++i) {
1350 int oldbit = reorder[i];
1351 int newbit = i;
1352 newbyte += ((input >> oldbit) & 1) << newbit;
1353 }
1354
1355 return newbyte;
1356}
1357
1358static const uint8_t _bbdDataReordering[8][8] = {
1359 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00 - Normal
1360 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 01 - NOT KNOWN YET
1361 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 02 - NOT KNOWN YET
1362 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 03 - NOT KNOWN YET
1363 { 0, 5, 1, 3, 4, 2, 6, 7 }, // 04 - Garou
1364 { 0, 4, 2, 3, 1, 5, 6, 7 }, // 05 - Harry
1365 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 06 - NOT KNOWN YET
1366 { 0, 1, 5, 3, 4, 2, 6, 7 }, // 07 - Digimon
1367};
1368
1369static const uint8_t _bbdBankReordering[8][8] = {
1370 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 00 - Normal
1371 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 01 - NOT KNOWN YET
1372 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 02 - NOT KNOWN YET
1373 { 3, 4, 2, 0, 1, 5, 6, 7 }, // 03 - 0,1 unconfirmed. Digimon/Garou
1374 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 04 - NOT KNOWN YET
1375 { 1, 2, 3, 4, 0, 5, 6, 7 }, // 05 - 0,1 unconfirmed. Harry
1376 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 06 - NOT KNOWN YET
1377 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 07 - NOT KNOWN YET
1378};
1379
1380void _GBBBD(struct GB* gb, uint16_t address, uint8_t value) {
1381 struct GBMemory* memory = &gb->memory;
1382 switch (address & 0xF0FF) {
1383 case 0x2000:
1384 value = _reorderBits(value, _bbdBankReordering[memory->mbcState.bbd.bankSwapMode]);
1385 break;
1386 case 0x2001:
1387 memory->mbcState.bbd.dataSwapMode = value & 0x07;
1388 if (!(memory->mbcState.bbd.dataSwapMode == 0x07 || memory->mbcState.bbd.dataSwapMode == 0x05 || memory->mbcState.bbd.dataSwapMode == 0x04 || memory->mbcState.bbd.dataSwapMode == 0x00)) {
1389 mLOG(GB_MBC, STUB, "Bitswap mode unsupported: %X", memory->mbcState.bbd.dataSwapMode);
1390 }
1391 break;
1392 case 0x2080:
1393 memory->mbcState.bbd.bankSwapMode = value & 0x07;
1394 if (!(memory->mbcState.bbd.bankSwapMode == 0x03 || memory->mbcState.bbd.bankSwapMode == 0x05 || memory->mbcState.bbd.bankSwapMode == 0x00)) {
1395 mLOG(GB_MBC, STUB, "Bankswap mode unsupported: %X", memory->mbcState.bbd.dataSwapMode);
1396 }
1397 break;
1398 }
1399 _GBMBC5(gb, address, value);
1400}
1401
1402uint8_t _GBBBDRead(struct GBMemory* memory, uint16_t address) {
1403 switch (address >> 14) {
1404 case 0:
1405 default:
1406 return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
1407 case 1:
1408 return _reorderBits(memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)], _bbdDataReordering[memory->mbcState.bbd.dataSwapMode]);
1409 }
1410}
1411
1412static const uint8_t _hitekDataReordering[8][8] = {
1413 { 0, 1, 2, 3, 4, 5, 6, 7 },
1414 { 0, 6, 5, 3, 4, 1, 2, 7 },
1415 { 0, 5, 6, 3, 4, 2, 1, 7 },
1416 { 0, 6, 2, 3, 4, 5, 1, 7 },
1417 { 0, 6, 1, 3, 4, 5, 2, 7 },
1418 { 0, 1, 6, 3, 4, 5, 2, 7 },
1419 { 0, 2, 6, 3, 4, 1, 5, 7 },
1420 { 0, 6, 2, 3, 4, 1, 5, 7 },
1421};
1422
1423static const uint8_t _hitekBankReordering[8][8] = {
1424 { 0, 1, 2, 3, 4, 5, 6, 7 },
1425 { 3, 2, 1, 0, 4, 5, 6, 7 },
1426 { 2, 1, 0, 3, 4, 5, 6, 7 },
1427 { 1, 0, 3, 2, 4, 5, 6, 7 },
1428 { 0, 3, 2, 1, 4, 5, 6, 7 },
1429 { 2, 3, 0, 1, 4, 5, 6, 7 },
1430 { 3, 0, 1, 2, 4, 5, 6, 7 },
1431 { 2, 0, 3, 1, 4, 5, 6, 7 },
1432};
1433
1434void _GBHitek(struct GB* gb, uint16_t address, uint8_t value) {
1435 struct GBMemory* memory = &gb->memory;
1436 switch (address & 0xF0FF) {
1437 case 0x2000:
1438 value = _reorderBits(value, _hitekBankReordering[memory->mbcState.bbd.bankSwapMode]);
1439 break;
1440 case 0x2001:
1441 memory->mbcState.bbd.dataSwapMode = value & 0x07;
1442 break;
1443 case 0x2080:
1444 memory->mbcState.bbd.bankSwapMode = value & 0x07;
1445 break;
1446 case 0x300:
1447 // See hhugboy src/memory/mbc/MbcUnlHitek.cpp for commentary on this return
1448 return;
1449 }
1450 _GBMBC5(gb, address, value);
1451}
1452
1453uint8_t _GBHitekRead(struct GBMemory* memory, uint16_t address) {
1454 switch (address >> 14) {
1455 case 0:
1456 default:
1457 return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
1458 case 1:
1459 return _reorderBits(memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)], _hitekDataReordering[memory->mbcState.bbd.dataSwapMode]);
1460 }
1461}
1462
1463void GBMBCRTCRead(struct GB* gb) {
1464 struct GBMBCRTCSaveBuffer rtcBuffer;
1465 struct VFile* vf = gb->sramVf;
1466 if (!vf) {
1467 return;
1468 }
1469 vf->seek(vf, gb->sramSize, SEEK_SET);
1470 if (vf->read(vf, &rtcBuffer, sizeof(rtcBuffer)) < (ssize_t) sizeof(rtcBuffer) - 4) {
1471 return;
1472 }
1473
1474 LOAD_32LE(gb->memory.rtcRegs[0], 0, &rtcBuffer.latchedSec);
1475 LOAD_32LE(gb->memory.rtcRegs[1], 0, &rtcBuffer.latchedMin);
1476 LOAD_32LE(gb->memory.rtcRegs[2], 0, &rtcBuffer.latchedHour);
1477 LOAD_32LE(gb->memory.rtcRegs[3], 0, &rtcBuffer.latchedDays);
1478 LOAD_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
1479 LOAD_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime);
1480}
1481
1482void GBMBCRTCWrite(struct GB* gb) {
1483 struct VFile* vf = gb->sramVf;
1484 if (!vf) {
1485 return;
1486 }
1487
1488 uint8_t rtcRegs[5];
1489 memcpy(rtcRegs, gb->memory.rtcRegs, sizeof(rtcRegs));
1490 time_t rtcLastLatch = gb->memory.rtcLastLatch;
1491 _latchRtc(gb->memory.rtc, rtcRegs, &rtcLastLatch);
1492
1493 struct GBMBCRTCSaveBuffer rtcBuffer;
1494 STORE_32LE(rtcRegs[0], 0, &rtcBuffer.sec);
1495 STORE_32LE(rtcRegs[1], 0, &rtcBuffer.min);
1496 STORE_32LE(rtcRegs[2], 0, &rtcBuffer.hour);
1497 STORE_32LE(rtcRegs[3], 0, &rtcBuffer.days);
1498 STORE_32LE(rtcRegs[4], 0, &rtcBuffer.daysHi);
1499 STORE_32LE(gb->memory.rtcRegs[0], 0, &rtcBuffer.latchedSec);
1500 STORE_32LE(gb->memory.rtcRegs[1], 0, &rtcBuffer.latchedMin);
1501 STORE_32LE(gb->memory.rtcRegs[2], 0, &rtcBuffer.latchedHour);
1502 STORE_32LE(gb->memory.rtcRegs[3], 0, &rtcBuffer.latchedDays);
1503 STORE_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
1504 STORE_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime);
1505
1506 if ((size_t) vf->size(vf) < gb->sramSize + sizeof(rtcBuffer)) {
1507 // Writing past the end of the file can invalidate the file mapping
1508 vf->unmap(vf, gb->memory.sram, gb->sramSize);
1509 gb->memory.sram = NULL;
1510 }
1511 vf->seek(vf, gb->sramSize, SEEK_SET);
1512 vf->write(vf, &rtcBuffer, sizeof(rtcBuffer));
1513 if (!gb->memory.sram) {
1514 gb->memory.sram = vf->map(vf, gb->sramSize, MAP_WRITE);
1515 GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
1516 }
1517}