mirror of https://github.com/mgba-emu/mgba.git
DS: A little more skeleton
This commit is contained in:
parent
290d5b77dd
commit
3cf9446ba1
|
@ -842,6 +842,7 @@ if(NOT QUIET)
|
|||
message(STATUS "Platforms:")
|
||||
message(STATUS " Game Boy Advance: ${M_CORE_GBA}")
|
||||
message(STATUS " Game Boy: ${M_CORE_GB}")
|
||||
message(STATUS " DS: ${M_CORE_DS}")
|
||||
message(STATUS "Features:")
|
||||
message(STATUS " Debuggers: ${USE_DEBUGGERS}")
|
||||
message(STATUS " CLI debugger: ${USE_EDITLINE}")
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "bios.h"
|
||||
|
||||
mLOG_DEFINE_CATEGORY(DS_BIOS, "DS BIOS");
|
||||
|
||||
const uint32_t DS7_BIOS_CHECKSUM = 0x1280F0D5;
|
||||
const uint32_t DS9_BIOS_CHECKSUM = 0x2AB23573;
|
|
@ -0,0 +1,24 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef DS_BIOS_H
|
||||
#define DS_BIOS_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "core/log.h"
|
||||
|
||||
mLOG_DECLARE_CATEGORY(DS_BIOS);
|
||||
|
||||
struct ARMCore;
|
||||
void DS7Swi16(struct ARMCore* cpu, int immediate);
|
||||
void DS7Swi32(struct ARMCore* cpu, int immediate);
|
||||
void DS9Swi16(struct ARMCore* cpu, int immediate);
|
||||
void DS9Swi32(struct ARMCore* cpu, int immediate);
|
||||
|
||||
extern const uint32_t DS7_BIOS_CHECKSUM;
|
||||
extern const uint32_t DS9_BIOS_CHECKSUM;
|
||||
|
||||
#endif
|
|
@ -91,6 +91,14 @@ static void _DSCoreSetSync(struct mCore* core, struct mCoreSync* sync) {
|
|||
}
|
||||
|
||||
static void _DSCoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
|
||||
struct DS* ds = core->board;
|
||||
struct VFile* bios = NULL;
|
||||
if (core->opts.useBios && core->opts.bios) {
|
||||
bios = VFileOpen(core->opts.bios, O_RDONLY);
|
||||
}
|
||||
if (bios) {
|
||||
DSLoadBIOS(ds, bios);
|
||||
}
|
||||
}
|
||||
|
||||
static void _DSCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
|
||||
|
@ -124,7 +132,8 @@ static bool _DSCoreLoadROM(struct mCore* core, struct VFile* vf) {
|
|||
}
|
||||
|
||||
static bool _DSCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
|
||||
return false;
|
||||
UNUSED(type);
|
||||
return DSLoadBIOS(core->board, vf);
|
||||
}
|
||||
|
||||
static bool _DSCoreLoadSave(struct mCore* core, struct VFile* vf) {
|
||||
|
|
38
src/ds/ds.c
38
src/ds/ds.c
|
@ -8,11 +8,11 @@
|
|||
#include "arm/decoder.h"
|
||||
#include "arm/debugger/debugger.h"
|
||||
#include "arm/isa-inlines.h"
|
||||
#include "ds/bios.h"
|
||||
|
||||
#include "util/crc32.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/math.h"
|
||||
#include "util/patch.h"
|
||||
#include "util/vfs.h"
|
||||
|
||||
mLOG_DEFINE_CATEGORY(DS, "DS");
|
||||
|
@ -67,8 +67,11 @@ static void DSInit(void* cpu, struct mCPUComponent* component) {
|
|||
}
|
||||
ds->arm9 = cpu;
|
||||
|
||||
ds->arm9->cp15.r1.c0 = ARMControlRegFillVE(0);
|
||||
|
||||
DS7InterruptHandlerInit(&ds->arm7->irqh);
|
||||
DS9InterruptHandlerInit(&ds->arm9->irqh);
|
||||
DSMemoryInit(ds);
|
||||
|
||||
ds->video.p = ds;
|
||||
|
||||
|
@ -92,6 +95,7 @@ void DSUnloadROM(struct DS* ds) {
|
|||
|
||||
void DSDestroy(struct DS* ds) {
|
||||
DSUnloadROM(ds);
|
||||
DSMemoryDeinit(ds);
|
||||
}
|
||||
|
||||
void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh) {
|
||||
|
@ -134,6 +138,9 @@ void DS9Reset(struct ARMCore* cpu) {
|
|||
cpu->gprs[ARM_SP] = DS9_SP_BASE_SVC;
|
||||
ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
|
||||
cpu->gprs[ARM_SP] = DS9_SP_BASE;
|
||||
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
DSMemoryReset(ds);
|
||||
}
|
||||
|
||||
static void DSProcessEvents(struct ARMCore* cpu) {
|
||||
|
@ -198,6 +205,35 @@ bool DSIsROM(struct VFile* vf) {
|
|||
return memcmp(signature, DS_ROM_MAGIC, sizeof(signature)) == 0;
|
||||
}
|
||||
|
||||
bool DSLoadBIOS(struct DS* ds, struct VFile* vf) {
|
||||
size_t size = vf->size(vf);
|
||||
void* data = NULL;
|
||||
uint32_t crc;
|
||||
if (size == DS7_SIZE_BIOS) {
|
||||
data = vf->map(vf, size, MAP_READ);
|
||||
} else if (size == 0x1000) {
|
||||
data = vf->map(vf, size, MAP_READ);
|
||||
}
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
crc = doCrc32(data, size);
|
||||
if (crc == DS7_BIOS_CHECKSUM) {
|
||||
ds->bios7Vf = vf;
|
||||
ds->memory.bios7 = data;
|
||||
mLOG(DS, INFO, "Official DS ARM7 BIOS detected");
|
||||
} else if (crc == DS9_BIOS_CHECKSUM) {
|
||||
ds->bios9Vf = vf;
|
||||
ds->memory.bios9 = data;
|
||||
mLOG(DS, INFO, "Official DS ARM9 BIOS detected");
|
||||
} else {
|
||||
mLOG(DS, WARN, "BIOS checksum incorrect");
|
||||
vf->unmap(vf, data, size);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSGetGameCode(struct DS* ds, char* out) {
|
||||
memset(out, 0, 8);
|
||||
if (!ds->romVf) {
|
||||
|
|
10
src/ds/ds.h
10
src/ds/ds.h
|
@ -11,6 +11,7 @@
|
|||
#include "arm/arm.h"
|
||||
#include "core/log.h"
|
||||
|
||||
#include "ds/memory.h"
|
||||
#include "ds/video.h"
|
||||
|
||||
extern const uint32_t DS_ARM946ES_FREQUENCY;
|
||||
|
@ -54,6 +55,7 @@ struct DS {
|
|||
|
||||
struct ARMCore* arm7;
|
||||
struct ARMCore* arm9;
|
||||
struct DSMemory memory;
|
||||
struct DSVideo video;
|
||||
|
||||
struct mCoreSync* sync;
|
||||
|
@ -63,13 +65,15 @@ struct DS {
|
|||
int springIRQ7;
|
||||
int springIRQ9;
|
||||
|
||||
uint32_t biosChecksum;
|
||||
uint32_t bios7Checksum;
|
||||
uint32_t bios9Checksum;
|
||||
int* keySource;
|
||||
struct mRTCSource* rtcSource;
|
||||
struct mRumble* rumble;
|
||||
|
||||
uint32_t romCrc32;
|
||||
struct VFile* romVf;
|
||||
struct VFile* bios7Vf;
|
||||
struct VFile* bios9Vf;
|
||||
|
||||
struct mKeyCallback* keyCallback;
|
||||
};
|
||||
|
@ -121,6 +125,8 @@ bool DSLoadROM(struct DS* ds, struct VFile* vf);
|
|||
void DSUnloadROM(struct DS* ds);
|
||||
void DSApplyPatch(struct DS* ds, struct Patch* patch);
|
||||
|
||||
bool DSLoadBIOS(struct DS* ds, struct VFile* vf);
|
||||
|
||||
bool DSIsROM(struct VFile* vf);
|
||||
void DSGetGameCode(struct DS* ds, char* out);
|
||||
void DSGetGameTitle(struct DS* ds, char* out);
|
||||
|
|
|
@ -0,0 +1,583 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "memory.h"
|
||||
|
||||
#include "ds/ds.h"
|
||||
#include "util/math.h"
|
||||
|
||||
mLOG_DEFINE_CATEGORY(DS_MEM, "DS Memory");
|
||||
|
||||
#define LDM_LOOP(LDM) \
|
||||
for (i = 0; i < 16; i += 4) { \
|
||||
if (UNLIKELY(mask & (1 << i))) { \
|
||||
LDM; \
|
||||
cpu->gprs[i] = value; \
|
||||
++wait; \
|
||||
address += 4; \
|
||||
} \
|
||||
if (UNLIKELY(mask & (2 << i))) { \
|
||||
LDM; \
|
||||
cpu->gprs[i + 1] = value; \
|
||||
++wait; \
|
||||
address += 4; \
|
||||
} \
|
||||
if (UNLIKELY(mask & (4 << i))) { \
|
||||
LDM; \
|
||||
cpu->gprs[i + 2] = value; \
|
||||
++wait; \
|
||||
address += 4; \
|
||||
} \
|
||||
if (UNLIKELY(mask & (8 << i))) { \
|
||||
LDM; \
|
||||
cpu->gprs[i + 3] = value; \
|
||||
++wait; \
|
||||
address += 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define STM_LOOP(STM) \
|
||||
for (i = 0; i < 16; i += 4) { \
|
||||
if (UNLIKELY(mask & (1 << i))) { \
|
||||
value = cpu->gprs[i]; \
|
||||
STM; \
|
||||
++wait; \
|
||||
address += 4; \
|
||||
} \
|
||||
if (UNLIKELY(mask & (2 << i))) { \
|
||||
value = cpu->gprs[i + 1]; \
|
||||
STM; \
|
||||
++wait; \
|
||||
address += 4; \
|
||||
} \
|
||||
if (UNLIKELY(mask & (4 << i))) { \
|
||||
value = cpu->gprs[i + 2]; \
|
||||
STM; \
|
||||
++wait; \
|
||||
address += 4; \
|
||||
} \
|
||||
if (UNLIKELY(mask & (8 << i))) { \
|
||||
value = cpu->gprs[i + 3]; \
|
||||
STM; \
|
||||
++wait; \
|
||||
address += 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
|
||||
|
||||
static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
|
||||
static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
|
||||
static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
|
||||
|
||||
static const int DMA_OFFSET[] = { 1, -1, 0, 1 };
|
||||
|
||||
void DSMemoryInit(struct DS* ds) {
|
||||
struct ARMCore* arm7 = ds->arm7;
|
||||
arm7->memory.load32 = DS7Load32;
|
||||
arm7->memory.load16 = DS7Load16;
|
||||
arm7->memory.load8 = DS7Load8;
|
||||
arm7->memory.loadMultiple = DS7LoadMultiple;
|
||||
arm7->memory.store32 = DS7Store32;
|
||||
arm7->memory.store16 = DS7Store16;
|
||||
arm7->memory.store8 = DS7Store8;
|
||||
arm7->memory.storeMultiple = DS7StoreMultiple;
|
||||
arm7->memory.stall = DSMemoryStall;
|
||||
|
||||
struct ARMCore* arm9 = ds->arm9;
|
||||
arm9->memory.load32 = DS9Load32;
|
||||
arm9->memory.load16 = DS9Load16;
|
||||
arm9->memory.load8 = DS9Load8;
|
||||
arm9->memory.loadMultiple = DS9LoadMultiple;
|
||||
arm9->memory.store32 = DS9Store32;
|
||||
arm9->memory.store16 = DS9Store16;
|
||||
arm9->memory.store8 = DS9Store8;
|
||||
arm9->memory.storeMultiple = DS9StoreMultiple;
|
||||
arm9->memory.stall = DSMemoryStall;
|
||||
|
||||
ds->memory.bios7 = NULL;
|
||||
ds->memory.bios9 = NULL;
|
||||
ds->memory.wram = NULL;
|
||||
ds->memory.ram = NULL;
|
||||
ds->memory.rom = NULL;
|
||||
|
||||
ds->memory.activeRegion7 = -1;
|
||||
ds->memory.activeRegion9 = -1;
|
||||
|
||||
arm7->memory.activeRegion = 0;
|
||||
arm7->memory.activeMask = 0;
|
||||
arm7->memory.setActiveRegion = DS7SetActiveRegion;
|
||||
arm7->memory.activeSeqCycles32 = 0;
|
||||
arm7->memory.activeSeqCycles16 = 0;
|
||||
arm7->memory.activeNonseqCycles32 = 0;
|
||||
arm7->memory.activeNonseqCycles16 = 0;
|
||||
|
||||
arm9->memory.activeRegion = 0;
|
||||
arm9->memory.activeMask = 0;
|
||||
arm9->memory.setActiveRegion = DS9SetActiveRegion;
|
||||
arm9->memory.activeSeqCycles32 = 0;
|
||||
arm9->memory.activeSeqCycles16 = 0;
|
||||
arm9->memory.activeNonseqCycles32 = 0;
|
||||
arm9->memory.activeNonseqCycles16 = 0;
|
||||
}
|
||||
|
||||
void DSMemoryDeinit(struct DS* ds) {
|
||||
mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
|
||||
mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
|
||||
}
|
||||
|
||||
void DSMemoryReset(struct DS* ds) {
|
||||
if (ds->memory.wram) {
|
||||
mappedMemoryFree(ds->memory.wram, DS_SIZE_WORKING_RAM);
|
||||
}
|
||||
ds->memory.wram = anonymousMemoryMap(DS_SIZE_WORKING_RAM);
|
||||
|
||||
if (ds->memory.ram) {
|
||||
mappedMemoryFree(ds->memory.ram, DS_SIZE_RAM);
|
||||
}
|
||||
ds->memory.ram = anonymousMemoryMap(DS_SIZE_RAM);
|
||||
|
||||
memset(ds->memory.dma7, 0, sizeof(ds->memory.dma7));
|
||||
memset(ds->memory.dma9, 0, sizeof(ds->memory.dma9));
|
||||
ds->memory.activeDMA7 = -1;
|
||||
ds->memory.activeDMA9 = -1;
|
||||
ds->memory.nextDMA = INT_MAX;
|
||||
ds->memory.eventDiff = 0;
|
||||
|
||||
if (!ds->memory.wram || !ds->memory.ram) {
|
||||
DSMemoryDeinit(ds);
|
||||
mLOG(DS_MEM, FATAL, "Could not map memory");
|
||||
}
|
||||
}
|
||||
|
||||
static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
|
||||
int newRegion = address >> DS_BASE_OFFSET;
|
||||
|
||||
memory->activeRegion7 = newRegion;
|
||||
switch (newRegion) {
|
||||
case DS7_REGION_BIOS:
|
||||
cpu->memory.activeRegion = memory->bios7;
|
||||
cpu->memory.activeMask = DS7_SIZE_BIOS - 1;
|
||||
break;
|
||||
default:
|
||||
mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value = 0;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
wait += 2;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
|
||||
int rotate = (address & 3) << 3;
|
||||
return ROR(value, rotate);
|
||||
}
|
||||
|
||||
uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value = 0;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
wait += 2;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
|
||||
int rotate = (address & 1) << 3;
|
||||
return ROR(value, rotate);
|
||||
}
|
||||
|
||||
uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value = 0;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
wait += 2;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
++wait;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
}
|
||||
|
||||
void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
++wait;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
}
|
||||
|
||||
void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
++wait;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value;
|
||||
int wait = 0;
|
||||
|
||||
int i;
|
||||
int offset = 4;
|
||||
int popcount = 0;
|
||||
if (direction & LSM_D) {
|
||||
offset = -4;
|
||||
popcount = popcount32(mask);
|
||||
address -= (popcount << 2) - 4;
|
||||
}
|
||||
|
||||
if (direction & LSM_B) {
|
||||
address += offset;
|
||||
}
|
||||
|
||||
uint32_t addressMisalign = address & 0x3;
|
||||
address &= 0xFFFFFFFC;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
++wait;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
|
||||
if (direction & LSM_B) {
|
||||
address -= offset;
|
||||
}
|
||||
|
||||
if (direction & LSM_D) {
|
||||
address -= (popcount << 2) + 4;
|
||||
}
|
||||
|
||||
return address | addressMisalign;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
|
||||
struct DS* ds = (struct ds*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value;
|
||||
int wait = 0;
|
||||
|
||||
int i;
|
||||
int offset = 4;
|
||||
int popcount = 0;
|
||||
if (direction & LSM_D) {
|
||||
offset = -4;
|
||||
popcount = popcount32(mask);
|
||||
address -= (popcount << 2) - 4;
|
||||
}
|
||||
|
||||
if (direction & LSM_B) {
|
||||
address += offset;
|
||||
}
|
||||
|
||||
uint32_t addressMisalign = address & 0x3;
|
||||
address &= 0xFFFFFFFC;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
|
||||
if (direction & LSM_B) {
|
||||
address -= offset;
|
||||
}
|
||||
|
||||
if (direction & LSM_D) {
|
||||
address -= (popcount << 2) + 4;
|
||||
}
|
||||
|
||||
return address | addressMisalign;
|
||||
}
|
||||
|
||||
static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
|
||||
int newRegion = address >> DS_BASE_OFFSET;
|
||||
|
||||
memory->activeRegion7 = newRegion;
|
||||
switch (newRegion) {
|
||||
case DS9_REGION_BIOS:
|
||||
// TODO: Mask properly
|
||||
if (memory->bios9) {
|
||||
cpu->memory.activeRegion = memory->bios9;
|
||||
cpu->memory.activeMask = DS9_SIZE_BIOS - 1;
|
||||
} else {
|
||||
cpu->memory.activeRegion = _deadbeef;
|
||||
cpu->memory.activeMask = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mLOG(DS_MEM, FATAL, "Jumped to invalid address: %08X", address);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value = 0;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
wait += 2;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
// Unaligned 32-bit loads are "rotated" so they make some semblance of sense
|
||||
int rotate = (address & 3) << 3;
|
||||
return ROR(value, rotate);
|
||||
}
|
||||
|
||||
uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value = 0;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
wait += 2;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
// Unaligned 16-bit loads are "unpredictable", TODO: See what DS does
|
||||
int rotate = (address & 1) << 3;
|
||||
return ROR(value, rotate);
|
||||
}
|
||||
|
||||
uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value = 0;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
wait += 2;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
++wait;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
}
|
||||
|
||||
void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
++wait;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
}
|
||||
|
||||
void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
int wait = 0;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
++wait;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value;
|
||||
int wait = 0;
|
||||
|
||||
int i;
|
||||
int offset = 4;
|
||||
int popcount = 0;
|
||||
if (direction & LSM_D) {
|
||||
offset = -4;
|
||||
popcount = popcount32(mask);
|
||||
address -= (popcount << 2) - 4;
|
||||
}
|
||||
|
||||
if (direction & LSM_B) {
|
||||
address += offset;
|
||||
}
|
||||
|
||||
uint32_t addressMisalign = address & 0x3;
|
||||
address &= 0xFFFFFFFC;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
++wait;
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
|
||||
if (direction & LSM_B) {
|
||||
address -= offset;
|
||||
}
|
||||
|
||||
if (direction & LSM_D) {
|
||||
address -= (popcount << 2) + 4;
|
||||
}
|
||||
|
||||
return address | addressMisalign;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
|
||||
struct DS* ds = (struct ds*) cpu->master;
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
uint32_t value;
|
||||
int wait = 0;
|
||||
|
||||
int i;
|
||||
int offset = 4;
|
||||
int popcount = 0;
|
||||
if (direction & LSM_D) {
|
||||
offset = -4;
|
||||
popcount = popcount32(mask);
|
||||
address -= (popcount << 2) - 4;
|
||||
}
|
||||
|
||||
if (direction & LSM_B) {
|
||||
address += offset;
|
||||
}
|
||||
|
||||
uint32_t addressMisalign = address & 0x3;
|
||||
address &= 0xFFFFFFFC;
|
||||
|
||||
switch (address >> DS_BASE_OFFSET) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter) {
|
||||
*cycleCounter += wait;
|
||||
}
|
||||
|
||||
if (direction & LSM_B) {
|
||||
address -= offset;
|
||||
}
|
||||
|
||||
if (direction & LSM_D) {
|
||||
address -= (popcount << 2) + 4;
|
||||
}
|
||||
|
||||
return address | addressMisalign;
|
||||
}
|
||||
|
||||
int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
|
||||
return wait;
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef DS_MEMORY_H
|
||||
#define DS_MEMORY_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "arm/arm.h"
|
||||
#include "core/log.h"
|
||||
|
||||
enum DSMemoryRegion {
|
||||
DS7_REGION_BIOS = 0x0,
|
||||
DS9_REGION_ITCM = 0x0,
|
||||
DS_REGION_RAM = 0x2,
|
||||
DS_REGION_WORKING_RAM = 0x3,
|
||||
DS_REGION_IO = 0x4,
|
||||
DS9_REGION_PALETTE_RAM = 0x5,
|
||||
DS_REGION_VRAM = 0x6,
|
||||
DS9_REGION_OAM = 0x7,
|
||||
DS_REGION_SLOT2 = 0x8,
|
||||
DS_REGION_SLOT2_EX = 0x9,
|
||||
DS_REGION_SLOT2_SRAM = 0xA,
|
||||
DS9_REGION_BIOS = 0xFF,
|
||||
};
|
||||
|
||||
enum DSMemoryBase {
|
||||
DS7_BASE_BIOS = 0x00000000,
|
||||
DS9_BASE_ITCM = 0x00000000,
|
||||
DS_BASE_RAM = 0x02000000,
|
||||
DS_BASE_WORKING_RAM = 0x03000000,
|
||||
DS_BASE_IO = 0x04000000,
|
||||
DS9_BASE_PALETTE_RAM = 0x05000000,
|
||||
DS_BASE_VRAM = 0x06000000,
|
||||
DS9_BASE_OAM = 0x07000000,
|
||||
DS_BASE_SLOT2 = 0x08000000,
|
||||
DS_BASE_SLOT2_EX = 0x09000000,
|
||||
DS9_BASE_BIOS = 0xFFFF0000,
|
||||
};
|
||||
|
||||
enum {
|
||||
DS7_SIZE_BIOS = 0x00004000,
|
||||
DS9_SIZE_BIOS = 0x00008000,
|
||||
DS_SIZE_RAM = 0x00400000,
|
||||
DS_SIZE_WORKING_RAM = 0x00008000,
|
||||
DS9_SIZE_PALETTE_RAM = 0x00000800,
|
||||
DS9_SIZE_OAM = 0x00000800,
|
||||
DS_SIZE_SLOT2 = 0x02000000,
|
||||
DS_SIZE_SLOT2_SRAM = 0x00010000,
|
||||
};
|
||||
|
||||
enum {
|
||||
DS_OFFSET_MASK = 0x00FFFFFF,
|
||||
DS_BASE_OFFSET = 24
|
||||
};
|
||||
|
||||
enum DSDMAControl {
|
||||
DS_DMA_INCREMENT = 0,
|
||||
DS_DMA_DECREMENT = 1,
|
||||
DS_DMA_FIXED = 2,
|
||||
DS_DMA_INCREMENT_RELOAD = 3
|
||||
};
|
||||
|
||||
enum DSDMATiming {
|
||||
DS_DMA_TIMING_NOW = 0,
|
||||
DS_DMA_TIMING_VBLANK = 1,
|
||||
DS_DMA_TIMING_HBLANK = 2,
|
||||
DS7_DMA_TIMING_SLOT1 = 2,
|
||||
DS_DMA_TIMING_DISPLAY_START = 3,
|
||||
DS7_DMA_TIMING_CUSTOM = 3,
|
||||
DS_DMA_TIMING_MEMORY_DISPLAY = 4,
|
||||
DS9_DMA_TIMING_SLOT1 = 5,
|
||||
DS_DMA_TIMING_SLOT2 = 6,
|
||||
DS_DMA_TIMING_GEOM_FIFO = 7,
|
||||
};
|
||||
|
||||
mLOG_DECLARE_CATEGORY(DS_MEM);
|
||||
|
||||
DECL_BITFIELD(DSDMARegister, uint16_t);
|
||||
DECL_BITS(DSDMARegister, DestControl, 5, 2);
|
||||
DECL_BITS(DSDMARegister, SrcControl, 7, 2);
|
||||
DECL_BIT(DSDMARegister, Repeat, 9);
|
||||
DECL_BIT(DSDMARegister, Width, 10);
|
||||
DECL_BITS(DSDMARegister, Timing7, 12, 2);
|
||||
DECL_BITS(DSDMARegister, Timing9, 11, 3);
|
||||
DECL_BIT(DSDMARegister, DoIRQ, 14);
|
||||
DECL_BIT(DSDMARegister, Enable, 15);
|
||||
|
||||
struct DSDMA {
|
||||
DSDMARegister reg;
|
||||
|
||||
uint32_t source;
|
||||
uint32_t dest;
|
||||
int32_t count;
|
||||
uint32_t nextSource;
|
||||
uint32_t nextDest;
|
||||
int32_t nextCount;
|
||||
int32_t nextEvent;
|
||||
};
|
||||
|
||||
struct DSMemory {
|
||||
uint32_t* bios7;
|
||||
uint32_t* bios9;
|
||||
uint32_t* ram;
|
||||
uint32_t* wram;
|
||||
uint32_t* rom;
|
||||
|
||||
size_t romSize;
|
||||
|
||||
char waitstatesSeq32[256];
|
||||
char waitstatesSeq16[256];
|
||||
char waitstatesNonseq32[256];
|
||||
char waitstatesNonseq16[256];
|
||||
char waitstatesPrefetchSeq32[16];
|
||||
char waitstatesPrefetchSeq16[16];
|
||||
char waitstatesPrefetchNonseq32[16];
|
||||
char waitstatesPrefetchNonseq16[16];
|
||||
int activeRegion7;
|
||||
int activeRegion9;
|
||||
|
||||
struct DSDMA dma7[4];
|
||||
struct DSDMA dma9[4];
|
||||
int activeDMA7;
|
||||
int activeDMA9;
|
||||
int32_t nextDMA;
|
||||
int32_t eventDiff;
|
||||
};
|
||||
|
||||
struct DS;
|
||||
void DSMemoryInit(struct DS* ds);
|
||||
void DSMemoryDeinit(struct DS* ds);
|
||||
|
||||
void DSMemoryReset(struct DS* ds);
|
||||
|
||||
uint32_t DS7Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter);
|
||||
uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter);
|
||||
uint32_t DS7Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter);
|
||||
|
||||
void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter);
|
||||
void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter);
|
||||
void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter);
|
||||
|
||||
uint32_t DS7LoadMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction,
|
||||
int* cycleCounter);
|
||||
uint32_t DS7StoreMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction,
|
||||
int* cycleCounter);
|
||||
|
||||
uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter);
|
||||
uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter);
|
||||
uint32_t DS9Load8(struct ARMCore* cpu, uint32_t address, int* cycleCounter);
|
||||
|
||||
void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter);
|
||||
void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter);
|
||||
void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter);
|
||||
|
||||
uint32_t DS9LoadMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction,
|
||||
int* cycleCounter);
|
||||
uint32_t DS9StoreMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction,
|
||||
int* cycleCounter);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue