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