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
30void GBMemoryInit(struct GB* gb) {
31 struct LR35902Core* cpu = gb->cpu;
32 cpu->memory.load16 = GBLoad16;
33 cpu->memory.load8 = GBLoad8;
34 cpu->memory.store16 = GBStore16;
35 cpu->memory.store8 = GBStore8;
36 cpu->memory.setActiveRegion = GBSetActiveRegion;
37
38 gb->memory.wram = 0;
39 gb->memory.wramBank = 0;
40 gb->memory.rom = 0;
41 gb->memory.romBank = 0;
42 gb->memory.romSize = 0;
43 gb->memory.mbcType = GB_MBC_NONE;
44 gb->memory.mbc = 0;
45
46 memset(gb->memory.hram, 0, sizeof(gb->memory.hram));
47
48 GBIOInit(gb);
49}
50
51void GBMemoryDeinit(struct GB* gb) {
52 mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
53 if (gb->memory.rom) {
54 mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
55 }
56}
57
58void GBMemoryReset(struct GB* gb) {
59 if (gb->memory.wram) {
60 mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
61 }
62 gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
63 gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
64 gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
65
66 const struct GBCartridge* cart = &gb->memory.rom[0x100];
67 switch (cart->type) {
68 case 0:
69 case 8:
70 case 9:
71 gb->memory.mbc = _GBMBCNone;
72 gb->memory.mbcType = GB_MBC_NONE;
73 break;
74 case 1:
75 case 2:
76 case 3:
77 gb->memory.mbc = _GBMBC1;
78 gb->memory.mbcType = GB_MBC1;
79 break;
80 case 5:
81 case 6:
82 gb->memory.mbc = _GBMBC2;
83 gb->memory.mbcType = GB_MBC2;
84 break;
85 case 0x0F:
86 case 0x10:
87 case 0x11:
88 case 0x12:
89 case 0x13:
90 gb->memory.mbc = _GBMBC3;
91 gb->memory.mbcType = GB_MBC3;
92 break;
93 case 0x15:
94 case 0x16:
95 case 0x17:
96 gb->memory.mbc = _GBMBC4;
97 gb->memory.mbcType = GB_MBC4;
98 break;
99 default:
100 // TODO: Log
101 case 0x19:
102 case 0x1A:
103 case 0x1B:
104 case 0x1C:
105 case 0x1D:
106 case 0x1E:
107 gb->memory.mbc = _GBMBC5;
108 gb->memory.mbcType = GB_MBC5;
109 break;
110 }
111
112 if (!gb->memory.wram) {
113 GBMemoryDeinit(gb);
114 }
115}
116
117uint16_t GBLoad16(struct LR35902Core* cpu, uint16_t address) {
118 // TODO
119}
120
121uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
122 struct GB* gb = (struct GB*) cpu->master;
123 struct GBMemory* memory = &gb->memory;
124 switch (address >> 12) {
125 case GB_REGION_CART_BANK0:
126 case GB_REGION_CART_BANK0 + 1:
127 case GB_REGION_CART_BANK0 + 2:
128 case GB_REGION_CART_BANK0 + 3:
129 return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
130 case GB_REGION_CART_BANK1:
131 case GB_REGION_CART_BANK1 + 1:
132 case GB_REGION_CART_BANK1 + 2:
133 case GB_REGION_CART_BANK1 + 3:
134 return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
135 case GB_REGION_VRAM:
136 case GB_REGION_VRAM + 1:
137 return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
138 case GB_REGION_EXTERNAL_RAM:
139 case GB_REGION_EXTERNAL_RAM + 1:
140 // TODO
141 return 0;
142 case GB_REGION_WORKING_RAM_BANK0:
143 case GB_REGION_WORKING_RAM_BANK0 + 2:
144 return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
145 case GB_REGION_WORKING_RAM_BANK1:
146 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
147 default:
148 if (address < GB_BASE_OAM) {
149 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
150 }
151 if (address < GB_BASE_IO) {
152 // TODO
153 return 0;
154 }
155 if (address < GB_BASE_HRAM) {
156 return GBIORead(gb, address & (GB_SIZE_IO - 1));
157 }
158 if (address < GB_BASE_IE) {
159 return memory->hram[address & GB_SIZE_HRAM];
160 }
161 return GBIORead(gb, REG_IE);
162 }
163}
164
165void GBStore16(struct LR35902Core* cpu, uint16_t address, int16_t value) {
166 // TODO
167}
168
169void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
170 struct GB* gb = (struct GB*) cpu->master;
171 struct GBMemory* memory = &gb->memory;
172 switch (address >> 12) {
173 case GB_REGION_CART_BANK0:
174 case GB_REGION_CART_BANK0 + 1:
175 case GB_REGION_CART_BANK0 + 2:
176 case GB_REGION_CART_BANK0 + 3:
177 case GB_REGION_CART_BANK1:
178 case GB_REGION_CART_BANK1 + 1:
179 case GB_REGION_CART_BANK1 + 2:
180 case GB_REGION_CART_BANK1 + 3:
181 memory->mbc(memory, address, value);
182 return;
183 case GB_REGION_VRAM:
184 case GB_REGION_VRAM + 1:
185 // TODO: Block access in wrong modes
186 gb->video.vram[address & (GB_SIZE_VRAM - 1)] = value;
187 gb->video.renderer->writeVRAM(gb->video.renderer, address & (GB_SIZE_VRAM - 1));
188 return;
189 case GB_REGION_EXTERNAL_RAM:
190 case GB_REGION_EXTERNAL_RAM + 1:
191 // TODO
192 return;
193 case GB_REGION_WORKING_RAM_BANK0:
194 case GB_REGION_WORKING_RAM_BANK0 + 2:
195 memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
196 return;
197 case GB_REGION_WORKING_RAM_BANK1:
198 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
199 return;
200 default:
201 if (address < GB_BASE_OAM) {
202 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
203 } else if (address < GB_BASE_IO) {
204 // TODO
205 } else if (address < GB_BASE_HRAM) {
206 GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
207 } else if (address < GB_BASE_IE) {
208 memory->hram[address & GB_SIZE_HRAM] = value;
209 } else {
210 GBIOWrite(gb, REG_IE, value);
211 }
212 }
213}
214
215uint16_t GBView16(struct LR35902Core* cpu, uint16_t address);
216uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
217
218void GBPatch16(struct LR35902Core* cpu, uint16_t address, int16_t value, int16_t* old);
219void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
220
221static void _switchBank(struct GBMemory* memory, int bank) {
222 size_t bankStart = bank * GB_SIZE_CART_BANK0;
223 if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
224 // TODO: Log
225 return;
226 }
227 memory->romBank = &memory->rom[bankStart];
228 memory->currentBank = bank;
229}
230
231void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
232 int bank = value & 0x1F;
233 switch (address >> 13) {
234 case 0x0:
235 // TODO
236 break;
237 case 0x1:
238 if (!bank) {
239 ++bank;
240 }
241 _switchBank(memory, bank | (memory->currentBank & 0x60));
242 break;
243 }
244}
245
246void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
247 // TODO
248}
249
250void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
251 int bank = value & 0x7F;
252 switch (address >> 13) {
253 case 0x0:
254 // TODO
255 break;
256 case 0x1:
257 if (!bank) {
258 ++bank;
259 }
260 _switchBank(memory, bank);
261 break;
262 }
263}
264
265void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
266 // TODO
267}
268
269void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
270 int bank = value & 0x7F;
271 switch (address >> 13) {
272 case 0x0:
273 // TODO
274 break;
275 case 0x1:
276 _switchBank(memory, bank);
277 break;
278 }
279}