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->rom;
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 = 0;
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->rom[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 = value;
686 } else if (!memory->rtcLatched && value == 1) {
687 _latchRtc(memory);
688 }
689 break;
690 }
691}
692
693void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
694 int bank;
695 switch (address >> 12) {
696 case 0x0:
697 case 0x1:
698 switch (value) {
699 case 0:
700 memory->sramAccess = false;
701 break;
702 case 0xA:
703 memory->sramAccess = true;
704 _switchSramBank(memory, memory->sramCurrentBank);
705 break;
706 default:
707 // TODO
708 mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
709 break;
710 }
711 break;
712 case 0x2:
713 bank = (memory->currentBank & 0x100) | value;
714 _switchBank(memory, bank);
715 break;
716 case 0x3:
717 bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
718 _switchBank(memory, bank);
719 break;
720 case 0x4:
721 case 0x5:
722 if (memory->mbcType == GB_MBC5_RUMBLE) {
723 memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
724 value &= ~8;
725 }
726 _switchSramBank(memory, value & 0xF);
727 break;
728 default:
729 // TODO
730 mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
731 break;
732 }
733}
734
735void _GBMBC6(struct GBMemory* memory, uint16_t address, uint8_t value) {
736 // TODO
737 mLOG(GB_MBC, STUB, "MBC6 unimplemented");
738}
739
740void _GBMBC7(struct GBMemory* memory, uint16_t address, uint8_t value) {
741 int bank = value & 0x7F;
742 switch (address >> 13) {
743 case 0x1:
744 _switchBank(memory, bank);
745 break;
746 case 0x2:
747 if (value < 0x10) {
748 _switchSramBank(memory, value);
749 }
750 break;
751 default:
752 // TODO
753 mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
754 break;
755 }
756}
757
758uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) {
759 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
760 switch (address & 0xF0) {
761 case 0x00:
762 case 0x10:
763 case 0x60:
764 case 0x70:
765 return 0;
766 case 0x20:
767 if (memory->rotation && memory->rotation->readTiltX) {
768 int32_t x = -memory->rotation->readTiltX(memory->rotation);
769 x >>= 21;
770 x += 2047;
771 return x;
772 }
773 return 0xFF;
774 case 0x30:
775 if (memory->rotation && memory->rotation->readTiltX) {
776 int32_t x = -memory->rotation->readTiltX(memory->rotation);
777 x >>= 21;
778 x += 2047;
779 return x >> 8;
780 }
781 return 7;
782 case 0x40:
783 if (memory->rotation && memory->rotation->readTiltY) {
784 int32_t y = -memory->rotation->readTiltY(memory->rotation);
785 y >>= 21;
786 y += 2047;
787 return y;
788 }
789 return 0xFF;
790 case 0x50:
791 if (memory->rotation && memory->rotation->readTiltY) {
792 int32_t y = -memory->rotation->readTiltY(memory->rotation);
793 y >>= 21;
794 y += 2047;
795 return y >> 8;
796 }
797 return 7;
798 case 0x80:
799 return (mbc7->sr >> 16) & 1;
800 default:
801 return 0xFF;
802 }
803}
804
805void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
806 if ((address & 0xF0) != 0x80) {
807 return;
808 }
809 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
810 GBMBC7Field old = memory->mbcState.mbc7.field;
811 mbc7->field = GBMBC7FieldClearIO(value);
812 if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
813 if (mbc7->state == GBMBC7_STATE_WRITE) {
814 if (mbc7->writable) {
815 memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8;
816 memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr;
817 }
818 mbc7->sr = 0x1FFFF;
819 mbc7->state = GBMBC7_STATE_NULL;
820 } else {
821 mbc7->state = GBMBC7_STATE_IDLE;
822 }
823 }
824 if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) {
825 if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) {
826 mbc7->sr <<= 1;
827 mbc7->sr |= GBMBC7FieldGetIO(value);
828 ++mbc7->srBits;
829 }
830 switch (mbc7->state) {
831 case GBMBC7_STATE_IDLE:
832 if (GBMBC7FieldIsIO(value)) {
833 mbc7->state = GBMBC7_STATE_READ_COMMAND;
834 mbc7->srBits = 0;
835 mbc7->sr = 0;
836 }
837 break;
838 case GBMBC7_STATE_READ_COMMAND:
839 if (mbc7->srBits == 2) {
840 mbc7->state = GBMBC7_STATE_READ_ADDRESS;
841 mbc7->srBits = 0;
842 mbc7->command = mbc7->sr;
843 }
844 break;
845 case GBMBC7_STATE_READ_ADDRESS:
846 if (mbc7->srBits == 8) {
847 mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command;
848 mbc7->srBits = 0;
849 mbc7->address = mbc7->sr;
850 if (mbc7->state == GBMBC7_STATE_COMMAND_0) {
851 switch (mbc7->address >> 6) {
852 case 0:
853 mbc7->writable = false;
854 mbc7->state = GBMBC7_STATE_NULL;
855 break;
856 case 3:
857 mbc7->writable = true;
858 mbc7->state = GBMBC7_STATE_NULL;
859 break;
860 }
861 }
862 }
863 break;
864 case GBMBC7_STATE_COMMAND_0:
865 if (mbc7->srBits == 16) {
866 switch (mbc7->address >> 6) {
867 case 0:
868 mbc7->writable = false;
869 mbc7->state = GBMBC7_STATE_NULL;
870 break;
871 case 1:
872 mbc7->state = GBMBC7_STATE_WRITE;
873 if (mbc7->writable) {
874 int i;
875 for (i = 0; i < 256; ++i) {
876 memory->sramBank[i * 2] = mbc7->sr >> 8;
877 memory->sramBank[i * 2 + 1] = mbc7->sr;
878 }
879 }
880 break;
881 case 2:
882 mbc7->state = GBMBC7_STATE_WRITE;
883 if (mbc7->writable) {
884 int i;
885 for (i = 0; i < 256; ++i) {
886 memory->sramBank[i * 2] = 0xFF;
887 memory->sramBank[i * 2 + 1] = 0xFF;
888 }
889 }
890 break;
891 case 3:
892 mbc7->writable = true;
893 mbc7->state = GBMBC7_STATE_NULL;
894 break;
895 }
896 }
897 break;
898 case GBMBC7_STATE_COMMAND_SR_WRITE:
899 if (mbc7->srBits == 16) {
900 mbc7->srBits = 0;
901 mbc7->state = GBMBC7_STATE_WRITE;
902 }
903 break;
904 case GBMBC7_STATE_COMMAND_SR_READ:
905 if (mbc7->srBits == 1) {
906 mbc7->sr = memory->sramBank[mbc7->address * 2] << 8;
907 mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1];
908 mbc7->srBits = 0;
909 mbc7->state = GBMBC7_STATE_READ;
910 }
911 break;
912 case GBMBC7_STATE_COMMAND_SR_FILL:
913 if (mbc7->srBits == 16) {
914 mbc7->sr = 0xFFFF;
915 mbc7->srBits = 0;
916 mbc7->state = GBMBC7_STATE_WRITE;
917 }
918 break;
919 default:
920 break;
921 }
922 } else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) {
923 if (mbc7->state == GBMBC7_STATE_READ) {
924 mbc7->sr <<= 1;
925 ++mbc7->srBits;
926 if (mbc7->srBits == 16) {
927 mbc7->srBits = 0;
928 mbc7->state = GBMBC7_STATE_NULL;
929 }
930 }
931 }
932}
933
934void _pristineCow(struct GB* gb) {
935 if (gb->memory.rom != gb->pristineRom) {
936 return;
937 }
938 gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX);
939 memcpy(gb->memory.rom, gb->pristineRom, gb->memory.romSize);
940 memset(((uint8_t*) gb->memory.rom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize);
941 _switchBank(&gb->memory, gb->memory.currentBank);
942}