all repos — mgba @ e93154fb417d77b4ffb4f275a0623e6bff3526b1

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