all repos — mgba @ 133d574667b66c760897811f3e64a9f400184af1

mGBA Game Boy Advance Emulator

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}