all repos — mgba @ 7c5a6b121c4d9d4287ce0d178ea2cede753d808c

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 <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}