src/gba.c (view raw)
1#include "gba.h"
2
3#include "debugger.h"
4
5#include <stdarg.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <sys/mman.h>
9#include <unistd.h>
10
11static const char* GBA_CANNOT_MMAP = "Could not map memory";
12
13static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t region);
14static void GBAHitStub(struct ARMBoard* board, uint32_t opcode);
15
16void GBAInit(struct GBA* gba) {
17 gba->errno = GBA_NO_ERROR;
18 gba->errstr = 0;
19
20 ARMInit(&gba->cpu);
21
22 gba->memory.p = gba;
23 GBAMemoryInit(&gba->memory);
24 ARMAssociateMemory(&gba->cpu, &gba->memory.d);
25
26 GBABoardInit(&gba->board);
27 ARMAssociateBoard(&gba->cpu, &gba->board.d);
28
29 ARMReset(&gba->cpu);
30}
31
32void GBADeinit(struct GBA* gba) {
33 GBAMemoryDeinit(&gba->memory);
34}
35
36void GBAMemoryInit(struct GBAMemory* memory) {
37 memory->d.load32 = GBALoad32;
38 memory->d.load16 = GBALoad16;
39 memory->d.loadU16 = GBALoadU16;
40 memory->d.load8 = GBALoad8;
41 memory->d.loadU8 = GBALoadU8;
42 memory->d.store32 = GBAStore32;
43 memory->d.store16 = GBAStore16;
44 memory->d.store8 = GBAStore8;
45
46 memory->bios = 0;
47 memory->wram = mmap(0, SIZE_WORKING_RAM, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
48 memory->iwram = mmap(0, SIZE_WORKING_IRAM, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
49 memory->rom = 0;
50
51 if (!memory->wram || !memory->iwram) {
52 GBAMemoryDeinit(memory);
53 memory->p->errno = GBA_OUT_OF_MEMORY;
54 memory->p->errstr = GBA_CANNOT_MMAP;
55 }
56
57 memory->d.activeRegion = 0;
58 memory->d.activeMask = 0;
59 memory->d.setActiveRegion = GBASetActiveRegion;
60}
61
62void GBAMemoryDeinit(struct GBAMemory* memory) {
63 munmap(memory->wram, SIZE_WORKING_RAM);
64 munmap(memory->iwram, SIZE_WORKING_IRAM);
65}
66
67void GBABoardInit(struct GBABoard* board) {
68 board->d.reset = GBABoardReset;
69 board->d.hitStub = GBAHitStub;
70}
71
72void GBABoardReset(struct ARMBoard* board) {
73 struct ARMCore* cpu = board->cpu;
74 ARMSetPrivilegeMode(cpu, MODE_IRQ);
75 cpu->gprs[ARM_SP] = SP_BASE_IRQ;
76 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
77 cpu->gprs[ARM_SP] = SP_BASE_SUPERVISOR;
78 ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
79 cpu->gprs[ARM_SP] = SP_BASE_SYSTEM;
80}
81
82void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger) {
83 ARMDebuggerInit(debugger, &gba->cpu);
84 gba->debugger = debugger;
85}
86
87void GBALoadROM(struct GBA* gba, int fd) {
88 gba->memory.rom = mmap(0, SIZE_CART0, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FILE, fd, 0);
89 // TODO: error check
90}
91
92static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t address) {
93 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
94
95 switch (address & ~OFFSET_MASK) {
96 case BASE_BIOS:
97 memory->activeRegion = gbaMemory->bios;
98 memory->activeMask = 0;
99 break;
100 case BASE_WORKING_RAM:
101 memory->activeRegion = gbaMemory->wram;
102 memory->activeMask = SIZE_WORKING_RAM - 1;
103 break;
104 case BASE_WORKING_IRAM:
105 memory->activeRegion = gbaMemory->iwram;
106 memory->activeMask = SIZE_WORKING_IRAM - 1;
107 break;
108 case BASE_CART0:
109 case BASE_CART0_EX:
110 case BASE_CART1:
111 case BASE_CART1_EX:
112 case BASE_CART2:
113 case BASE_CART2_EX:
114 memory->activeRegion = gbaMemory->rom;
115 memory->activeMask = SIZE_CART0 - 1;
116 break;
117 default:
118 memory->activeRegion = 0;
119 memory->activeMask = 0;
120 break;
121 }
122}
123
124int32_t GBALoad32(struct ARMMemory* memory, uint32_t address) {
125 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
126
127 switch (address & ~OFFSET_MASK) {
128 case BASE_BIOS:
129 break;
130 case BASE_WORKING_RAM:
131 return gbaMemory->wram[(address & (SIZE_WORKING_RAM - 1)) >> 2];
132 case BASE_WORKING_IRAM:
133 return gbaMemory->iwram[(address & (SIZE_WORKING_IRAM - 1)) >> 2];
134 case BASE_IO:
135 break;
136 case BASE_PALETTE_RAM:
137 break;
138 case BASE_VRAM:
139 break;
140 case BASE_OAM:
141 break;
142 case BASE_CART0:
143 case BASE_CART0_EX:
144 case BASE_CART1:
145 case BASE_CART1_EX:
146 case BASE_CART2:
147 case BASE_CART2_EX:
148 return gbaMemory->rom[(address & (SIZE_CART0 - 1)) >> 2];
149 case BASE_CART_SRAM:
150 break;
151 default:
152 break;
153 }
154
155 return 0;
156}
157
158int16_t GBALoad16(struct ARMMemory* memory, uint32_t address) {
159 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
160
161 switch (address & ~OFFSET_MASK) {
162 case BASE_BIOS:
163 break;
164 case BASE_WORKING_RAM:
165 return ((int16_t*) gbaMemory->wram)[(address & (SIZE_WORKING_RAM - 1)) >> 1];
166 case BASE_WORKING_IRAM:
167 return ((int16_t*) gbaMemory->iwram)[(address & (SIZE_WORKING_IRAM - 1)) >> 1];
168 case BASE_IO:
169 break;
170 case BASE_PALETTE_RAM:
171 break;
172 case BASE_VRAM:
173 break;
174 case BASE_OAM:
175 break;
176 case BASE_CART0:
177 case BASE_CART0_EX:
178 case BASE_CART1:
179 case BASE_CART1_EX:
180 case BASE_CART2:
181 case BASE_CART2_EX:
182 return ((int16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1];
183 case BASE_CART_SRAM:
184 break;
185 default:
186 break;
187 }
188
189 return 0;
190}
191
192uint16_t GBALoadU16(struct ARMMemory* memory, uint32_t address) {
193 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
194
195 switch (address & ~OFFSET_MASK) {
196 case BASE_BIOS:
197 break;
198 case BASE_WORKING_RAM:
199 return ((uint16_t*) gbaMemory->wram)[(address & (SIZE_WORKING_RAM - 1)) >> 1];
200 case BASE_WORKING_IRAM:
201 return ((uint16_t*) gbaMemory->iwram)[(address & (SIZE_WORKING_IRAM - 1)) >> 1];
202 case BASE_IO:
203 break;
204 case BASE_PALETTE_RAM:
205 break;
206 case BASE_VRAM:
207 break;
208 case BASE_OAM:
209 break;
210 case BASE_CART0:
211 case BASE_CART0_EX:
212 case BASE_CART1:
213 case BASE_CART1_EX:
214 case BASE_CART2:
215 case BASE_CART2_EX:
216 return ((uint16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1];
217 case BASE_CART_SRAM:
218 break;
219 default:
220 break;
221 }
222
223 return 0;
224}
225
226int8_t GBALoad8(struct ARMMemory* memory, uint32_t address) {
227 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
228
229 switch (address & ~OFFSET_MASK) {
230 case BASE_BIOS:
231 break;
232 case BASE_WORKING_RAM:
233 return ((int8_t*) gbaMemory->wram)[address & (SIZE_WORKING_RAM - 1)];
234 case BASE_WORKING_IRAM:
235 return ((int8_t*) gbaMemory->iwram)[address & (SIZE_WORKING_IRAM - 1)];
236 case BASE_IO:
237 break;
238 case BASE_PALETTE_RAM:
239 break;
240 case BASE_VRAM:
241 break;
242 case BASE_OAM:
243 break;
244 case BASE_CART0:
245 case BASE_CART0_EX:
246 case BASE_CART1:
247 case BASE_CART1_EX:
248 case BASE_CART2:
249 case BASE_CART2_EX:
250 return ((int8_t*) gbaMemory->rom)[address & (SIZE_CART0 - 1)];
251 case BASE_CART_SRAM:
252 break;
253 default:
254 break;
255 }
256
257 return 0;
258}
259
260uint8_t GBALoadU8(struct ARMMemory* memory, uint32_t address) {
261 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
262
263 switch (address & ~OFFSET_MASK) {
264 case BASE_BIOS:
265 break;
266 case BASE_WORKING_RAM:
267 return ((uint8_t*) gbaMemory->wram)[address & (SIZE_WORKING_RAM - 1)];
268 break;
269 case BASE_WORKING_IRAM:
270 return ((uint8_t*) gbaMemory->iwram)[address & (SIZE_WORKING_IRAM - 1)];
271 break;
272 case BASE_IO:
273 break;
274 case BASE_PALETTE_RAM:
275 break;
276 case BASE_VRAM:
277 break;
278 case BASE_OAM:
279 break;
280 case BASE_CART0:
281 case BASE_CART0_EX:
282 case BASE_CART1:
283 case BASE_CART1_EX:
284 case BASE_CART2:
285 case BASE_CART2_EX:
286 return ((uint8_t*) gbaMemory->rom)[address & (SIZE_CART0 - 1)];
287 case BASE_CART_SRAM:
288 break;
289 default:
290 break;
291 }
292
293 return 0;
294}
295
296void GBAStore32(struct ARMMemory* memory, uint32_t address, int32_t value) {
297 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
298
299 switch (address & ~OFFSET_MASK) {
300 case BASE_WORKING_RAM:
301 gbaMemory->wram[(address & (SIZE_WORKING_RAM - 1)) >> 2] = value;
302 break;
303 case BASE_WORKING_IRAM:
304 gbaMemory->iwram[(address & (SIZE_WORKING_IRAM - 1)) >> 2] = value;
305 break;
306 case BASE_IO:
307 break;
308 case BASE_PALETTE_RAM:
309 break;
310 case BASE_VRAM:
311 break;
312 case BASE_OAM:
313 break;
314 case BASE_CART0:
315 break;
316 case BASE_CART2_EX:
317 break;
318 case BASE_CART_SRAM:
319 break;
320 default:
321 break;
322 }
323}
324
325void GBAStore16(struct ARMMemory* memory, uint32_t address, int16_t value) {
326 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
327
328 switch (address & ~OFFSET_MASK) {
329 case BASE_WORKING_RAM:
330 ((int16_t*) gbaMemory->wram)[(address & (SIZE_WORKING_RAM - 1)) >> 1] = value;
331 break;
332 case BASE_WORKING_IRAM:
333 ((int16_t*) gbaMemory->iwram)[(address & (SIZE_WORKING_IRAM - 1)) >> 1] = value;
334 break;
335 case BASE_IO:
336 break;
337 case BASE_PALETTE_RAM:
338 break;
339 case BASE_VRAM:
340 break;
341 case BASE_OAM:
342 break;
343 case BASE_CART0:
344 break;
345 case BASE_CART2_EX:
346 break;
347 case BASE_CART_SRAM:
348 break;
349 default:
350 break;
351 }
352}
353
354void GBAStore8(struct ARMMemory* memory, uint32_t address, int8_t value) {
355 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
356
357 switch (address & ~OFFSET_MASK) {
358 case BASE_WORKING_RAM:
359 ((int8_t*) gbaMemory->wram)[address & (SIZE_WORKING_RAM - 1)] = value;
360 break;
361 case BASE_WORKING_IRAM:
362 ((int8_t*) gbaMemory->iwram)[address & (SIZE_WORKING_IRAM - 1)] = value;
363 break;
364 case BASE_IO:
365 break;
366 case BASE_PALETTE_RAM:
367 break;
368 case BASE_VRAM:
369 break;
370 case BASE_OAM:
371 break;
372 case BASE_CART0:
373 break;
374 case BASE_CART2_EX:
375 break;
376 case BASE_CART_SRAM:
377 break;
378 default:
379 break;
380 }
381}
382
383void GBALog(int level, const char* format, ...) {
384 va_list args;
385 va_start(args, format);
386 vprintf(format, args);
387 va_end(args);
388 printf("\n");
389}
390
391void GBAHitStub(struct ARMBoard* board, uint32_t opcode) {
392 GBALog(GBA_LOG_STUB, "Stub opcode: %08x", opcode);
393 abort();
394}