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 "gb/gb.h"
9#include "gb/io.h"
10
11#include "util/memory.h"
12
13static void _GBMBCNone(struct GBMemory* memory, uint16_t address, uint8_t value) {
14 // TODO: Log game error
15 UNUSED(memory);
16 UNUSED(address);
17 UNUSED(value);
18}
19
20static void _GBMBC1(struct GBMemory*, uint16_t address, uint8_t value);
21static void _GBMBC2(struct GBMemory*, uint16_t address, uint8_t value);
22static void _GBMBC3(struct GBMemory*, uint16_t address, uint8_t value);
23static void _GBMBC4(struct GBMemory*, uint16_t address, uint8_t value);
24static void _GBMBC5(struct GBMemory*, uint16_t address, uint8_t value);
25
26static void GBSetActiveRegion(struct LR35902Core* cpu, uint16_t address) {
27 // TODO
28}
29
30static void _GBMemoryDMAService(struct GB* gb);
31
32
33void GBMemoryInit(struct GB* gb) {
34 struct LR35902Core* cpu = gb->cpu;
35 cpu->memory.load8 = GBLoad8;
36 cpu->memory.store8 = GBStore8;
37 cpu->memory.setActiveRegion = GBSetActiveRegion;
38
39 gb->memory.wram = 0;
40 gb->memory.wramBank = 0;
41 gb->memory.rom = 0;
42 gb->memory.romBank = 0;
43 gb->memory.romSize = 0;
44 gb->memory.mbcType = GB_MBC_NONE;
45 gb->memory.mbc = 0;
46
47 gb->memory.dmaNext = INT_MAX;
48 gb->memory.dmaRemaining = 0;
49
50 memset(gb->memory.hram, 0, sizeof(gb->memory.hram));
51
52 GBIOInit(gb);
53}
54
55void GBMemoryDeinit(struct GB* gb) {
56 mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
57 if (gb->memory.rom) {
58 mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
59 }
60 if (gb->memory.sram) {
61 mappedMemoryFree(gb->memory.sram, 0x8000);
62 }
63}
64
65void GBMemoryReset(struct GB* gb) {
66 if (gb->memory.wram) {
67 mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
68 }
69 gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
70 gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
71 gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
72 gb->memory.currentBank = 1;
73 gb->memory.sram = anonymousMemoryMap(0x8000); // TODO: Persist
74 gb->memory.sramCurrentBank = 0;
75
76 memset(&gb->video.oam, 0, sizeof(gb->video.oam));
77
78 const struct GBCartridge* cart = &gb->memory.rom[0x100];
79 switch (cart->type) {
80 case 0:
81 case 8:
82 case 9:
83 gb->memory.mbc = _GBMBCNone;
84 gb->memory.mbcType = GB_MBC_NONE;
85 break;
86 case 1:
87 case 2:
88 case 3:
89 gb->memory.mbc = _GBMBC1;
90 gb->memory.mbcType = GB_MBC1;
91 break;
92 case 5:
93 case 6:
94 gb->memory.mbc = _GBMBC2;
95 gb->memory.mbcType = GB_MBC2;
96 break;
97 case 0x0F:
98 case 0x10:
99 case 0x11:
100 case 0x12:
101 case 0x13:
102 gb->memory.mbc = _GBMBC3;
103 gb->memory.mbcType = GB_MBC3;
104 break;
105 case 0x15:
106 case 0x16:
107 case 0x17:
108 gb->memory.mbc = _GBMBC4;
109 gb->memory.mbcType = GB_MBC4;
110 break;
111 default:
112 // TODO: Log
113 case 0x19:
114 case 0x1A:
115 case 0x1B:
116 case 0x1C:
117 case 0x1D:
118 case 0x1E:
119 gb->memory.mbc = _GBMBC5;
120 gb->memory.mbcType = GB_MBC5;
121 break;
122 }
123
124 if (!gb->memory.wram) {
125 GBMemoryDeinit(gb);
126 }
127}
128
129uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
130 struct GB* gb = (struct GB*) cpu->master;
131 struct GBMemory* memory = &gb->memory;
132 switch (address >> 12) {
133 case GB_REGION_CART_BANK0:
134 case GB_REGION_CART_BANK0 + 1:
135 case GB_REGION_CART_BANK0 + 2:
136 case GB_REGION_CART_BANK0 + 3:
137 return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
138 case GB_REGION_CART_BANK1:
139 case GB_REGION_CART_BANK1 + 1:
140 case GB_REGION_CART_BANK1 + 2:
141 case GB_REGION_CART_BANK1 + 3:
142 return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
143 case GB_REGION_VRAM:
144 case GB_REGION_VRAM + 1:
145 return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
146 case GB_REGION_EXTERNAL_RAM:
147 case GB_REGION_EXTERNAL_RAM + 1:
148 if (memory->sramAccess) {
149 return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
150 }
151 return 0xFF;
152 case GB_REGION_WORKING_RAM_BANK0:
153 case GB_REGION_WORKING_RAM_BANK0 + 2:
154 return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
155 case GB_REGION_WORKING_RAM_BANK1:
156 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
157 default:
158 if (address < GB_BASE_OAM) {
159 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
160 }
161 if (address < GB_BASE_UNUSABLE) {
162 if (gb->video.mode < 2) {
163 return gb->video.oam.raw[address & 0xFF];
164 }
165 return 0xFF;
166 }
167 if (address < GB_BASE_IO) {
168 return 0xFF;
169 }
170 if (address < GB_BASE_HRAM) {
171 return GBIORead(gb, address & (GB_SIZE_IO - 1));
172 }
173 if (address < GB_BASE_IE) {
174 return memory->hram[address & GB_SIZE_HRAM];
175 }
176 return GBIORead(gb, REG_IE);
177 }
178}
179
180void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
181 struct GB* gb = (struct GB*) cpu->master;
182 struct GBMemory* memory = &gb->memory;
183 switch (address >> 12) {
184 case GB_REGION_CART_BANK0:
185 case GB_REGION_CART_BANK0 + 1:
186 case GB_REGION_CART_BANK0 + 2:
187 case GB_REGION_CART_BANK0 + 3:
188 case GB_REGION_CART_BANK1:
189 case GB_REGION_CART_BANK1 + 1:
190 case GB_REGION_CART_BANK1 + 2:
191 case GB_REGION_CART_BANK1 + 3:
192 memory->mbc(memory, address, value);
193 return;
194 case GB_REGION_VRAM:
195 case GB_REGION_VRAM + 1:
196 // TODO: Block access in wrong modes
197 gb->video.vram[address & (GB_SIZE_VRAM - 1)] = value;
198 gb->video.renderer->writeVRAM(gb->video.renderer, address & (GB_SIZE_VRAM - 1));
199 return;
200 case GB_REGION_EXTERNAL_RAM:
201 case GB_REGION_EXTERNAL_RAM + 1:
202 if (memory->sramAccess) {
203 gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
204 }
205 return;
206 case GB_REGION_WORKING_RAM_BANK0:
207 case GB_REGION_WORKING_RAM_BANK0 + 2:
208 memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
209 return;
210 case GB_REGION_WORKING_RAM_BANK1:
211 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
212 return;
213 default:
214 if (address < GB_BASE_OAM) {
215 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
216 } else if (address < GB_BASE_UNUSABLE) {
217 if (gb->video.mode < 2) {
218 gb->video.oam.raw[address & 0xFF] = value;
219 gb->video.renderer->writeOAM(gb->video.renderer, address & 0xFF);
220 }
221 } else if (address < GB_BASE_IO) {
222 // TODO: Log
223 } else if (address < GB_BASE_HRAM) {
224 GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
225 } else if (address < GB_BASE_IE) {
226 memory->hram[address & GB_SIZE_HRAM] = value;
227 } else {
228 GBIOWrite(gb, REG_IE, value);
229 }
230 }
231}
232
233int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles) {
234 if (!gb->memory.dmaRemaining) {
235 return INT_MAX;
236 }
237 gb->memory.dmaNext -= cycles;
238 if (gb->memory.dmaNext <= 0) {
239 _GBMemoryDMAService(gb);
240 }
241 return gb->memory.dmaNext;
242}
243
244void GBMemoryDMA(struct GB* gb, uint16_t base) {
245 if (base > 0xF100) {
246 return;
247 }
248 gb->cpu->memory.store8 = GBDMAStore8;
249 gb->cpu->memory.load8 = GBDMALoad8;
250 gb->memory.dmaNext = gb->cpu->cycles + 4;
251 if (gb->memory.dmaNext < gb->cpu->nextEvent) {
252 gb->cpu->nextEvent = gb->memory.dmaNext;
253 }
254 gb->memory.dmaSource = base;
255 gb->memory.dmaDest = GB_BASE_OAM;
256 gb->memory.dmaRemaining = 0xA0;
257}
258
259void _GBMemoryDMAService(struct GB* gb) {
260 uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
261 GBStore8(gb->cpu, gb->memory.dmaDest, b);
262 ++gb->memory.dmaSource;
263 ++gb->memory.dmaDest;
264 --gb->memory.dmaRemaining;
265 if (gb->memory.dmaRemaining) {
266 gb->memory.dmaNext += 4;
267 } else {
268 gb->memory.dmaNext = INT_MAX;
269 gb->cpu->memory.store8 = GBStore8;
270 gb->cpu->memory.load8 = GBLoad8;
271 }
272}
273
274uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) {
275 struct GB* gb = (struct GB*) cpu->master;
276 struct GBMemory* memory = &gb->memory;
277 if (address < 0xFF80 || address == 0xFFFF) {
278 return 0xFF;
279 }
280 return memory->hram[address & GB_SIZE_HRAM];
281}
282
283void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
284 struct GB* gb = (struct GB*) cpu->master;
285 struct GBMemory* memory = &gb->memory;
286 if (address < 0xFF80 || address == 0xFFFF) {
287 return;
288 }
289 memory->hram[address & GB_SIZE_HRAM] = value;
290}
291
292uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
293
294void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
295
296static void _switchBank(struct GBMemory* memory, int bank) {
297 size_t bankStart = bank * GB_SIZE_CART_BANK0;
298 if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
299 // TODO: Log
300 return;
301 }
302 memory->romBank = &memory->rom[bankStart];
303 memory->currentBank = bank;
304}
305
306static void _switchSramBank(struct GBMemory* memory, int bank) {
307 size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
308 memory->sramBank = &memory->sram[bankStart];
309 memory->sramCurrentBank = bank;
310}
311
312void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
313 int bank = value & 0x1F;
314 switch (address >> 13) {
315 case 0x0:
316 switch (value) {
317 case 0:
318 memory->sramAccess = false;
319 break;
320 case 0xA:
321 memory->sramAccess = true;
322 _switchSramBank(memory, memory->sramCurrentBank);
323 break;
324 default:
325 // TODO
326 break;
327 }
328 break;
329 break;
330 case 0x1:
331 if (!bank) {
332 ++bank;
333 }
334 _switchBank(memory, bank | (memory->currentBank & 0x60));
335 break;
336 }
337}
338
339void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
340 // TODO
341}
342
343void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
344 int bank = value & 0x7F;
345 switch (address >> 13) {
346 case 0x0:
347 switch (value) {
348 case 0:
349 memory->sramAccess = false;
350 break;
351 case 0xA:
352 memory->sramAccess = true;
353 _switchSramBank(memory, memory->sramCurrentBank);
354 break;
355 default:
356 // TODO
357 break;
358 }
359 break;
360 case 0x1:
361 if (!bank) {
362 ++bank;
363 }
364 _switchBank(memory, bank);
365 break;
366 case 0x2:
367 if (value < 4) {
368 _switchSramBank(memory, value);
369 }
370 break;
371 }
372}
373
374void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
375 // TODO
376}
377
378void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
379 int bank = value & 0x7F;
380 switch (address >> 13) {
381 case 0x0:
382 switch (value) {
383 case 0:
384 memory->sramAccess = false;
385 break;
386 case 0xA:
387 memory->sramAccess = true;
388 _switchSramBank(memory, memory->sramCurrentBank);
389 break;
390 default:
391 // TODO
392 break;
393 }
394 break;
395 break;
396 case 0x1:
397 _switchBank(memory, bank);
398 break;
399 }
400}