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