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