src/gb/memory.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 "memory.h"
7
8#include "core/interface.h"
9#include "gb/gb.h"
10#include "gb/io.h"
11
12#include "util/memory.h"
13
14#include <time.h>
15
16mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC");
17mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory");
18
19static void _pristineCow(struct GB* gba);
20
21static void _GBMBCNone(struct GBMemory* memory, uint16_t address, uint8_t value) {
22 UNUSED(memory);
23 UNUSED(address);
24 UNUSED(value);
25
26 mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC");
27}
28
29static void _GBMBC1(struct GBMemory*, uint16_t address, uint8_t value);
30static void _GBMBC2(struct GBMemory*, uint16_t address, uint8_t value);
31static void _GBMBC3(struct GBMemory*, uint16_t address, uint8_t value);
32static void _GBMBC5(struct GBMemory*, uint16_t address, uint8_t value);
33static void _GBMBC6(struct GBMemory*, uint16_t address, uint8_t value);
34static void _GBMBC7(struct GBMemory*, uint16_t address, uint8_t value);
35static uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address);
36static void _GBMBC7Write(struct GBMemory*, uint16_t address, uint8_t value);
37
38static uint8_t GBFastLoad8(struct LR35902Core* cpu, uint16_t address) {
39 if (UNLIKELY(address > cpu->memory.activeRegionEnd)) {
40 cpu->memory.setActiveRegion(cpu, address);
41 return cpu->memory.cpuLoad8(cpu, address);
42 }
43 return cpu->memory.activeRegion[address & cpu->memory.activeMask];
44}
45
46static void GBSetActiveRegion(struct LR35902Core* cpu, uint16_t address) {
47 struct GB* gb = (struct GB*) cpu->master;
48 struct GBMemory* memory = &gb->memory;
49 switch (address >> 12) {
50 case GB_REGION_CART_BANK0:
51 case GB_REGION_CART_BANK0 + 1:
52 case GB_REGION_CART_BANK0 + 2:
53 case GB_REGION_CART_BANK0 + 3:
54 cpu->memory.cpuLoad8 = GBFastLoad8;
55 cpu->memory.activeRegion = memory->romBase;
56 cpu->memory.activeRegionEnd = GB_BASE_CART_BANK1;
57 cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1;
58 break;
59 case GB_REGION_CART_BANK1:
60 case GB_REGION_CART_BANK1 + 1:
61 case GB_REGION_CART_BANK1 + 2:
62 case GB_REGION_CART_BANK1 + 3:
63 cpu->memory.cpuLoad8 = GBFastLoad8;
64 cpu->memory.activeRegion = memory->romBank;
65 cpu->memory.activeRegionEnd = GB_BASE_VRAM;
66 cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1;
67 break;
68 default:
69 cpu->memory.cpuLoad8 = GBLoad8;
70 break;
71 }
72}
73
74static void _GBMemoryDMAService(struct GB* gb);
75static void _GBMemoryHDMAService(struct GB* gb);
76
77void GBMemoryInit(struct GB* gb) {
78 struct LR35902Core* cpu = gb->cpu;
79 cpu->memory.cpuLoad8 = GBLoad8;
80 cpu->memory.load8 = GBLoad8;
81 cpu->memory.store8 = GBStore8;
82 cpu->memory.setActiveRegion = GBSetActiveRegion;
83
84 gb->memory.wram = 0;
85 gb->memory.wramBank = 0;
86 gb->memory.rom = 0;
87 gb->memory.romBank = 0;
88 gb->memory.romSize = 0;
89 gb->memory.sram = 0;
90 gb->memory.mbcType = GB_MBC_NONE;
91 gb->memory.mbc = 0;
92
93 gb->memory.rtc = NULL;
94
95 GBIOInit(gb);
96}
97
98void GBMemoryDeinit(struct GB* gb) {
99 mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
100 if (gb->memory.rom) {
101 mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
102 }
103}
104
105void GBMemoryReset(struct GB* gb) {
106 if (gb->memory.wram) {
107 mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
108 }
109 gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
110 GBMemorySwitchWramBank(&gb->memory, 1);
111 gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
112 gb->memory.currentBank = 1;
113 if (!gb->memory.sram) {
114 gb->memory.sram = anonymousMemoryMap(0x20000);
115 }
116 gb->memory.sramCurrentBank = 0;
117 gb->memory.sramBank = gb->memory.sram;
118
119 gb->memory.ime = false;
120 gb->memory.ie = 0;
121
122 gb->memory.dmaNext = INT_MAX;
123 gb->memory.dmaRemaining = 0;
124 gb->memory.dmaSource = 0;
125 gb->memory.dmaDest = 0;
126 gb->memory.hdmaNext = INT_MAX;
127 gb->memory.hdmaRemaining = 0;
128 gb->memory.hdmaSource = 0;
129 gb->memory.hdmaDest = 0;
130 gb->memory.isHdma = false;
131
132 gb->memory.sramAccess = false;
133 gb->memory.rtcAccess = false;
134 gb->memory.activeRtcReg = 0;
135 gb->memory.rtcLatched = false;
136 memset(&gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
137
138 memset(&gb->memory.hram, 0, sizeof(gb->memory.hram));
139 memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState));
140
141 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
142 switch (cart->type) {
143 case 0:
144 case 8:
145 case 9:
146 gb->memory.mbc = _GBMBCNone;
147 gb->memory.mbcType = GB_MBC_NONE;
148 break;
149 case 1:
150 case 2:
151 case 3:
152 gb->memory.mbc = _GBMBC1;
153 gb->memory.mbcType = GB_MBC1;
154 break;
155 case 5:
156 case 6:
157 gb->memory.mbc = _GBMBC2;
158 gb->memory.mbcType = GB_MBC2;
159 break;
160 case 0x0F:
161 case 0x10:
162 case 0x11:
163 case 0x12:
164 case 0x13:
165 gb->memory.mbc = _GBMBC3;
166 gb->memory.mbcType = GB_MBC3;
167 break;
168 default:
169 mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
170 case 0x19:
171 case 0x1A:
172 case 0x1B:
173 gb->memory.mbc = _GBMBC5;
174 gb->memory.mbcType = GB_MBC5;
175 break;
176 case 0x1C:
177 case 0x1D:
178 case 0x1E:
179 gb->memory.mbc = _GBMBC5;
180 gb->memory.mbcType = GB_MBC5_RUMBLE;
181 break;
182 case 0x20:
183 gb->memory.mbc = _GBMBC6;
184 gb->memory.mbcType = GB_MBC6;
185 break;
186 case 0x22:
187 gb->memory.mbc = _GBMBC7;
188 gb->memory.mbcType = GB_MBC7;
189 break;
190 }
191
192 if (!gb->memory.wram) {
193 GBMemoryDeinit(gb);
194 }
195}
196
197void GBMemorySwitchWramBank(struct GBMemory* memory, int bank) {
198 bank &= 7;
199 if (!bank) {
200 bank = 1;
201 }
202 memory->wramBank = &memory->wram[GB_SIZE_WORKING_RAM_BANK0 * bank];
203 memory->wramCurrentBank = bank;
204}
205
206uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
207 struct GB* gb = (struct GB*) cpu->master;
208 struct GBMemory* memory = &gb->memory;
209 switch (address >> 12) {
210 case GB_REGION_CART_BANK0:
211 case GB_REGION_CART_BANK0 + 1:
212 case GB_REGION_CART_BANK0 + 2:
213 case GB_REGION_CART_BANK0 + 3:
214 return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
215 case GB_REGION_CART_BANK1:
216 case GB_REGION_CART_BANK1 + 1:
217 case GB_REGION_CART_BANK1 + 2:
218 case GB_REGION_CART_BANK1 + 3:
219 return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
220 case GB_REGION_VRAM:
221 case GB_REGION_VRAM + 1:
222 return gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)];
223 case GB_REGION_EXTERNAL_RAM:
224 case GB_REGION_EXTERNAL_RAM + 1:
225 if (memory->rtcAccess) {
226 return gb->memory.rtcRegs[memory->activeRtcReg];
227 } else if (memory->sramAccess) {
228 return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
229 } else if (memory->mbcType == GB_MBC7) {
230 return _GBMBC7Read(memory, address);
231 }
232 return 0xFF;
233 case GB_REGION_WORKING_RAM_BANK0:
234 case GB_REGION_WORKING_RAM_BANK0 + 2:
235 return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
236 case GB_REGION_WORKING_RAM_BANK1:
237 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
238 default:
239 if (address < GB_BASE_OAM) {
240 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
241 }
242 if (address < GB_BASE_UNUSABLE) {
243 if (gb->video.mode < 2) {
244 return gb->video.oam.raw[address & 0xFF];
245 }
246 return 0xFF;
247 }
248 if (address < GB_BASE_IO) {
249 mLOG(GB_MEM, GAME_ERROR, "Attempt to read from unusable memory: %04X", address);
250 return 0xFF;
251 }
252 if (address < GB_BASE_HRAM) {
253 return GBIORead(gb, address & (GB_SIZE_IO - 1));
254 }
255 if (address < GB_BASE_IE) {
256 return memory->hram[address & GB_SIZE_HRAM];
257 }
258 return GBIORead(gb, REG_IE);
259 }
260}
261
262void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
263 struct GB* gb = (struct GB*) cpu->master;
264 struct GBMemory* memory = &gb->memory;
265 switch (address >> 12) {
266 case GB_REGION_CART_BANK0:
267 case GB_REGION_CART_BANK0 + 1:
268 case GB_REGION_CART_BANK0 + 2:
269 case GB_REGION_CART_BANK0 + 3:
270 case GB_REGION_CART_BANK1:
271 case GB_REGION_CART_BANK1 + 1:
272 case GB_REGION_CART_BANK1 + 2:
273 case GB_REGION_CART_BANK1 + 3:
274 memory->mbc(memory, address, value);
275 cpu->memory.setActiveRegion(cpu, cpu->pc);
276 return;
277 case GB_REGION_VRAM:
278 case GB_REGION_VRAM + 1:
279 // TODO: Block access in wrong modes
280 gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value;
281 return;
282 case GB_REGION_EXTERNAL_RAM:
283 case GB_REGION_EXTERNAL_RAM + 1:
284 if (memory->rtcAccess) {
285 gb->memory.rtcRegs[memory->activeRtcReg] = value;
286 } else if (memory->sramAccess) {
287 gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
288 } else if (gb->memory.mbcType == GB_MBC7) {
289 _GBMBC7Write(&gb->memory, address, value);
290 }
291 return;
292 case GB_REGION_WORKING_RAM_BANK0:
293 case GB_REGION_WORKING_RAM_BANK0 + 2:
294 memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
295 return;
296 case GB_REGION_WORKING_RAM_BANK1:
297 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
298 return;
299 default:
300 if (address < GB_BASE_OAM) {
301 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
302 } else if (address < GB_BASE_UNUSABLE) {
303 if (gb->video.mode < 2) {
304 gb->video.oam.raw[address & 0xFF] = value;
305 }
306 } else if (address < GB_BASE_IO) {
307 mLOG(GB_MEM, GAME_ERROR, "Attempt to write to unusable memory: %04X:%02X", address, value);
308 } else if (address < GB_BASE_HRAM) {
309 GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
310 } else if (address < GB_BASE_IE) {
311 memory->hram[address & GB_SIZE_HRAM] = value;
312 } else {
313 GBIOWrite(gb, REG_IE, value);
314 }
315 }
316}
317
318int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles) {
319 int nextEvent = INT_MAX;
320 if (gb->memory.dmaRemaining) {
321 gb->memory.dmaNext -= cycles;
322 if (gb->memory.dmaNext <= 0) {
323 _GBMemoryDMAService(gb);
324 }
325 nextEvent = gb->memory.dmaNext;
326 }
327 if (gb->memory.hdmaRemaining) {
328 gb->memory.hdmaNext -= cycles;
329 if (gb->memory.hdmaNext <= 0) {
330 _GBMemoryHDMAService(gb);
331 }
332 if (gb->memory.hdmaNext < nextEvent) {
333 nextEvent = gb->memory.hdmaNext;
334 }
335 }
336 return nextEvent;
337}
338
339void GBMemoryDMA(struct GB* gb, uint16_t base) {
340 if (base > 0xF100) {
341 return;
342 }
343 gb->cpu->memory.store8 = GBDMAStore8;
344 gb->cpu->memory.load8 = GBDMALoad8;
345 gb->cpu->memory.cpuLoad8 = GBDMALoad8;
346 gb->memory.dmaNext = gb->cpu->cycles + 8;
347 if (gb->memory.dmaNext < gb->cpu->nextEvent) {
348 gb->cpu->nextEvent = gb->memory.dmaNext;
349 }
350 gb->memory.dmaSource = base;
351 gb->memory.dmaDest = 0;
352 gb->memory.dmaRemaining = 0xA0;
353}
354
355void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
356 gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8;
357 gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2];
358 gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8;
359 gb->memory.hdmaDest |= gb->memory.io[REG_HDMA4];
360 gb->memory.hdmaSource &= 0xFFF0;
361 if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) {
362 mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource);
363 return;
364 }
365 gb->memory.hdmaDest &= 0x1FF0;
366 gb->memory.hdmaDest |= 0x8000;
367 bool wasHdma = gb->memory.isHdma;
368 gb->memory.isHdma = value & 0x80;
369 if (!wasHdma && !gb->memory.isHdma) {
370 gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10;
371 gb->memory.hdmaNext = gb->cpu->cycles;
372 gb->cpu->nextEvent = gb->cpu->cycles;
373 }
374}
375
376void _GBMemoryDMAService(struct GB* gb) {
377 uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
378 // TODO: Can DMA write OAM during modes 2-3?
379 gb->video.oam.raw[gb->memory.dmaDest] = b;
380 ++gb->memory.dmaSource;
381 ++gb->memory.dmaDest;
382 --gb->memory.dmaRemaining;
383 if (gb->memory.dmaRemaining) {
384 gb->memory.dmaNext += 4;
385 } else {
386 gb->memory.dmaNext = INT_MAX;
387 gb->cpu->memory.store8 = GBStore8;
388 gb->cpu->memory.load8 = GBLoad8;
389 }
390}
391
392void _GBMemoryHDMAService(struct GB* gb) {
393 uint8_t b = gb->cpu->memory.load8(gb->cpu, gb->memory.hdmaSource);
394 gb->cpu->memory.store8(gb->cpu, gb->memory.hdmaDest, b);
395 ++gb->memory.hdmaSource;
396 ++gb->memory.hdmaDest;
397 --gb->memory.hdmaRemaining;
398 gb->cpu->cycles += 2;
399 if (gb->memory.hdmaRemaining) {
400 gb->memory.hdmaNext += 2;
401 } else {
402 gb->memory.io[REG_HDMA1] = gb->memory.hdmaSource >> 8;
403 gb->memory.io[REG_HDMA2] = gb->memory.hdmaSource;
404 gb->memory.io[REG_HDMA3] = gb->memory.hdmaDest >> 8;
405 gb->memory.io[REG_HDMA4] = gb->memory.hdmaDest;
406 if (gb->memory.isHdma) {
407 --gb->memory.io[REG_HDMA5];
408 if (gb->memory.io[REG_HDMA5] == 0xFF) {
409 gb->memory.isHdma = false;
410 }
411 } else {
412 gb->memory.io[REG_HDMA5] |= 0x80;
413 }
414 }
415}
416
417struct OAMBlock {
418 uint16_t low;
419 uint16_t high;
420};
421
422static const struct OAMBlock _oamBlockDMG[] = {
423 { 0xA000, 0xFE00 },
424 { 0xA000, 0xFE00 },
425 { 0xA000, 0xFE00 },
426 { 0xA000, 0xFE00 },
427 { 0x8000, 0xA000 },
428 { 0xA000, 0xFE00 },
429 { 0xA000, 0xFE00 },
430 { 0xA000, 0xFE00 },
431};
432
433static const struct OAMBlock _oamBlockCGB[] = {
434 { 0xA000, 0xC000 },
435 { 0xA000, 0xC000 },
436 { 0xA000, 0xC000 },
437 { 0xA000, 0xC000 },
438 { 0x8000, 0xA000 },
439 { 0xA000, 0xC000 },
440 { 0xC000, 0xFE00 },
441 { 0xA000, 0xC000 },
442};
443
444uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) {
445 struct GB* gb = (struct GB*) cpu->master;
446 struct GBMemory* memory = &gb->memory;
447 const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB;
448 block = &block[memory->dmaSource >> 13];
449 if (address >= block->low && address < block->high) {
450 return 0xFF;
451 }
452 if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
453 return 0xFF;
454 }
455 return GBLoad8(cpu, address);
456}
457
458void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
459 struct GB* gb = (struct GB*) cpu->master;
460 struct GBMemory* memory = &gb->memory;
461 const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB;
462 block = &block[memory->dmaSource >> 13];
463 if (address >= block->low && address < block->high) {
464 return;
465 }
466 if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
467 return;
468 }
469 GBStore8(cpu, address, value);
470}
471
472void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old) {
473 struct GB* gb = (struct GB*) cpu->master;
474 struct GBMemory* memory = &gb->memory;
475 int8_t oldValue = -1;
476
477 switch (address >> 12) {
478 case GB_REGION_CART_BANK0:
479 case GB_REGION_CART_BANK0 + 1:
480 case GB_REGION_CART_BANK0 + 2:
481 case GB_REGION_CART_BANK0 + 3:
482 _pristineCow(gb);
483 oldValue = memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
484 memory->rom[address & (GB_SIZE_CART_BANK0 - 1)] = value;
485 break;
486 case GB_REGION_CART_BANK1:
487 case GB_REGION_CART_BANK1 + 1:
488 case GB_REGION_CART_BANK1 + 2:
489 case GB_REGION_CART_BANK1 + 3:
490 _pristineCow(gb);
491 oldValue = memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
492 memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)] = value;
493 break;
494 case GB_REGION_VRAM:
495 case GB_REGION_VRAM + 1:
496 oldValue = gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)];
497 gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value;
498 break;
499 case GB_REGION_EXTERNAL_RAM:
500 case GB_REGION_EXTERNAL_RAM + 1:
501 mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address);
502 return;
503 case GB_REGION_WORKING_RAM_BANK0:
504 case GB_REGION_WORKING_RAM_BANK0 + 2:
505 oldValue = memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
506 memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
507 break;
508 case GB_REGION_WORKING_RAM_BANK1:
509 oldValue = memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
510 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
511 break;
512 default:
513 if (address < GB_BASE_OAM) {
514 oldValue = memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
515 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
516 } else if (address < GB_BASE_UNUSABLE) {
517 oldValue = gb->video.oam.raw[address & 0xFF];
518 gb->video.oam.raw[address & 0xFF] = value;
519 } else if (address < GB_BASE_HRAM) {
520 mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address);
521 return;
522 } else if (address < GB_BASE_IE) {
523 oldValue = memory->hram[address & GB_SIZE_HRAM];
524 memory->hram[address & GB_SIZE_HRAM] = value;
525 } else {
526 mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address);
527 return;
528 }
529 }
530 if (old) {
531 *old = oldValue;
532 }
533}
534
535static void _switchBank(struct GBMemory* memory, int bank) {
536 size_t bankStart = bank * GB_SIZE_CART_BANK0;
537 if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
538 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
539 bankStart &= (memory->romSize - 1);
540 bank = bankStart / GB_SIZE_CART_BANK0;
541 }
542 memory->romBank = &memory->rom[bankStart];
543 memory->currentBank = bank;
544}
545
546static void _switchSramBank(struct GBMemory* memory, int bank) {
547 size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
548 memory->sramBank = &memory->sram[bankStart];
549 memory->sramCurrentBank = bank;
550}
551
552static void _latchRtc(struct GBMemory* memory) {
553 time_t t;
554 struct mRTCSource* rtc = memory->rtc;
555 if (rtc) {
556 if (rtc->sample) {
557 rtc->sample(rtc);
558 }
559 t = rtc->unixTime(rtc);
560 } else {
561 t = time(0);
562 }
563 struct tm date;
564 localtime_r(&t, &date);
565 memory->rtcRegs[0] = date.tm_sec;
566 memory->rtcRegs[1] = date.tm_min;
567 memory->rtcRegs[2] = date.tm_hour;
568 memory->rtcRegs[3] = date.tm_yday; // TODO: Persist day counter
569 memory->rtcRegs[4] &= 0xF0;
570 memory->rtcRegs[4] |= date.tm_yday >> 8;
571}
572
573void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
574 int bank = value & 0x1F;
575 switch (address >> 13) {
576 case 0x0:
577 switch (value) {
578 case 0:
579 memory->sramAccess = false;
580 break;
581 case 0xA:
582 memory->sramAccess = true;
583 _switchSramBank(memory, memory->sramCurrentBank);
584 break;
585 default:
586 // TODO
587 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
588 break;
589 }
590 break;
591 case 0x1:
592 if (!bank) {
593 ++bank;
594 }
595 _switchBank(memory, bank | (memory->currentBank & 0x60));
596 break;
597 case 0x2:
598 bank &= 3;
599 if (!memory->mbcState.mbc1.mode) {
600 _switchBank(memory, (bank << 5) | (memory->currentBank & 0x1F));
601 } else {
602 _switchSramBank(memory, bank);
603 }
604 break;
605 case 0x3:
606 memory->mbcState.mbc1.mode = value & 1;
607 if (memory->mbcState.mbc1.mode) {
608 _switchBank(memory, memory->currentBank & 0x1F);
609 } else {
610 _switchSramBank(memory, 0);
611 }
612 break;
613 default:
614 // TODO
615 mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
616 break;
617 }
618}
619
620void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
621 int bank = value & 0xF;
622 switch (address >> 13) {
623 case 0x0:
624 switch (value) {
625 case 0:
626 memory->sramAccess = false;
627 break;
628 case 0xA:
629 memory->sramAccess = true;
630 _switchSramBank(memory, memory->sramCurrentBank);
631 break;
632 default:
633 // TODO
634 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
635 break;
636 }
637 break;
638 case 0x1:
639 if (!bank) {
640 ++bank;
641 }
642 _switchBank(memory, bank);
643 break;
644 default:
645 // TODO
646 mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
647 break;
648 }}
649
650void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
651 int bank = value & 0x7F;
652 switch (address >> 13) {
653 case 0x0:
654 switch (value) {
655 case 0:
656 memory->sramAccess = false;
657 break;
658 case 0xA:
659 memory->sramAccess = true;
660 _switchSramBank(memory, memory->sramCurrentBank);
661 break;
662 default:
663 // TODO
664 mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
665 break;
666 }
667 break;
668 case 0x1:
669 if (!bank) {
670 ++bank;
671 }
672 _switchBank(memory, bank);
673 break;
674 case 0x2:
675 if (value < 4) {
676 _switchSramBank(memory, value);
677 memory->rtcAccess = false;
678 } else if (value >= 8 && value <= 0xC) {
679 memory->activeRtcReg = value - 8;
680 memory->rtcAccess = true;
681 }
682 break;
683 case 0x3:
684 if (memory->rtcLatched && value == 0) {
685 memory->rtcLatched = false;
686 } else if (!memory->rtcLatched && value == 1) {
687 _latchRtc(memory);
688 memory->rtcLatched = true;
689 }
690 break;
691 }
692}
693
694void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
695 int bank;
696 switch (address >> 12) {
697 case 0x0:
698 case 0x1:
699 switch (value) {
700 case 0:
701 memory->sramAccess = false;
702 break;
703 case 0xA:
704 memory->sramAccess = true;
705 _switchSramBank(memory, memory->sramCurrentBank);
706 break;
707 default:
708 // TODO
709 mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
710 break;
711 }
712 break;
713 case 0x2:
714 bank = (memory->currentBank & 0x100) | value;
715 _switchBank(memory, bank);
716 break;
717 case 0x3:
718 bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
719 _switchBank(memory, bank);
720 break;
721 case 0x4:
722 case 0x5:
723 if (memory->mbcType == GB_MBC5_RUMBLE) {
724 memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
725 value &= ~8;
726 }
727 _switchSramBank(memory, value & 0xF);
728 break;
729 default:
730 // TODO
731 mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
732 break;
733 }
734}
735
736void _GBMBC6(struct GBMemory* memory, uint16_t address, uint8_t value) {
737 // TODO
738 mLOG(GB_MBC, STUB, "MBC6 unimplemented");
739}
740
741void _GBMBC7(struct GBMemory* memory, uint16_t address, uint8_t value) {
742 int bank = value & 0x7F;
743 switch (address >> 13) {
744 case 0x1:
745 _switchBank(memory, bank);
746 break;
747 case 0x2:
748 if (value < 0x10) {
749 _switchSramBank(memory, value);
750 }
751 break;
752 default:
753 // TODO
754 mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
755 break;
756 }
757}
758
759uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) {
760 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
761 switch (address & 0xF0) {
762 case 0x00:
763 case 0x10:
764 case 0x60:
765 case 0x70:
766 return 0;
767 case 0x20:
768 if (memory->rotation && memory->rotation->readTiltX) {
769 int32_t x = -memory->rotation->readTiltX(memory->rotation);
770 x >>= 21;
771 x += 2047;
772 return x;
773 }
774 return 0xFF;
775 case 0x30:
776 if (memory->rotation && memory->rotation->readTiltX) {
777 int32_t x = -memory->rotation->readTiltX(memory->rotation);
778 x >>= 21;
779 x += 2047;
780 return x >> 8;
781 }
782 return 7;
783 case 0x40:
784 if (memory->rotation && memory->rotation->readTiltY) {
785 int32_t y = -memory->rotation->readTiltY(memory->rotation);
786 y >>= 21;
787 y += 2047;
788 return y;
789 }
790 return 0xFF;
791 case 0x50:
792 if (memory->rotation && memory->rotation->readTiltY) {
793 int32_t y = -memory->rotation->readTiltY(memory->rotation);
794 y >>= 21;
795 y += 2047;
796 return y >> 8;
797 }
798 return 7;
799 case 0x80:
800 return (mbc7->sr >> 16) & 1;
801 default:
802 return 0xFF;
803 }
804}
805
806void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
807 if ((address & 0xF0) != 0x80) {
808 return;
809 }
810 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
811 GBMBC7Field old = memory->mbcState.mbc7.field;
812 mbc7->field = GBMBC7FieldClearIO(value);
813 if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
814 if (mbc7->state == GBMBC7_STATE_WRITE) {
815 if (mbc7->writable) {
816 memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8;
817 memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr;
818 }
819 mbc7->sr = 0x1FFFF;
820 mbc7->state = GBMBC7_STATE_NULL;
821 } else {
822 mbc7->state = GBMBC7_STATE_IDLE;
823 }
824 }
825 if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) {
826 if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) {
827 mbc7->sr <<= 1;
828 mbc7->sr |= GBMBC7FieldGetIO(value);
829 ++mbc7->srBits;
830 }
831 switch (mbc7->state) {
832 case GBMBC7_STATE_IDLE:
833 if (GBMBC7FieldIsIO(value)) {
834 mbc7->state = GBMBC7_STATE_READ_COMMAND;
835 mbc7->srBits = 0;
836 mbc7->sr = 0;
837 }
838 break;
839 case GBMBC7_STATE_READ_COMMAND:
840 if (mbc7->srBits == 2) {
841 mbc7->state = GBMBC7_STATE_READ_ADDRESS;
842 mbc7->srBits = 0;
843 mbc7->command = mbc7->sr;
844 }
845 break;
846 case GBMBC7_STATE_READ_ADDRESS:
847 if (mbc7->srBits == 8) {
848 mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command;
849 mbc7->srBits = 0;
850 mbc7->address = mbc7->sr;
851 if (mbc7->state == GBMBC7_STATE_COMMAND_0) {
852 switch (mbc7->address >> 6) {
853 case 0:
854 mbc7->writable = false;
855 mbc7->state = GBMBC7_STATE_NULL;
856 break;
857 case 3:
858 mbc7->writable = true;
859 mbc7->state = GBMBC7_STATE_NULL;
860 break;
861 }
862 }
863 }
864 break;
865 case GBMBC7_STATE_COMMAND_0:
866 if (mbc7->srBits == 16) {
867 switch (mbc7->address >> 6) {
868 case 0:
869 mbc7->writable = false;
870 mbc7->state = GBMBC7_STATE_NULL;
871 break;
872 case 1:
873 mbc7->state = GBMBC7_STATE_WRITE;
874 if (mbc7->writable) {
875 int i;
876 for (i = 0; i < 256; ++i) {
877 memory->sramBank[i * 2] = mbc7->sr >> 8;
878 memory->sramBank[i * 2 + 1] = mbc7->sr;
879 }
880 }
881 break;
882 case 2:
883 mbc7->state = GBMBC7_STATE_WRITE;
884 if (mbc7->writable) {
885 int i;
886 for (i = 0; i < 256; ++i) {
887 memory->sramBank[i * 2] = 0xFF;
888 memory->sramBank[i * 2 + 1] = 0xFF;
889 }
890 }
891 break;
892 case 3:
893 mbc7->writable = true;
894 mbc7->state = GBMBC7_STATE_NULL;
895 break;
896 }
897 }
898 break;
899 case GBMBC7_STATE_COMMAND_SR_WRITE:
900 if (mbc7->srBits == 16) {
901 mbc7->srBits = 0;
902 mbc7->state = GBMBC7_STATE_WRITE;
903 }
904 break;
905 case GBMBC7_STATE_COMMAND_SR_READ:
906 if (mbc7->srBits == 1) {
907 mbc7->sr = memory->sramBank[mbc7->address * 2] << 8;
908 mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1];
909 mbc7->srBits = 0;
910 mbc7->state = GBMBC7_STATE_READ;
911 }
912 break;
913 case GBMBC7_STATE_COMMAND_SR_FILL:
914 if (mbc7->srBits == 16) {
915 mbc7->sr = 0xFFFF;
916 mbc7->srBits = 0;
917 mbc7->state = GBMBC7_STATE_WRITE;
918 }
919 break;
920 default:
921 break;
922 }
923 } else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) {
924 if (mbc7->state == GBMBC7_STATE_READ) {
925 mbc7->sr <<= 1;
926 ++mbc7->srBits;
927 if (mbc7->srBits == 16) {
928 mbc7->srBits = 0;
929 mbc7->state = GBMBC7_STATE_NULL;
930 }
931 }
932 }
933}
934
935void _pristineCow(struct GB* gb) {
936 if (gb->memory.rom != gb->pristineRom) {
937 return;
938 }
939 gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX);
940 memcpy(gb->memory.rom, gb->pristineRom, gb->memory.romSize);
941 memset(((uint8_t*) gb->memory.rom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize);
942 _switchBank(&gb->memory, gb->memory.currentBank);
943}