all repos — mgba @ e5379c99e015d33243a02da824f9b156264335ba

mGBA Game Boy Advance Emulator

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}