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