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 gb->memory.currentBank = 1;
66
67 const struct GBCartridge* cart = &gb->memory.rom[0x100];
68 switch (cart->type) {
69 case 0:
70 case 8:
71 case 9:
72 gb->memory.mbc = _GBMBCNone;
73 gb->memory.mbcType = GB_MBC_NONE;
74 break;
75 case 1:
76 case 2:
77 case 3:
78 gb->memory.mbc = _GBMBC1;
79 gb->memory.mbcType = GB_MBC1;
80 break;
81 case 5:
82 case 6:
83 gb->memory.mbc = _GBMBC2;
84 gb->memory.mbcType = GB_MBC2;
85 break;
86 case 0x0F:
87 case 0x10:
88 case 0x11:
89 case 0x12:
90 case 0x13:
91 gb->memory.mbc = _GBMBC3;
92 gb->memory.mbcType = GB_MBC3;
93 break;
94 case 0x15:
95 case 0x16:
96 case 0x17:
97 gb->memory.mbc = _GBMBC4;
98 gb->memory.mbcType = GB_MBC4;
99 break;
100 default:
101 // TODO: Log
102 case 0x19:
103 case 0x1A:
104 case 0x1B:
105 case 0x1C:
106 case 0x1D:
107 case 0x1E:
108 gb->memory.mbc = _GBMBC5;
109 gb->memory.mbcType = GB_MBC5;
110 break;
111 }
112
113 if (!gb->memory.wram) {
114 GBMemoryDeinit(gb);
115 }
116}
117
118uint16_t GBLoad16(struct LR35902Core* cpu, uint16_t address) {
119 // TODO
120}
121
122uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
123 struct GB* gb = (struct GB*) cpu->master;
124 struct GBMemory* memory = &gb->memory;
125 switch (address >> 12) {
126 case GB_REGION_CART_BANK0:
127 case GB_REGION_CART_BANK0 + 1:
128 case GB_REGION_CART_BANK0 + 2:
129 case GB_REGION_CART_BANK0 + 3:
130 return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
131 case GB_REGION_CART_BANK1:
132 case GB_REGION_CART_BANK1 + 1:
133 case GB_REGION_CART_BANK1 + 2:
134 case GB_REGION_CART_BANK1 + 3:
135 return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
136 case GB_REGION_VRAM:
137 case GB_REGION_VRAM + 1:
138 return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
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: Block access in wrong modes
187 gb->video.vram[address & (GB_SIZE_VRAM - 1)] = value;
188 gb->video.renderer->writeVRAM(gb->video.renderer, address & (GB_SIZE_VRAM - 1));
189 return;
190 case GB_REGION_EXTERNAL_RAM:
191 case GB_REGION_EXTERNAL_RAM + 1:
192 // TODO
193 return;
194 case GB_REGION_WORKING_RAM_BANK0:
195 case GB_REGION_WORKING_RAM_BANK0 + 2:
196 memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
197 return;
198 case GB_REGION_WORKING_RAM_BANK1:
199 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
200 return;
201 default:
202 if (address < GB_BASE_OAM) {
203 memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
204 } else if (address < GB_BASE_IO) {
205 // TODO
206 } else if (address < GB_BASE_HRAM) {
207 GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
208 } else if (address < GB_BASE_IE) {
209 memory->hram[address & GB_SIZE_HRAM] = value;
210 } else {
211 GBIOWrite(gb, REG_IE, value);
212 }
213 }
214}
215
216uint16_t GBView16(struct LR35902Core* cpu, uint16_t address);
217uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
218
219void GBPatch16(struct LR35902Core* cpu, uint16_t address, int16_t value, int16_t* old);
220void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
221
222static void _switchBank(struct GBMemory* memory, int bank) {
223 size_t bankStart = bank * GB_SIZE_CART_BANK0;
224 if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
225 // TODO: Log
226 return;
227 }
228 memory->romBank = &memory->rom[bankStart];
229 memory->currentBank = bank;
230}
231
232void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
233 int bank = value & 0x1F;
234 switch (address >> 13) {
235 case 0x0:
236 // TODO
237 break;
238 case 0x1:
239 if (!bank) {
240 ++bank;
241 }
242 _switchBank(memory, bank | (memory->currentBank & 0x60));
243 break;
244 }
245}
246
247void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
248 // TODO
249}
250
251void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
252 int bank = value & 0x7F;
253 switch (address >> 13) {
254 case 0x0:
255 // TODO
256 break;
257 case 0x1:
258 if (!bank) {
259 ++bank;
260 }
261 _switchBank(memory, bank);
262 break;
263 }
264}
265
266void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
267 // TODO
268}
269
270void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
271 int bank = value & 0x7F;
272 switch (address >> 13) {
273 case 0x0:
274 // TODO
275 break;
276 case 0x1:
277 _switchBank(memory, bank);
278 break;
279 }
280}