all repos — mgba @ f32e92e0f16db74668be2d10f56a6e0f10c7f214

mGBA Game Boy Advance Emulator

src/ds/memory.c (view raw)

  1/* Copyright (c) 2013-2016 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "memory.h"
  7
  8#include "arm/macros.h"
  9
 10#include "ds/ds.h"
 11#include "util/math.h"
 12#include "util/memory.h"
 13
 14mLOG_DEFINE_CATEGORY(DS_MEM, "DS Memory");
 15
 16#define LDM_LOOP(LDM) \
 17	for (i = 0; i < 16; i += 4) { \
 18		if (UNLIKELY(mask & (1 << i))) { \
 19			LDM; \
 20			cpu->gprs[i] = value; \
 21			++wait; \
 22			address += 4; \
 23		} \
 24		if (UNLIKELY(mask & (2 << i))) { \
 25			LDM; \
 26			cpu->gprs[i + 1] = value; \
 27			++wait; \
 28			address += 4; \
 29		} \
 30		if (UNLIKELY(mask & (4 << i))) { \
 31			LDM; \
 32			cpu->gprs[i + 2] = value; \
 33			++wait; \
 34			address += 4; \
 35		} \
 36		if (UNLIKELY(mask & (8 << i))) { \
 37			LDM; \
 38			cpu->gprs[i + 3] = value; \
 39			++wait; \
 40			address += 4; \
 41		} \
 42	}
 43
 44#define STM_LOOP(STM) \
 45	for (i = 0; i < 16; i += 4) { \
 46		if (UNLIKELY(mask & (1 << i))) { \
 47			value = cpu->gprs[i]; \
 48			STM; \
 49			++wait; \
 50			address += 4; \
 51		} \
 52		if (UNLIKELY(mask & (2 << i))) { \
 53			value = cpu->gprs[i + 1]; \
 54			STM; \
 55			++wait; \
 56			address += 4; \
 57		} \
 58		if (UNLIKELY(mask & (4 << i))) { \
 59			value = cpu->gprs[i + 2]; \
 60			STM; \
 61			++wait; \
 62			address += 4; \
 63		} \
 64		if (UNLIKELY(mask & (8 << i))) { \
 65			value = cpu->gprs[i + 3]; \
 66			STM; \
 67			++wait; \
 68			address += 4; \
 69		} \
 70	}
 71
 72
 73static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
 74
 75static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
 76static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
 77static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
 78
 79static const int DMA_OFFSET[] = { 1, -1, 0, 1 };
 80
 81void DSMemoryInit(struct DS* ds) {
 82	struct ARMCore* arm7 = ds->arm7;
 83	arm7->memory.load32 = DS7Load32;
 84	arm7->memory.load16 = DS7Load16;
 85	arm7->memory.load8 = DS7Load8;
 86	arm7->memory.loadMultiple = DS7LoadMultiple;
 87	arm7->memory.store32 = DS7Store32;
 88	arm7->memory.store16 = DS7Store16;
 89	arm7->memory.store8 = DS7Store8;
 90	arm7->memory.storeMultiple = DS7StoreMultiple;
 91	arm7->memory.stall = DSMemoryStall;
 92
 93	struct ARMCore* arm9 = ds->arm9;
 94	arm9->memory.load32 = DS9Load32;
 95	arm9->memory.load16 = DS9Load16;
 96	arm9->memory.load8 = DS9Load8;
 97	arm9->memory.loadMultiple = DS9LoadMultiple;
 98	arm9->memory.store32 = DS9Store32;
 99	arm9->memory.store16 = DS9Store16;
100	arm9->memory.store8 = DS9Store8;
101	arm9->memory.storeMultiple = DS9StoreMultiple;
102	arm9->memory.stall = DSMemoryStall;
103
104	ds->memory.bios7 = NULL;
105	ds->memory.bios9 = NULL;
106	ds->memory.wram = NULL;
107	ds->memory.ram = NULL;
108	ds->memory.rom = NULL;
109
110	ds->memory.activeRegion7 = -1;
111	ds->memory.activeRegion9 = -1;
112
113	arm7->memory.activeRegion = 0;
114	arm7->memory.activeMask = 0;
115	arm7->memory.setActiveRegion = DS7SetActiveRegion;
116	arm7->memory.activeSeqCycles32 = 0;
117	arm7->memory.activeSeqCycles16 = 0;
118	arm7->memory.activeNonseqCycles32 = 0;
119	arm7->memory.activeNonseqCycles16 = 0;
120
121	arm9->memory.activeRegion = 0;
122	arm9->memory.activeMask = 0;
123	arm9->memory.setActiveRegion = DS9SetActiveRegion;
124	arm9->memory.activeSeqCycles32 = 0;
125	arm9->memory.activeSeqCycles16 = 0;
126	arm9->memory.activeNonseqCycles32 = 0;
127	arm9->memory.activeNonseqCycles16 = 0;
128}
129
130void DSMemoryDeinit(struct DS* ds) {
131	mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
132	mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
133}
134
135void DSMemoryReset(struct DS* ds) {
136	if (ds->memory.wram) {
137		mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
138	}
139	ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM);
140
141	if (ds->memory.ram) {
142		mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
143	}
144	ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
145
146	memset(ds->memory.dma7, 0, sizeof(ds->memory.dma7));
147	memset(ds->memory.dma9, 0, sizeof(ds->memory.dma9));
148	ds->memory.activeDMA7 = -1;
149	ds->memory.activeDMA9 = -1;
150	ds->memory.nextDMA = INT_MAX;
151	ds->memory.eventDiff = 0;
152
153	if (!ds->memory.wram || !ds->memory.ram) {
154		DSMemoryDeinit(ds);
155		mLOG(DS_MEM, FATAL, "Could not map memory");
156	}
157}
158
159static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
160	struct DS* ds = (struct DS*) cpu->master;
161	struct DSMemory* memory = &ds->memory;
162
163	int newRegion = address >> DS_BASE_OFFSET;
164
165	memory->activeRegion7 = newRegion;
166	switch (newRegion) {
167	case DS_REGION_RAM:
168		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
169			cpu->memory.activeRegion = memory->ram;
170			cpu->memory.activeMask = DS_SIZE_RAM - 1;
171			return;
172		}
173		break;
174	case DS7_REGION_BIOS:
175		if (memory->bios7) {
176			cpu->memory.activeRegion = memory->bios9;
177			cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
178		} else {
179			cpu->memory.activeRegion = _deadbeef;
180			cpu->memory.activeMask = 0;
181		}
182		return;
183	default:
184		break;
185	}
186	cpu->memory.activeRegion = _deadbeef;
187	cpu->memory.activeMask = 0;
188	mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
189	return;
190}
191
192uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
193	struct DS* ds = (struct DS*) cpu->master;
194	struct DSMemory* memory = &ds->memory;
195	uint32_t value = 0;
196	int wait = 0;
197
198	switch (address >> DS_BASE_OFFSET) {
199	case DS_REGION_RAM:
200		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
201			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
202		}
203		break;
204	default:
205		break;
206	}
207
208	if (cycleCounter) {
209		wait += 2;
210		*cycleCounter += wait;
211	}
212	// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
213	int rotate = (address & 3) << 3;
214	return ROR(value, rotate);
215}
216
217uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
218	struct DS* ds = (struct DS*) cpu->master;
219	struct DSMemory* memory = &ds->memory;
220	uint32_t value = 0;
221	int wait = 0;
222
223	switch (address >> DS_BASE_OFFSET) {
224	default:
225		break;
226	}
227
228	if (cycleCounter) {
229		wait += 2;
230		*cycleCounter += wait;
231	}
232	// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
233	int rotate = (address & 1) << 3;
234	return ROR(value, rotate);
235}
236
237uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
238	struct DS* ds = (struct DS*) cpu->master;
239	struct DSMemory* memory = &ds->memory;
240	uint32_t value = 0;
241	int wait = 0;
242
243	switch (address >> DS_BASE_OFFSET) {
244	default:
245		break;
246	}
247
248	if (cycleCounter) {
249		wait += 2;
250		*cycleCounter += wait;
251	}
252	return value;
253}
254
255void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
256	struct DS* ds = (struct DS*) cpu->master;
257	struct DSMemory* memory = &ds->memory;
258	int wait = 0;
259
260	switch (address >> DS_BASE_OFFSET) {
261		break;
262	}
263
264	if (cycleCounter) {
265		++wait;
266		*cycleCounter += wait;
267	}
268}
269
270void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
271	struct DS* ds = (struct DS*) cpu->master;
272	struct DSMemory* memory = &ds->memory;
273	int wait = 0;
274
275	switch (address >> DS_BASE_OFFSET) {
276	default:
277		break;
278	}
279
280	if (cycleCounter) {
281		++wait;
282		*cycleCounter += wait;
283	}
284}
285
286void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
287	struct DS* ds = (struct DS*) cpu->master;
288	struct DSMemory* memory = &ds->memory;
289	int wait = 0;
290
291	switch (address >> DS_BASE_OFFSET) {
292	default:
293		break;
294	}
295
296	if (cycleCounter) {
297		++wait;
298		*cycleCounter += wait;
299	}
300}
301
302uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
303	struct DS* ds = (struct DS*) cpu->master;
304	struct DSMemory* memory = &ds->memory;
305	uint32_t value;
306	int wait = 0;
307
308	int i;
309	int offset = 4;
310	int popcount = 0;
311	if (direction & LSM_D) {
312		offset = -4;
313		popcount = popcount32(mask);
314		address -= (popcount << 2) - 4;
315	}
316
317	if (direction & LSM_B) {
318		address += offset;
319	}
320
321	uint32_t addressMisalign = address & 0x3;
322	address &= 0xFFFFFFFC;
323
324	switch (address >> DS_BASE_OFFSET) {
325	default:
326		break;
327	}
328
329	if (cycleCounter) {
330		++wait;
331		*cycleCounter += wait;
332	}
333
334	if (direction & LSM_B) {
335		address -= offset;
336	}
337
338	if (direction & LSM_D) {
339		address -= (popcount << 2) + 4;
340	}
341
342	return address | addressMisalign;
343}
344
345
346uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
347	struct DS* ds = (struct DS*) cpu->master;
348	struct DSMemory* memory = &ds->memory;
349	uint32_t value;
350	int wait = 0;
351
352	int i;
353	int offset = 4;
354	int popcount = 0;
355	if (direction & LSM_D) {
356		offset = -4;
357		popcount = popcount32(mask);
358		address -= (popcount << 2) - 4;
359	}
360
361	if (direction & LSM_B) {
362		address += offset;
363	}
364
365	uint32_t addressMisalign = address & 0x3;
366	address &= 0xFFFFFFFC;
367
368	switch (address >> DS_BASE_OFFSET) {
369	default:
370		break;
371	}
372
373	if (cycleCounter) {
374		*cycleCounter += wait;
375	}
376
377	if (direction & LSM_B) {
378		address -= offset;
379	}
380
381	if (direction & LSM_D) {
382		address -= (popcount << 2) + 4;
383	}
384
385	return address | addressMisalign;
386}
387
388static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
389	struct DS* ds = (struct DS*) cpu->master;
390	struct DSMemory* memory = &ds->memory;
391
392	int newRegion = address >> DS_BASE_OFFSET;
393
394	memory->activeRegion9 = newRegion;
395	switch (newRegion) {
396	case DS_REGION_RAM:
397		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
398			cpu->memory.activeRegion = memory->ram;
399			cpu->memory.activeMask = DS_SIZE_RAM - 1;
400			return;
401		}
402		break;
403	case DS9_REGION_BIOS:
404		// TODO: Mask properly
405		if (memory->bios9) {
406			cpu->memory.activeRegion = memory->bios9;
407			cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
408		} else {
409			cpu->memory.activeRegion = _deadbeef;
410			cpu->memory.activeMask = 0;
411		}
412		return;
413	default:
414		break;
415	}
416	cpu->memory.activeRegion = _deadbeef;
417	cpu->memory.activeMask = 0;
418	mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
419	return;
420}
421
422uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
423	struct DS* ds = (struct DS*) cpu->master;
424	struct DSMemory* memory = &ds->memory;
425	uint32_t value = 0;
426	int wait = 0;
427
428	switch (address >> DS_BASE_OFFSET) {
429	case DS_REGION_RAM:
430		if ((address & (DS_SIZE_RAM - 1)) < DS_SIZE_RAM) {
431			LOAD_32(value, address & (DS_SIZE_RAM - 1), memory->ram);
432		}
433		break;
434	default:
435		break;
436	}
437
438	if (cycleCounter) {
439		wait += 2;
440		*cycleCounter += wait;
441	}
442	// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
443	int rotate = (address & 3) << 3;
444	return ROR(value, rotate);
445}
446
447uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
448	struct DS* ds = (struct DS*) cpu->master;
449	struct DSMemory* memory = &ds->memory;
450	uint32_t value = 0;
451	int wait = 0;
452
453	switch (address >> DS_BASE_OFFSET) {
454	default:
455		break;
456	}
457
458	if (cycleCounter) {
459		wait += 2;
460		*cycleCounter += wait;
461	}
462	// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
463	int rotate = (address & 1) << 3;
464	return ROR(value, rotate);
465}
466
467uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
468	struct DS* ds = (struct DS*) cpu->master;
469	struct DSMemory* memory = &ds->memory;
470	uint32_t value = 0;
471	int wait = 0;
472
473	switch (address >> DS_BASE_OFFSET) {
474	default:
475		break;
476	}
477
478	if (cycleCounter) {
479		wait += 2;
480		*cycleCounter += wait;
481	}
482	return value;
483}
484
485void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
486	struct DS* ds = (struct DS*) cpu->master;
487	struct DSMemory* memory = &ds->memory;
488	int wait = 0;
489
490	switch (address >> DS_BASE_OFFSET) {
491		break;
492	}
493
494	if (cycleCounter) {
495		++wait;
496		*cycleCounter += wait;
497	}
498}
499
500void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
501	struct DS* ds = (struct DS*) cpu->master;
502	struct DSMemory* memory = &ds->memory;
503	int wait = 0;
504
505	switch (address >> DS_BASE_OFFSET) {
506	default:
507		break;
508	}
509
510	if (cycleCounter) {
511		++wait;
512		*cycleCounter += wait;
513	}
514}
515
516void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
517	struct DS* ds = (struct DS*) cpu->master;
518	struct DSMemory* memory = &ds->memory;
519	int wait = 0;
520
521	switch (address >> DS_BASE_OFFSET) {
522	default:
523		break;
524	}
525
526	if (cycleCounter) {
527		++wait;
528		*cycleCounter += wait;
529	}
530}
531
532uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
533	struct DS* ds = (struct DS*) cpu->master;
534	struct DSMemory* memory = &ds->memory;
535	uint32_t value;
536	int wait = 0;
537
538	int i;
539	int offset = 4;
540	int popcount = 0;
541	if (direction & LSM_D) {
542		offset = -4;
543		popcount = popcount32(mask);
544		address -= (popcount << 2) - 4;
545	}
546
547	if (direction & LSM_B) {
548		address += offset;
549	}
550
551	uint32_t addressMisalign = address & 0x3;
552	address &= 0xFFFFFFFC;
553
554	switch (address >> DS_BASE_OFFSET) {
555	default:
556		break;
557	}
558
559	if (cycleCounter) {
560		++wait;
561		*cycleCounter += wait;
562	}
563
564	if (direction & LSM_B) {
565		address -= offset;
566	}
567
568	if (direction & LSM_D) {
569		address -= (popcount << 2) + 4;
570	}
571
572	return address | addressMisalign;
573}
574
575
576uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
577	struct DS* ds = (struct DS*) cpu->master;
578	struct DSMemory* memory = &ds->memory;
579	uint32_t value;
580	int wait = 0;
581
582	int i;
583	int offset = 4;
584	int popcount = 0;
585	if (direction & LSM_D) {
586		offset = -4;
587		popcount = popcount32(mask);
588		address -= (popcount << 2) - 4;
589	}
590
591	if (direction & LSM_B) {
592		address += offset;
593	}
594
595	uint32_t addressMisalign = address & 0x3;
596	address &= 0xFFFFFFFC;
597
598	switch (address >> DS_BASE_OFFSET) {
599	default:
600		break;
601	}
602
603	if (cycleCounter) {
604		*cycleCounter += wait;
605	}
606
607	if (direction & LSM_B) {
608		address -= offset;
609	}
610
611	if (direction & LSM_D) {
612		address -= (popcount << 2) + 4;
613	}
614
615	return address | addressMisalign;
616}
617
618int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
619	return wait;
620}
621