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 // TODO
138 return 0;
139 case GB_REGION_EXTERNAL_RAM:
140 case GB_REGION_EXTERNAL_RAM + 1:
141 // TODO
142 return 0;
143 case GB_REGION_WORKING_RAM_BANK0:
144 case GB_REGION_WORKING_RAM_BANK0 + 2:
145 return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
146 case GB_REGION_WORKING_RAM_BANK1:
147 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
148 default:
149 if (address < GB_BASE_OAM) {
150 return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
151 }
152 if (address < GB_BASE_IO) {
153 // TODO
154 return 0;
155 }
156 if (address < GB_BASE_HRAM) {
157 return GBIORead(gb, address & (GB_SIZE_IO - 1));
158 }
159 if (address < GB_BASE_IE) {
160 return memory->hram[address & GB_SIZE_HRAM];
161 }
162 return GBIORead(gb, REG_IE);
163 }
164}
165
166void GBStore16(struct LR35902Core* cpu, uint16_t address, int16_t value) {
167 // TODO
168}
169
170void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
171 struct GB* gb = (struct GB*) cpu->master;
172 struct GBMemory* memory = &gb->memory;
173 switch (address >> 12) {
174 case GB_REGION_CART_BANK0:
175 case GB_REGION_CART_BANK0 + 1:
176 case GB_REGION_CART_BANK0 + 2:
177 case GB_REGION_CART_BANK0 + 3:
178 case GB_REGION_CART_BANK1:
179 case GB_REGION_CART_BANK1 + 1:
180 case GB_REGION_CART_BANK1 + 2:
181 case GB_REGION_CART_BANK1 + 3:
182 memory->mbc(memory, address, value);
183 return;
184 case GB_REGION_VRAM:
185 case GB_REGION_VRAM + 1:
186 // TODO
187 return;
188 case GB_REGION_EXTERNAL_RAM:
189 case GB_REGION_EXTERNAL_RAM + 1:
190 // TODO
191 return;
192 case GB_REGION_WORKING_RAM_BANK0:
193 case GB_REGION_WORKING_RAM_BANK0 + 2:
194 memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
195 return;
196 case GB_REGION_WORKING_RAM_BANK1:
197 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
198 return;
199 default:
200 if (address < GB_BASE_OAM) {
201 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
202 } else if (address < GB_BASE_IO) {
203 // TODO
204 } else if (address < GB_BASE_HRAM) {
205 GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
206 } else if (address < GB_BASE_IE) {
207 memory->hram[address & GB_SIZE_HRAM] = value;
208 } else {
209 GBIOWrite(gb, REG_IE, value);
210 }
211 }
212}
213
214uint16_t GBView16(struct LR35902Core* cpu, uint16_t address);
215uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
216
217void GBPatch16(struct LR35902Core* cpu, uint16_t address, int16_t value, int16_t* old);
218void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
219
220static void _switchBank(struct GBMemory* memory, int bank) {
221 size_t bankStart = bank * GB_SIZE_CART_BANK0;
222 if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
223 // TODO: Log
224 return;
225 }
226 memory->romBank = &memory->rom[bankStart];
227 memory->currentBank = bank;
228}
229
230void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
231 int bank = value & 0x1F;
232 switch (address >> 13) {
233 case 0x0:
234 // TODO
235 break;
236 case 0x1:
237 if (!bank) {
238 ++bank;
239 }
240 _switchBank(memory, bank | (memory->currentBank & 0x60));
241 break;
242 }
243}
244
245void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
246 // TODO
247}
248
249void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
250 int bank = value & 0x7F;
251 switch (address >> 13) {
252 case 0x0:
253 // TODO
254 break;
255 case 0x1:
256 if (!bank) {
257 ++bank;
258 }
259 _switchBank(memory, bank);
260 break;
261 }
262}
263
264void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
265 // TODO
266}
267
268void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
269 int bank = value & 0x7F;
270 switch (address >> 13) {
271 case 0x0:
272 // TODO
273 break;
274 case 0x1:
275 _switchBank(memory, bank);
276 break;
277 }
278}