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