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 memory->rtcRegs[memory->activeRtcReg];
233 } else if (memory->sramAccess) {
234 return 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 memory->rtcRegs[memory->activeRtcReg] = value;
294 } else if (memory->sramAccess) {
295 memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
296 } else if (memory->mbcType == GB_MBC7) {
297 _GBMBC7Write(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}
325uint8_t GBView8(struct LR35902Core* cpu, uint16_t address, int segment) {
326 struct GB* gb = (struct GB*) cpu->master;
327 struct GBMemory* memory = &gb->memory;
328 switch (address >> 12) {
329 case GB_REGION_CART_BANK0:
330 case GB_REGION_CART_BANK0 + 1:
331 case GB_REGION_CART_BANK0 + 2:
332 case GB_REGION_CART_BANK0 + 3:
333 return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
334 case GB_REGION_CART_BANK1:
335 case GB_REGION_CART_BANK1 + 1:
336 case GB_REGION_CART_BANK1 + 2:
337 case GB_REGION_CART_BANK1 + 3:
338 if (segment < 0) {
339 return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
340 } else {
341 if ((size_t) segment * GB_SIZE_CART_BANK0 > memory->romSize) {
342 return 0xFF;
343 }
344 return memory->rom[(address & (GB_SIZE_CART_BANK0 - 1)) + segment * GB_SIZE_CART_BANK0];
345 }
346 case GB_REGION_VRAM:
347 case GB_REGION_VRAM + 1:
348 if (segment < 0) {
349 return gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)];
350 } else {
351 return gb->video.vram[(address & (GB_SIZE_VRAM_BANK0 - 1)) + segment *GB_SIZE_VRAM_BANK0];
352 }
353 case GB_REGION_EXTERNAL_RAM:
354 case GB_REGION_EXTERNAL_RAM + 1:
355 if (memory->rtcAccess) {
356 return memory->rtcRegs[memory->activeRtcReg];
357 } else if (memory->sramAccess) {
358 if (segment < 0) {
359 return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
360 } else {
361 return memory->sram[(address & (GB_SIZE_EXTERNAL_RAM - 1)) + segment *GB_SIZE_EXTERNAL_RAM];
362 }
363 } else if (memory->mbcType == GB_MBC7) {
364 return _GBMBC7Read(memory, address);
365 } else if (memory->mbcType == GB_HuC3) {
366 return 0x01; // TODO: Is this supposed to be the current SRAM bank?
367 }
368 return 0xFF;
369 case GB_REGION_WORKING_RAM_BANK0:
370 case GB_REGION_WORKING_RAM_BANK0 + 2:
371 return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
372 case GB_REGION_WORKING_RAM_BANK1:
373 if (segment < 0) {
374 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
375 } else {
376 return memory->wram[(address & (GB_SIZE_WORKING_RAM_BANK0 - 1)) + segment *GB_SIZE_WORKING_RAM_BANK0];
377 }
378 default:
379 if (address < GB_BASE_OAM) {
380 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
381 }
382 if (address < GB_BASE_UNUSABLE) {
383 if (gb->video.mode < 2) {
384 return gb->video.oam.raw[address & 0xFF];
385 }
386 return 0xFF;
387 }
388 if (address < GB_BASE_IO) {
389 mLOG(GB_MEM, GAME_ERROR, "Attempt to read from unusable memory: %04X", address);
390 return 0xFF;
391 }
392 if (address < GB_BASE_HRAM) {
393 return GBIORead(gb, address & (GB_SIZE_IO - 1));
394 }
395 if (address < GB_BASE_IE) {
396 return memory->hram[address & GB_SIZE_HRAM];
397 }
398 return GBIORead(gb, REG_IE);
399 }
400}
401
402int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles) {
403 int nextEvent = INT_MAX;
404 if (gb->memory.dmaRemaining) {
405 gb->memory.dmaNext -= cycles;
406 if (gb->memory.dmaNext <= 0) {
407 _GBMemoryDMAService(gb);
408 }
409 nextEvent = gb->memory.dmaNext;
410 }
411 if (gb->memory.hdmaRemaining) {
412 gb->memory.hdmaNext -= cycles;
413 if (gb->memory.hdmaNext <= 0) {
414 _GBMemoryHDMAService(gb);
415 }
416 if (gb->memory.hdmaNext < nextEvent) {
417 nextEvent = gb->memory.hdmaNext;
418 }
419 }
420 return nextEvent;
421}
422
423void GBMemoryDMA(struct GB* gb, uint16_t base) {
424 if (base > 0xF100) {
425 return;
426 }
427 gb->cpu->memory.store8 = GBDMAStore8;
428 gb->cpu->memory.load8 = GBDMALoad8;
429 gb->cpu->memory.cpuLoad8 = GBDMALoad8;
430 gb->memory.dmaNext = gb->cpu->cycles + 8;
431 if (gb->memory.dmaNext < gb->cpu->nextEvent) {
432 gb->cpu->nextEvent = gb->memory.dmaNext;
433 }
434 gb->memory.dmaSource = base;
435 gb->memory.dmaDest = 0;
436 gb->memory.dmaRemaining = 0xA0;
437}
438
439void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
440 gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8;
441 gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2];
442 gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8;
443 gb->memory.hdmaDest |= gb->memory.io[REG_HDMA4];
444 gb->memory.hdmaSource &= 0xFFF0;
445 if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) {
446 mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource);
447 return;
448 }
449 gb->memory.hdmaDest &= 0x1FF0;
450 gb->memory.hdmaDest |= 0x8000;
451 bool wasHdma = gb->memory.isHdma;
452 gb->memory.isHdma = value & 0x80;
453 if (!wasHdma && !gb->memory.isHdma) {
454 gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10;
455 gb->memory.hdmaNext = gb->cpu->cycles;
456 gb->cpu->nextEvent = gb->cpu->cycles;
457 }
458}
459
460void _GBMemoryDMAService(struct GB* gb) {
461 uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
462 // TODO: Can DMA write OAM during modes 2-3?
463 gb->video.oam.raw[gb->memory.dmaDest] = b;
464 ++gb->memory.dmaSource;
465 ++gb->memory.dmaDest;
466 --gb->memory.dmaRemaining;
467 if (gb->memory.dmaRemaining) {
468 gb->memory.dmaNext += 4;
469 } else {
470 gb->memory.dmaNext = INT_MAX;
471 gb->cpu->memory.store8 = GBStore8;
472 gb->cpu->memory.load8 = GBLoad8;
473 }
474}
475
476void _GBMemoryHDMAService(struct GB* gb) {
477 uint8_t b = gb->cpu->memory.load8(gb->cpu, gb->memory.hdmaSource);
478 gb->cpu->memory.store8(gb->cpu, gb->memory.hdmaDest, b);
479 ++gb->memory.hdmaSource;
480 ++gb->memory.hdmaDest;
481 --gb->memory.hdmaRemaining;
482 gb->cpu->cycles += 2;
483 if (gb->memory.hdmaRemaining) {
484 gb->memory.hdmaNext += 2;
485 } else {
486 gb->memory.io[REG_HDMA1] = gb->memory.hdmaSource >> 8;
487 gb->memory.io[REG_HDMA2] = gb->memory.hdmaSource;
488 gb->memory.io[REG_HDMA3] = gb->memory.hdmaDest >> 8;
489 gb->memory.io[REG_HDMA4] = gb->memory.hdmaDest;
490 if (gb->memory.isHdma) {
491 --gb->memory.io[REG_HDMA5];
492 if (gb->memory.io[REG_HDMA5] == 0xFF) {
493 gb->memory.isHdma = false;
494 }
495 } else {
496 gb->memory.io[REG_HDMA5] |= 0x80;
497 }
498 }
499}
500
501struct OAMBlock {
502 uint16_t low;
503 uint16_t high;
504};
505
506static const struct OAMBlock _oamBlockDMG[] = {
507 { 0xA000, 0xFE00 },
508 { 0xA000, 0xFE00 },
509 { 0xA000, 0xFE00 },
510 { 0xA000, 0xFE00 },
511 { 0x8000, 0xA000 },
512 { 0xA000, 0xFE00 },
513 { 0xA000, 0xFE00 },
514 { 0xA000, 0xFE00 },
515};
516
517static const struct OAMBlock _oamBlockCGB[] = {
518 { 0xA000, 0xC000 },
519 { 0xA000, 0xC000 },
520 { 0xA000, 0xC000 },
521 { 0xA000, 0xC000 },
522 { 0x8000, 0xA000 },
523 { 0xA000, 0xC000 },
524 { 0xC000, 0xFE00 },
525 { 0xA000, 0xC000 },
526};
527
528uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) {
529 struct GB* gb = (struct GB*) cpu->master;
530 struct GBMemory* memory = &gb->memory;
531 const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB;
532 block = &block[memory->dmaSource >> 13];
533 if (address >= block->low && address < block->high) {
534 return 0xFF;
535 }
536 if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
537 return 0xFF;
538 }
539 return GBLoad8(cpu, address);
540}
541
542void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
543 struct GB* gb = (struct GB*) cpu->master;
544 struct GBMemory* memory = &gb->memory;
545 const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB;
546 block = &block[memory->dmaSource >> 13];
547 if (address >= block->low && address < block->high) {
548 return;
549 }
550 if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
551 return;
552 }
553 GBStore8(cpu, address, value);
554}
555
556void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old) {
557 struct GB* gb = (struct GB*) cpu->master;
558 struct GBMemory* memory = &gb->memory;
559 int8_t oldValue = -1;
560
561 switch (address >> 12) {
562 case GB_REGION_CART_BANK0:
563 case GB_REGION_CART_BANK0 + 1:
564 case GB_REGION_CART_BANK0 + 2:
565 case GB_REGION_CART_BANK0 + 3:
566 _pristineCow(gb);
567 oldValue = memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
568 memory->rom[address & (GB_SIZE_CART_BANK0 - 1)] = value;
569 break;
570 case GB_REGION_CART_BANK1:
571 case GB_REGION_CART_BANK1 + 1:
572 case GB_REGION_CART_BANK1 + 2:
573 case GB_REGION_CART_BANK1 + 3:
574 _pristineCow(gb);
575 oldValue = memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
576 memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)] = value;
577 break;
578 case GB_REGION_VRAM:
579 case GB_REGION_VRAM + 1:
580 oldValue = gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)];
581 gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value;
582 break;
583 case GB_REGION_EXTERNAL_RAM:
584 case GB_REGION_EXTERNAL_RAM + 1:
585 mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address);
586 return;
587 case GB_REGION_WORKING_RAM_BANK0:
588 case GB_REGION_WORKING_RAM_BANK0 + 2:
589 oldValue = memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
590 memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
591 break;
592 case GB_REGION_WORKING_RAM_BANK1:
593 oldValue = memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
594 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
595 break;
596 default:
597 if (address < GB_BASE_OAM) {
598 oldValue = memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
599 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
600 } else if (address < GB_BASE_UNUSABLE) {
601 oldValue = gb->video.oam.raw[address & 0xFF];
602 gb->video.oam.raw[address & 0xFF] = value;
603 } else if (address < GB_BASE_HRAM) {
604 mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address);
605 return;
606 } else if (address < GB_BASE_IE) {
607 oldValue = memory->hram[address & GB_SIZE_HRAM];
608 memory->hram[address & GB_SIZE_HRAM] = value;
609 } else {
610 mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address);
611 return;
612 }
613 }
614 if (old) {
615 *old = oldValue;
616 }
617}
618
619static void _switchBank(struct GBMemory* memory, int bank) {
620 size_t bankStart = bank * GB_SIZE_CART_BANK0;
621 if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
622 mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
623 bankStart &= (memory->romSize - 1);
624 bank = bankStart / GB_SIZE_CART_BANK0;
625 }
626 memory->romBank = &memory->rom[bankStart];
627 memory->currentBank = bank;
628}
629
630static void _switchSramBank(struct GBMemory* memory, int bank) {
631 size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
632 memory->sramBank = &memory->sram[bankStart];
633 memory->sramCurrentBank = bank;
634}
635
636static void _latchRtc(struct GBMemory* memory) {
637 time_t t;
638 struct mRTCSource* rtc = memory->rtc;
639 if (rtc) {
640 if (rtc->sample) {
641 rtc->sample(rtc);
642 }
643 t = rtc->unixTime(rtc);
644 } else {
645 t = time(0);
646 }
647 struct tm date;
648 localtime_r(&t, &date);
649 memory->rtcRegs[0] = date.tm_sec;
650 memory->rtcRegs[1] = date.tm_min;
651 memory->rtcRegs[2] = date.tm_hour;
652 memory->rtcRegs[3] = date.tm_yday; // TODO: Persist day counter
653 memory->rtcRegs[4] &= 0xF0;
654 memory->rtcRegs[4] |= date.tm_yday >> 8;
655}
656
657void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
658 int bank = value & 0x1F;
659 switch (address >> 13) {
660 case 0x0:
661 switch (value) {
662 case 0:
663 memory->sramAccess = false;
664 break;
665 case 0xA:
666 memory->sramAccess = true;
667 _switchSramBank(memory, memory->sramCurrentBank);
668 break;
669 default:
670 // TODO
671 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
672 break;
673 }
674 break;
675 case 0x1:
676 if (!bank) {
677 ++bank;
678 }
679 _switchBank(memory, bank | (memory->currentBank & 0x60));
680 break;
681 case 0x2:
682 bank &= 3;
683 if (!memory->mbcState.mbc1.mode) {
684 _switchBank(memory, (bank << 5) | (memory->currentBank & 0x1F));
685 } else {
686 _switchSramBank(memory, bank);
687 }
688 break;
689 case 0x3:
690 memory->mbcState.mbc1.mode = value & 1;
691 if (memory->mbcState.mbc1.mode) {
692 _switchBank(memory, memory->currentBank & 0x1F);
693 } else {
694 _switchSramBank(memory, 0);
695 }
696 break;
697 default:
698 // TODO
699 mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
700 break;
701 }
702}
703
704void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
705 int bank = value & 0xF;
706 switch (address >> 13) {
707 case 0x0:
708 switch (value) {
709 case 0:
710 memory->sramAccess = false;
711 break;
712 case 0xA:
713 memory->sramAccess = true;
714 _switchSramBank(memory, memory->sramCurrentBank);
715 break;
716 default:
717 // TODO
718 mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
719 break;
720 }
721 break;
722 case 0x1:
723 if (!bank) {
724 ++bank;
725 }
726 _switchBank(memory, bank);
727 break;
728 default:
729 // TODO
730 mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
731 break;
732 }}
733
734void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
735 int bank = value & 0x7F;
736 switch (address >> 13) {
737 case 0x0:
738 switch (value) {
739 case 0:
740 memory->sramAccess = false;
741 break;
742 case 0xA:
743 memory->sramAccess = true;
744 _switchSramBank(memory, memory->sramCurrentBank);
745 break;
746 default:
747 // TODO
748 mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
749 break;
750 }
751 break;
752 case 0x1:
753 if (!bank) {
754 ++bank;
755 }
756 _switchBank(memory, bank);
757 break;
758 case 0x2:
759 if (value < 4) {
760 _switchSramBank(memory, value);
761 memory->rtcAccess = false;
762 } else if (value >= 8 && value <= 0xC) {
763 memory->activeRtcReg = value - 8;
764 memory->rtcAccess = true;
765 }
766 break;
767 case 0x3:
768 if (memory->rtcLatched && value == 0) {
769 memory->rtcLatched = false;
770 } else if (!memory->rtcLatched && value == 1) {
771 _latchRtc(memory);
772 memory->rtcLatched = true;
773 }
774 break;
775 }
776}
777
778void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
779 int bank;
780 switch (address >> 12) {
781 case 0x0:
782 case 0x1:
783 switch (value) {
784 case 0:
785 memory->sramAccess = false;
786 break;
787 case 0xA:
788 memory->sramAccess = true;
789 _switchSramBank(memory, memory->sramCurrentBank);
790 break;
791 default:
792 // TODO
793 mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
794 break;
795 }
796 break;
797 case 0x2:
798 bank = (memory->currentBank & 0x100) | value;
799 _switchBank(memory, bank);
800 break;
801 case 0x3:
802 bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
803 _switchBank(memory, bank);
804 break;
805 case 0x4:
806 case 0x5:
807 if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) {
808 memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
809 value &= ~8;
810 }
811 _switchSramBank(memory, value & 0xF);
812 break;
813 default:
814 // TODO
815 mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
816 break;
817 }
818}
819
820void _GBMBC6(struct GBMemory* memory, uint16_t address, uint8_t value) {
821 // TODO
822 mLOG(GB_MBC, STUB, "MBC6 unimplemented");
823}
824
825void _GBMBC7(struct GBMemory* memory, uint16_t address, uint8_t value) {
826 int bank = value & 0x7F;
827 switch (address >> 13) {
828 case 0x1:
829 _switchBank(memory, bank);
830 break;
831 case 0x2:
832 if (value < 0x10) {
833 _switchSramBank(memory, value);
834 }
835 break;
836 default:
837 // TODO
838 mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
839 break;
840 }
841}
842
843uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) {
844 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
845 switch (address & 0xF0) {
846 case 0x00:
847 case 0x10:
848 case 0x60:
849 case 0x70:
850 return 0;
851 case 0x20:
852 if (memory->rotation && memory->rotation->readTiltX) {
853 int32_t x = -memory->rotation->readTiltX(memory->rotation);
854 x >>= 21;
855 x += 2047;
856 return x;
857 }
858 return 0xFF;
859 case 0x30:
860 if (memory->rotation && memory->rotation->readTiltX) {
861 int32_t x = -memory->rotation->readTiltX(memory->rotation);
862 x >>= 21;
863 x += 2047;
864 return x >> 8;
865 }
866 return 7;
867 case 0x40:
868 if (memory->rotation && memory->rotation->readTiltY) {
869 int32_t y = -memory->rotation->readTiltY(memory->rotation);
870 y >>= 21;
871 y += 2047;
872 return y;
873 }
874 return 0xFF;
875 case 0x50:
876 if (memory->rotation && memory->rotation->readTiltY) {
877 int32_t y = -memory->rotation->readTiltY(memory->rotation);
878 y >>= 21;
879 y += 2047;
880 return y >> 8;
881 }
882 return 7;
883 case 0x80:
884 return (mbc7->sr >> 16) & 1;
885 default:
886 return 0xFF;
887 }
888}
889
890void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
891 if ((address & 0xF0) != 0x80) {
892 return;
893 }
894 struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
895 GBMBC7Field old = memory->mbcState.mbc7.field;
896 mbc7->field = GBMBC7FieldClearIO(value);
897 if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
898 if (mbc7->state == GBMBC7_STATE_WRITE) {
899 if (mbc7->writable) {
900 memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8;
901 memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr;
902 }
903 mbc7->sr = 0x1FFFF;
904 mbc7->state = GBMBC7_STATE_NULL;
905 } else {
906 mbc7->state = GBMBC7_STATE_IDLE;
907 }
908 }
909 if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) {
910 if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) {
911 mbc7->sr <<= 1;
912 mbc7->sr |= GBMBC7FieldGetIO(value);
913 ++mbc7->srBits;
914 }
915 switch (mbc7->state) {
916 case GBMBC7_STATE_IDLE:
917 if (GBMBC7FieldIsIO(value)) {
918 mbc7->state = GBMBC7_STATE_READ_COMMAND;
919 mbc7->srBits = 0;
920 mbc7->sr = 0;
921 }
922 break;
923 case GBMBC7_STATE_READ_COMMAND:
924 if (mbc7->srBits == 2) {
925 mbc7->state = GBMBC7_STATE_READ_ADDRESS;
926 mbc7->srBits = 0;
927 mbc7->command = mbc7->sr;
928 }
929 break;
930 case GBMBC7_STATE_READ_ADDRESS:
931 if (mbc7->srBits == 8) {
932 mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command;
933 mbc7->srBits = 0;
934 mbc7->address = mbc7->sr;
935 if (mbc7->state == GBMBC7_STATE_COMMAND_0) {
936 switch (mbc7->address >> 6) {
937 case 0:
938 mbc7->writable = false;
939 mbc7->state = GBMBC7_STATE_NULL;
940 break;
941 case 3:
942 mbc7->writable = true;
943 mbc7->state = GBMBC7_STATE_NULL;
944 break;
945 }
946 }
947 }
948 break;
949 case GBMBC7_STATE_COMMAND_0:
950 if (mbc7->srBits == 16) {
951 switch (mbc7->address >> 6) {
952 case 0:
953 mbc7->writable = false;
954 mbc7->state = GBMBC7_STATE_NULL;
955 break;
956 case 1:
957 mbc7->state = GBMBC7_STATE_WRITE;
958 if (mbc7->writable) {
959 int i;
960 for (i = 0; i < 256; ++i) {
961 memory->sramBank[i * 2] = mbc7->sr >> 8;
962 memory->sramBank[i * 2 + 1] = mbc7->sr;
963 }
964 }
965 break;
966 case 2:
967 mbc7->state = GBMBC7_STATE_WRITE;
968 if (mbc7->writable) {
969 int i;
970 for (i = 0; i < 256; ++i) {
971 memory->sramBank[i * 2] = 0xFF;
972 memory->sramBank[i * 2 + 1] = 0xFF;
973 }
974 }
975 break;
976 case 3:
977 mbc7->writable = true;
978 mbc7->state = GBMBC7_STATE_NULL;
979 break;
980 }
981 }
982 break;
983 case GBMBC7_STATE_COMMAND_SR_WRITE:
984 if (mbc7->srBits == 16) {
985 mbc7->srBits = 0;
986 mbc7->state = GBMBC7_STATE_WRITE;
987 }
988 break;
989 case GBMBC7_STATE_COMMAND_SR_READ:
990 if (mbc7->srBits == 1) {
991 mbc7->sr = memory->sramBank[mbc7->address * 2] << 8;
992 mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1];
993 mbc7->srBits = 0;
994 mbc7->state = GBMBC7_STATE_READ;
995 }
996 break;
997 case GBMBC7_STATE_COMMAND_SR_FILL:
998 if (mbc7->srBits == 16) {
999 mbc7->sr = 0xFFFF;
1000 mbc7->srBits = 0;
1001 mbc7->state = GBMBC7_STATE_WRITE;
1002 }
1003 break;
1004 default:
1005 break;
1006 }
1007 } else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) {
1008 if (mbc7->state == GBMBC7_STATE_READ) {
1009 mbc7->sr <<= 1;
1010 ++mbc7->srBits;
1011 if (mbc7->srBits == 16) {
1012 mbc7->srBits = 0;
1013 mbc7->state = GBMBC7_STATE_NULL;
1014 }
1015 }
1016 }
1017}
1018
1019void _GBHuC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
1020 int bank = value & 0x3F;
1021 if (address & 0x1FFF) {
1022 mLOG(GB_MBC, STUB, "HuC-3 unknown value %04X:%02X", address, value);
1023 }
1024
1025 switch (address >> 13) {
1026 case 0x0:
1027 switch (value) {
1028 case 0xA:
1029 memory->sramAccess = true;
1030 _switchSramBank(memory, memory->sramCurrentBank);
1031 break;
1032 default:
1033 memory->sramAccess = false;
1034 break;
1035 }
1036 break;
1037 case 0x1:
1038 _switchBank(memory, bank);
1039 break;
1040 case 0x2:
1041 _switchSramBank(memory, bank);
1042 break;
1043 default:
1044 // TODO
1045 mLOG(GB_MBC, STUB, "HuC-3 unknown address: %04X:%02X", address, value);
1046 break;
1047 }
1048}
1049
1050void GBMemorySerialize(const struct GBMemory* memory, struct GBSerializedState* state) {
1051 memcpy(state->wram, memory->wram, GB_SIZE_WORKING_RAM);
1052 memcpy(state->hram, memory->hram, GB_SIZE_HRAM);
1053 STORE_16LE(memory->currentBank, 0, &state->memory.currentBank);
1054 state->memory.wramCurrentBank = memory->wramCurrentBank;
1055 state->memory.sramCurrentBank = memory->sramCurrentBank;
1056
1057 STORE_32LE(memory->dmaNext, 0, &state->memory.dmaNext);
1058 STORE_16LE(memory->dmaSource, 0, &state->memory.dmaSource);
1059 STORE_16LE(memory->dmaDest, 0, &state->memory.dmaDest);
1060
1061 STORE_32LE(memory->hdmaNext, 0, &state->memory.hdmaNext);
1062 STORE_16LE(memory->hdmaSource, 0, &state->memory.hdmaSource);
1063 STORE_16LE(memory->hdmaDest, 0, &state->memory.hdmaDest);
1064
1065 STORE_16LE(memory->hdmaRemaining, 0, &state->memory.hdmaRemaining);
1066 state->memory.dmaRemaining = memory->dmaRemaining;
1067 memcpy(state->memory.rtcRegs, memory->rtcRegs, sizeof(state->memory.rtcRegs));
1068
1069 GBSerializedMemoryFlags flags = 0;
1070 flags = GBSerializedMemoryFlagsSetSramAccess(flags, memory->sramAccess);
1071 flags = GBSerializedMemoryFlagsSetRtcAccess(flags, memory->rtcAccess);
1072 flags = GBSerializedMemoryFlagsSetRtcLatched(flags, memory->rtcLatched);
1073 flags = GBSerializedMemoryFlagsSetIme(flags, memory->ime);
1074 flags = GBSerializedMemoryFlagsSetIsHdma(flags, memory->isHdma);
1075 flags = GBSerializedMemoryFlagsSetActiveRtcReg(flags, memory->activeRtcReg);
1076 STORE_16LE(flags, 0, &state->memory.flags);
1077}
1078
1079void GBMemoryDeserialize(struct GBMemory* memory, const struct GBSerializedState* state) {
1080 memcpy(memory->wram, state->wram, GB_SIZE_WORKING_RAM);
1081 memcpy(memory->hram, state->hram, GB_SIZE_HRAM);
1082 LOAD_16LE(memory->currentBank, 0, &state->memory.currentBank);
1083 memory->wramCurrentBank = state->memory.wramCurrentBank;
1084 memory->sramCurrentBank = state->memory.sramCurrentBank;
1085
1086 _switchBank(memory, memory->currentBank);
1087 GBMemorySwitchWramBank(memory, memory->wramCurrentBank);
1088 _switchSramBank(memory, memory->sramCurrentBank);
1089
1090 LOAD_32LE(memory->dmaNext, 0, &state->memory.dmaNext);
1091 LOAD_16LE(memory->dmaSource, 0, &state->memory.dmaSource);
1092 LOAD_16LE(memory->dmaDest, 0, &state->memory.dmaDest);
1093
1094 LOAD_32LE(memory->hdmaNext, 0, &state->memory.hdmaNext);
1095 LOAD_16LE(memory->hdmaSource, 0, &state->memory.hdmaSource);
1096 LOAD_16LE(memory->hdmaDest, 0, &state->memory.hdmaDest);
1097
1098 LOAD_16LE(memory->hdmaRemaining, 0, &state->memory.hdmaRemaining);
1099 memory->dmaRemaining = state->memory.dmaRemaining;
1100 memcpy(memory->rtcRegs, state->memory.rtcRegs, sizeof(state->memory.rtcRegs));
1101
1102 GBSerializedMemoryFlags flags;
1103 LOAD_16LE(flags, 0, &state->memory.flags);
1104 memory->sramAccess = GBSerializedMemoryFlagsGetSramAccess(flags);
1105 memory->rtcAccess = GBSerializedMemoryFlagsGetRtcAccess(flags);
1106 memory->rtcLatched = GBSerializedMemoryFlagsGetRtcLatched(flags);
1107 memory->ime = GBSerializedMemoryFlagsGetIme(flags);
1108 memory->isHdma = GBSerializedMemoryFlagsGetIsHdma(flags);
1109 memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags);
1110}
1111
1112void _pristineCow(struct GB* gb) {
1113 if (gb->memory.rom != gb->pristineRom) {
1114 return;
1115 }
1116 gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX);
1117 memcpy(gb->memory.rom, gb->pristineRom, gb->memory.romSize);
1118 memset(((uint8_t*) gb->memory.rom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize);
1119 _switchBank(&gb->memory, gb->memory.currentBank);
1120}