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