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