mirror of https://github.com/mgba-emu/mgba.git
DS: Share code between cores
This commit is contained in:
parent
2359a4e886
commit
c037dada3e
|
@ -54,21 +54,27 @@ struct mDebugger;
|
|||
|
||||
mLOG_DECLARE_CATEGORY(DS);
|
||||
|
||||
struct DSCommon {
|
||||
struct DS* p;
|
||||
|
||||
struct ARMCore* cpu;
|
||||
struct GBATimer timers[4];
|
||||
struct mTiming timing;
|
||||
int springIRQ;
|
||||
|
||||
struct DSCoreMemory memory;
|
||||
struct DSCommon* ipc;
|
||||
};
|
||||
|
||||
struct DS {
|
||||
struct mCPUComponent d;
|
||||
|
||||
struct ARMCore* arm7;
|
||||
struct ARMCore* arm9;
|
||||
struct DSCommon ds7;
|
||||
struct DSCommon ds9;
|
||||
struct DSMemory memory;
|
||||
struct DSVideo video;
|
||||
int timersEnabled7;
|
||||
int timersEnabled9;
|
||||
struct GBATimer timers7[4];
|
||||
struct GBATimer timers9[4];
|
||||
|
||||
struct mCoreSync* sync;
|
||||
struct mTiming timing7;
|
||||
struct mTiming timing9;
|
||||
struct mTimingEvent slice;
|
||||
struct ARMCore* activeCpu;
|
||||
uint32_t sliceStart;
|
||||
|
@ -76,8 +82,6 @@ struct DS {
|
|||
|
||||
struct ARMDebugger* debugger;
|
||||
|
||||
int springIRQ7;
|
||||
int springIRQ9;
|
||||
bool cpuBlocked;
|
||||
bool earlyExit;
|
||||
|
||||
|
|
|
@ -12,61 +12,70 @@ CXX_GUARD_START
|
|||
|
||||
#include <mgba/core/log.h>
|
||||
|
||||
enum DSIORegisters {
|
||||
// DMA
|
||||
DS_REG_DMA0SAD_LO = 0x0B0,
|
||||
DS_REG_DMA0SAD_HI = 0x0B2,
|
||||
DS_REG_DMA0DAD_LO = 0x0B4,
|
||||
DS_REG_DMA0DAD_HI = 0x0B6,
|
||||
DS_REG_DMA0CNT_LO = 0x0B8,
|
||||
DS_REG_DMA0CNT_HI = 0x0BA,
|
||||
DS_REG_DMA1SAD_LO = 0x0BC,
|
||||
DS_REG_DMA1SAD_HI = 0x0BE,
|
||||
DS_REG_DMA1DAD_LO = 0x0C0,
|
||||
DS_REG_DMA1DAD_HI = 0x0C2,
|
||||
DS_REG_DMA1CNT_LO = 0x0C4,
|
||||
DS_REG_DMA1CNT_HI = 0x0C6,
|
||||
DS_REG_DMA2SAD_LO = 0x0C8,
|
||||
DS_REG_DMA2SAD_HI = 0x0CA,
|
||||
DS_REG_DMA2DAD_LO = 0x0CC,
|
||||
DS_REG_DMA2DAD_HI = 0x0CE,
|
||||
DS_REG_DMA2CNT_LO = 0x0D0,
|
||||
DS_REG_DMA2CNT_HI = 0x0D2,
|
||||
DS_REG_DMA3SAD_LO = 0x0D4,
|
||||
DS_REG_DMA3SAD_HI = 0x0D6,
|
||||
DS_REG_DMA3DAD_LO = 0x0D8,
|
||||
DS_REG_DMA3DAD_HI = 0x0DA,
|
||||
DS_REG_DMA3CNT_LO = 0x0DC,
|
||||
DS_REG_DMA3CNT_HI = 0x0DE,
|
||||
|
||||
// Timers
|
||||
DS_REG_TM0CNT_LO = 0x100,
|
||||
DS_REG_TM0CNT_HI = 0x102,
|
||||
DS_REG_TM1CNT_LO = 0x104,
|
||||
DS_REG_TM1CNT_HI = 0x106,
|
||||
DS_REG_TM2CNT_LO = 0x108,
|
||||
DS_REG_TM2CNT_HI = 0x10A,
|
||||
DS_REG_TM3CNT_LO = 0x10C,
|
||||
DS_REG_TM3CNT_HI = 0x10E,
|
||||
|
||||
// IPC
|
||||
DS_REG_IPCSYNC = 0x180,
|
||||
DS_REG_IPCFIFOCNT = 0x182,
|
||||
DS_REG_IPCFIFOSEND_LO = 0x184,
|
||||
DS_REG_IPCFIFOSEND_HI = 0x186,
|
||||
DS_REG_IPCFIFORECV_LO = 0x100000,
|
||||
DS_REG_IPCFIFORECV_HI = 0x100002,
|
||||
|
||||
// Interrupts
|
||||
DS_REG_IME = 0x208,
|
||||
DS_REG_IE_LO = 0x210,
|
||||
DS_REG_IE_HI = 0x212,
|
||||
DS_REG_IF_LO = 0x214,
|
||||
DS_REG_IF_HI = 0x216,
|
||||
};
|
||||
|
||||
enum DS7IORegisters {
|
||||
// Video
|
||||
DS7_REG_DISPSTAT = 0x004,
|
||||
DS7_REG_VCOUNT = 0x006,
|
||||
|
||||
// DMA
|
||||
DS7_REG_DISPSTAT_REG_DMA0SAD_LO = 0x0B0,
|
||||
DS7_REG_DISPSTAT_REG_DMA0SAD_HI = 0x0B2,
|
||||
DS7_REG_DISPSTAT_REG_DMA0DAD_LO = 0x0B4,
|
||||
DS7_REG_DISPSTAT_REG_DMA0DAD_HI = 0x0B6,
|
||||
DS7_REG_DISPSTAT_REG_DMA0CNT_LO = 0x0B8,
|
||||
DS7_REG_DISPSTAT_REG_DMA0CNT_HI = 0x0BA,
|
||||
DS7_REG_DISPSTAT_REG_DMA1SAD_LO = 0x0BC,
|
||||
DS7_REG_DISPSTAT_REG_DMA1SAD_HI = 0x0BE,
|
||||
DS7_REG_DISPSTAT_REG_DMA1DAD_LO = 0x0C0,
|
||||
DS7_REG_DISPSTAT_REG_DMA1DAD_HI = 0x0C2,
|
||||
DS7_REG_DISPSTAT_REG_DMA1CNT_LO = 0x0C4,
|
||||
DS7_REG_DISPSTAT_REG_DMA1CNT_HI = 0x0C6,
|
||||
DS7_REG_DISPSTAT_REG_DMA2SAD_LO = 0x0C8,
|
||||
DS7_REG_DISPSTAT_REG_DMA2SAD_HI = 0x0CA,
|
||||
DS7_REG_DISPSTAT_REG_DMA2DAD_LO = 0x0CC,
|
||||
DS7_REG_DISPSTAT_REG_DMA2DAD_HI = 0x0CE,
|
||||
DS7_REG_DISPSTAT_REG_DMA2CNT_LO = 0x0D0,
|
||||
DS7_REG_DISPSTAT_REG_DMA2CNT_HI = 0x0D2,
|
||||
DS7_REG_DISPSTAT_REG_DMA3SAD_LO = 0x0D4,
|
||||
DS7_REG_DISPSTAT_REG_DMA3SAD_HI = 0x0D6,
|
||||
DS7_REG_DISPSTAT_REG_DMA3DAD_LO = 0x0D8,
|
||||
DS7_REG_DISPSTAT_REG_DMA3DAD_HI = 0x0DA,
|
||||
DS7_REG_DISPSTAT_REG_DMA3CNT_LO = 0x0DC,
|
||||
DS7_REG_DISPSTAT_REG_DMA3CNT_HI = 0x0DE,
|
||||
|
||||
// Timers
|
||||
DS7_REG_TM0CNT_LO = 0x100,
|
||||
DS7_REG_TM0CNT_HI = 0x102,
|
||||
DS7_REG_TM1CNT_LO = 0x104,
|
||||
DS7_REG_TM1CNT_HI = 0x106,
|
||||
DS7_REG_TM2CNT_LO = 0x108,
|
||||
DS7_REG_TM2CNT_HI = 0x10A,
|
||||
DS7_REG_TM3CNT_LO = 0x10C,
|
||||
DS7_REG_TM3CNT_HI = 0x10E,
|
||||
|
||||
// Keypad
|
||||
DS7_REG_KEYINPUT = 0x130,
|
||||
DS7_REG_KEYCNT = 0x132,
|
||||
DS7_REG_EXTKEYIN = 0x136,
|
||||
DS7_REG_RTC = 0x138,
|
||||
|
||||
// IPC
|
||||
DS7_REG_IPCSYNC = 0x180,
|
||||
DS7_REG_IPCFIFOCNT = 0x182,
|
||||
DS7_REG_IPCFIFOSEND_LO = 0x184,
|
||||
DS7_REG_IPCFIFOSEND_HI = 0x186,
|
||||
DS7_REG_IPCFIFORECV_LO = 0x100000,
|
||||
DS7_REG_IPCFIFORECV_HI = 0x100002,
|
||||
|
||||
// Game card
|
||||
DS7_REG_AUXSPICNT = 0x1A0,
|
||||
DS7_REG_AUXSPIDATA = 0x1A2,
|
||||
|
@ -85,13 +94,8 @@ enum DS7IORegisters {
|
|||
DS7_REG_SLOT1DATA_2 = 0x100012,
|
||||
DS7_REG_SLOT1DATA_3 = 0x100013,
|
||||
|
||||
// Interrupts, etc
|
||||
// Etc
|
||||
DS7_REG_EXMEMSTAT = 0x204,
|
||||
DS7_REG_IME = 0x208,
|
||||
DS7_REG_IE_LO = 0x210,
|
||||
DS7_REG_IE_HI = 0x212,
|
||||
DS7_REG_IF_LO = 0x214,
|
||||
DS7_REG_IF_HI = 0x216,
|
||||
|
||||
// Memory control
|
||||
DS7_REG_VRAMSTAT = 0x240,
|
||||
|
@ -198,62 +202,10 @@ enum DS9IORegisters {
|
|||
DS9_REG_B_BLDY = 0x1054,
|
||||
DS9_REG_B_MASTER_BRIGHT = 0x106C,
|
||||
|
||||
// DMA
|
||||
DS9_REG_DMA0SAD_LO = 0x0B0,
|
||||
DS9_REG_DMA0SAD_HI = 0x0B2,
|
||||
DS9_REG_DMA0DAD_LO = 0x0B4,
|
||||
DS9_REG_DMA0DAD_HI = 0x0B6,
|
||||
DS9_REG_DMA0CNT_LO = 0x0B8,
|
||||
DS9_REG_DMA0CNT_HI = 0x0BA,
|
||||
DS9_REG_DMA1SAD_LO = 0x0BC,
|
||||
DS9_REG_DMA1SAD_HI = 0x0BE,
|
||||
DS9_REG_DMA1DAD_LO = 0x0C0,
|
||||
DS9_REG_DMA1DAD_HI = 0x0C2,
|
||||
DS9_REG_DMA1CNT_LO = 0x0C4,
|
||||
DS9_REG_DMA1CNT_HI = 0x0C6,
|
||||
DS9_REG_DMA2SAD_LO = 0x0C8,
|
||||
DS9_REG_DMA2SAD_HI = 0x0CA,
|
||||
DS9_REG_DMA2DAD_LO = 0x0CC,
|
||||
DS9_REG_DMA2DAD_HI = 0x0CE,
|
||||
DS9_REG_DMA2CNT_LO = 0x0D0,
|
||||
DS9_REG_DMA2CNT_HI = 0x0D2,
|
||||
DS9_REG_DMA3SAD_LO = 0x0D4,
|
||||
DS9_REG_DMA3SAD_HI = 0x0D6,
|
||||
DS9_REG_DMA3DAD_LO = 0x0D8,
|
||||
DS9_REG_DMA3DAD_HI = 0x0DA,
|
||||
DS9_REG_DMA3CNT_LO = 0x0DC,
|
||||
DS9_REG_DMA3CNT_HI = 0x0DE,
|
||||
DS9_REG_DMA0FILL_LO = 0x0E0,
|
||||
DS9_REG_DMA0FILL_HI = 0x0E2,
|
||||
DS9_REG_DMA1FILL_LO = 0x0E4,
|
||||
DS9_REG_DMA1FILL_HI = 0x0E6,
|
||||
DS9_REG_DMA2FILL_LO = 0x0E8,
|
||||
DS9_REG_DMA2FILL_HI = 0x0EA,
|
||||
DS9_REG_DMA3FILL_LO = 0x0EC,
|
||||
DS9_REG_DMA3FILL_HI = 0x0EE,
|
||||
|
||||
// Timers
|
||||
DS9_REG_TM0CNT_LO = 0x100,
|
||||
DS9_REG_TM0CNT_HI = 0x102,
|
||||
DS9_REG_TM1CNT_LO = 0x104,
|
||||
DS9_REG_TM1CNT_HI = 0x106,
|
||||
DS9_REG_TM2CNT_LO = 0x108,
|
||||
DS9_REG_TM2CNT_HI = 0x10A,
|
||||
DS9_REG_TM3CNT_LO = 0x10C,
|
||||
DS9_REG_TM3CNT_HI = 0x10E,
|
||||
|
||||
// Keypad
|
||||
DS9_REG_KEYINPUT = 0x130,
|
||||
DS9_REG_KEYCNT = 0x132,
|
||||
|
||||
// IPC
|
||||
DS9_REG_IPCSYNC = 0x180,
|
||||
DS9_REG_IPCFIFOCNT = 0x182,
|
||||
DS9_REG_IPCFIFOSEND_LO = 0x184,
|
||||
DS9_REG_IPCFIFOSEND_HI = 0x186,
|
||||
DS9_REG_IPCFIFORECV_LO = 0x100000,
|
||||
DS9_REG_IPCFIFORECV_HI = 0x100002,
|
||||
|
||||
// Game card
|
||||
DS9_REG_AUXSPICNT = 0x1A0,
|
||||
DS9_REG_AUXSPIDATA = 0x1A2,
|
||||
|
@ -272,13 +224,8 @@ enum DS9IORegisters {
|
|||
DS9_REG_SLOT1DATA_2 = 0x100012,
|
||||
DS9_REG_SLOT1DATA_3 = 0x100013,
|
||||
|
||||
// Interrupts, etc
|
||||
// Etc
|
||||
DS9_REG_EXMEMCNT = 0x204,
|
||||
DS9_REG_IME = 0x208,
|
||||
DS9_REG_IE_LO = 0x210,
|
||||
DS9_REG_IE_HI = 0x212,
|
||||
DS9_REG_IF_LO = 0x214,
|
||||
DS9_REG_IF_HI = 0x216,
|
||||
|
||||
// Memory control
|
||||
DS9_REG_VRAMCNT_A = 0x240,
|
||||
|
|
|
@ -133,15 +133,14 @@ struct DSMemory {
|
|||
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 DSCoreMemory {
|
||||
uint16_t* io;
|
||||
int activeRegion;
|
||||
|
||||
struct DSDMA dma[4];
|
||||
int activeDMA;
|
||||
};
|
||||
|
||||
struct DS;
|
||||
|
|
|
@ -159,8 +159,8 @@ static void _DSCoreUnloadROM(struct mCore* core) {
|
|||
static void _DSCoreReset(struct mCore* core) {
|
||||
struct DSCore* dscore = (struct DSCore*) core;
|
||||
struct DS* ds = (struct DS*) core->board;
|
||||
ARMReset(ds->arm7);
|
||||
ARMReset(ds->arm9);
|
||||
ARMReset(ds->ds7.cpu);
|
||||
ARMReset(ds->ds9.cpu);
|
||||
}
|
||||
|
||||
static void _DSCoreRunFrame(struct mCore* core) {
|
||||
|
|
137
src/ds/ds.c
137
src/ds/ds.c
|
@ -49,7 +49,7 @@ static void DS9WriteCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int
|
|||
static void DS9InterruptHandlerInit(struct ARMInterruptHandler* irqh);
|
||||
static void DS9ProcessEvents(struct ARMCore* cpu);
|
||||
|
||||
static void DSProcessEvents(struct DS* ds, struct mTiming* timing);
|
||||
static void DSProcessEvents(struct DSCommon* dscore);
|
||||
static void DSHitStub(struct ARMCore* cpu, uint32_t opcode);
|
||||
static void DSIllegal(struct ARMCore* cpu, uint32_t opcode);
|
||||
static void DSBreakpoint(struct ARMCore* cpu, int immediate);
|
||||
|
@ -58,16 +58,16 @@ static void _slice(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
|||
UNUSED(cyclesLate);
|
||||
struct DS* ds = context;
|
||||
uint32_t cycles = mTimingCurrentTime(timing) - ds->sliceStart;
|
||||
if (ds->activeCpu == ds->arm9) {
|
||||
ds->activeCpu = ds->arm7;
|
||||
if (ds->activeCpu == ds->ds9.cpu) {
|
||||
ds->activeCpu = ds->ds7.cpu;
|
||||
ds->cycleDrift += cycles;
|
||||
cycles = ds->cycleDrift >> 1;
|
||||
timing = &ds->timing7;
|
||||
timing = &ds->ds7.timing;
|
||||
} else {
|
||||
ds->activeCpu = ds->arm9;
|
||||
ds->activeCpu = ds->ds9.cpu;
|
||||
ds->cycleDrift -= cycles << 1;
|
||||
cycles = ds->cycleDrift + SLICE_CYCLES;
|
||||
timing = &ds->timing9;
|
||||
timing = &ds->ds9.timing;
|
||||
}
|
||||
mTimingSchedule(timing, &ds->slice, cycles);
|
||||
ds->sliceStart = mTimingCurrentTime(timing);
|
||||
|
@ -77,38 +77,42 @@ void DSCreate(struct DS* ds) {
|
|||
ds->d.id = DS_COMPONENT_MAGIC;
|
||||
ds->d.init = DSInit;
|
||||
ds->d.deinit = NULL;
|
||||
ds->arm7 = NULL;
|
||||
ds->arm9 = NULL;
|
||||
ds->ds7.p = ds;
|
||||
ds->ds9.p = ds;
|
||||
ds->ds7.cpu = NULL;
|
||||
ds->ds9.cpu = NULL;
|
||||
ds->ds7.ipc = &ds->ds9;
|
||||
ds->ds9.ipc = &ds->ds7;
|
||||
}
|
||||
|
||||
static void DSInit(void* cpu, struct mCPUComponent* component) {
|
||||
struct DS* ds = (struct DS*) component;
|
||||
struct ARMCore* core = cpu;
|
||||
if (!ds->arm7) {
|
||||
if (!ds->ds7.cpu) {
|
||||
// The ARM7 must get initialized first
|
||||
ds->arm7 = core;
|
||||
ds->ds7.cpu = core;
|
||||
ds->debugger = 0;
|
||||
ds->sync = 0;
|
||||
return;
|
||||
}
|
||||
ds->arm9 = cpu;
|
||||
ds->ds9.cpu = cpu;
|
||||
ds->activeCpu = NULL;
|
||||
|
||||
ds->arm9->cp15.r1.c0 = ARMControlRegFillVE(0);
|
||||
ds->ds9.cpu->cp15.r1.c0 = ARMControlRegFillVE(0);
|
||||
|
||||
ds->slice.name = "DS CPU Time Slicing";
|
||||
ds->slice.callback = _slice;
|
||||
ds->slice.context = ds;
|
||||
ds->slice.priority = UINT_MAX;
|
||||
|
||||
DS7InterruptHandlerInit(&ds->arm7->irqh);
|
||||
DS9InterruptHandlerInit(&ds->arm9->irqh);
|
||||
DS7InterruptHandlerInit(&ds->ds7.cpu->irqh);
|
||||
DS9InterruptHandlerInit(&ds->ds9.cpu->irqh);
|
||||
DSMemoryInit(ds);
|
||||
|
||||
ds->video.p = ds;
|
||||
|
||||
ds->springIRQ7 = 0;
|
||||
ds->springIRQ9 = 0;
|
||||
ds->ds7.springIRQ = 0;
|
||||
ds->ds9.springIRQ = 0;
|
||||
DSTimerInit(ds);
|
||||
ds->keySource = NULL;
|
||||
ds->rtcSource = NULL;
|
||||
|
@ -118,8 +122,8 @@ static void DSInit(void* cpu, struct mCPUComponent* component) {
|
|||
|
||||
ds->keyCallback = NULL;
|
||||
|
||||
mTimingInit(&ds->timing7, &ds->arm7->cycles, &ds->arm7->nextEvent);
|
||||
mTimingInit(&ds->timing9, &ds->arm9->cycles, &ds->arm9->nextEvent);
|
||||
mTimingInit(&ds->ds7.timing, &ds->ds7.cpu->cycles, &ds->ds7.cpu->nextEvent);
|
||||
mTimingInit(&ds->ds9.timing, &ds->ds9.cpu->cycles, &ds->ds9.cpu->nextEvent);
|
||||
}
|
||||
|
||||
void DSUnloadROM(struct DS* ds) {
|
||||
|
@ -132,8 +136,8 @@ void DSUnloadROM(struct DS* ds) {
|
|||
void DSDestroy(struct DS* ds) {
|
||||
DSUnloadROM(ds);
|
||||
DSMemoryDeinit(ds);
|
||||
mTimingDeinit(&ds->timing7);
|
||||
mTimingDeinit(&ds->timing9);
|
||||
mTimingDeinit(&ds->ds7.timing);
|
||||
mTimingDeinit(&ds->ds9.timing);
|
||||
}
|
||||
|
||||
void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh) {
|
||||
|
@ -171,7 +175,7 @@ void DS7Reset(struct ARMCore* cpu) {
|
|||
cpu->gprs[ARM_SP] = DS7_SP_BASE;
|
||||
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
mTimingClear(&ds->timing7);
|
||||
mTimingClear(&ds->ds7.timing);
|
||||
DSMemoryReset(ds);
|
||||
DS7IOInit(ds);
|
||||
|
||||
|
@ -203,13 +207,13 @@ void DS9Reset(struct ARMCore* cpu) {
|
|||
cpu->gprs[ARM_SP] = DS9_SP_BASE;
|
||||
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
mTimingClear(&ds->timing9);
|
||||
mTimingClear(&ds->ds9.timing);
|
||||
DS9IOInit(ds);
|
||||
|
||||
ds->activeCpu = cpu;
|
||||
mTimingSchedule(&ds->timing9, &ds->slice, SLICE_CYCLES);
|
||||
mTimingSchedule(&ds->ds9.timing, &ds->slice, SLICE_CYCLES);
|
||||
ds->cycleDrift = 0;
|
||||
ds->sliceStart = mTimingCurrentTime(&ds->timing9);
|
||||
ds->sliceStart = mTimingCurrentTime(&ds->ds9.timing);
|
||||
|
||||
struct DSCartridge* header = ds->romVf->map(ds->romVf, sizeof(*header), MAP_READ);
|
||||
if (header) {
|
||||
|
@ -232,26 +236,22 @@ void DS9Reset(struct ARMCore* cpu) {
|
|||
|
||||
static void DS7ProcessEvents(struct ARMCore* cpu) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
|
||||
if (ds->springIRQ7 && !cpu->cpsr.i) {
|
||||
ARMRaiseIRQ(cpu);
|
||||
ds->springIRQ7 = 0;
|
||||
}
|
||||
DSProcessEvents(ds, &ds->timing7);
|
||||
DSProcessEvents(&ds->ds7);
|
||||
}
|
||||
|
||||
static void DS9ProcessEvents(struct ARMCore* cpu) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
|
||||
if (ds->springIRQ9 && !cpu->cpsr.i) {
|
||||
ARMRaiseIRQ(cpu);
|
||||
ds->springIRQ9 = 0;
|
||||
}
|
||||
DSProcessEvents(ds, &ds->timing9);
|
||||
DSProcessEvents(&ds->ds9);
|
||||
}
|
||||
|
||||
static void DSProcessEvents(struct DS* ds, struct mTiming* timing) {
|
||||
struct ARMCore* cpu = ds->activeCpu;
|
||||
static void DSProcessEvents(struct DSCommon* dscore) {
|
||||
struct ARMCore* cpu = dscore->cpu;
|
||||
struct DS* ds = dscore->p;
|
||||
if (dscore->springIRQ && !cpu->cpsr.i) {
|
||||
ARMRaiseIRQ(cpu);
|
||||
dscore->springIRQ = 0;
|
||||
}
|
||||
|
||||
int32_t nextEvent = cpu->nextEvent;
|
||||
while (cpu->cycles >= nextEvent) {
|
||||
int32_t cycles = cpu->cycles;
|
||||
|
@ -266,7 +266,7 @@ static void DSProcessEvents(struct DS* ds, struct mTiming* timing) {
|
|||
#endif
|
||||
nextEvent = cycles;
|
||||
do {
|
||||
nextEvent = mTimingTick(timing, nextEvent);
|
||||
nextEvent = mTimingTick(&dscore->timing, nextEvent);
|
||||
} while (ds->cpuBlocked);
|
||||
|
||||
cpu->nextEvent = nextEvent;
|
||||
|
@ -287,41 +287,41 @@ static void DSProcessEvents(struct DS* ds, struct mTiming* timing) {
|
|||
}
|
||||
|
||||
void DSRunLoop(struct DS* ds) {
|
||||
if (ds->activeCpu == ds->arm9) {
|
||||
ARMv5RunLoop(ds->arm9);
|
||||
if (ds->activeCpu == ds->ds9.cpu) {
|
||||
ARMv5RunLoop(ds->ds9.cpu);
|
||||
} else {
|
||||
ARMv4RunLoop(ds->arm7);
|
||||
ARMv4RunLoop(ds->ds7.cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void DS7Step(struct DS* ds) {
|
||||
while (ds->activeCpu == ds->arm9) {
|
||||
ARMv5RunLoop(ds->arm9);
|
||||
while (ds->activeCpu == ds->ds9.cpu) {
|
||||
ARMv5RunLoop(ds->ds9.cpu);
|
||||
}
|
||||
ARMv4Run(ds->arm7);
|
||||
ARMv4Run(ds->ds7.cpu);
|
||||
}
|
||||
|
||||
void DS9Step(struct DS* ds) {
|
||||
while (ds->activeCpu == ds->arm7) {
|
||||
ARMv4RunLoop(ds->arm7);
|
||||
while (ds->activeCpu == ds->ds7.cpu) {
|
||||
ARMv4RunLoop(ds->ds7.cpu);
|
||||
}
|
||||
ARMv5Run(ds->arm9);
|
||||
ARMv5Run(ds->ds9.cpu);
|
||||
}
|
||||
|
||||
void DSAttachDebugger(struct DS* ds, struct mDebugger* debugger) {
|
||||
ds->debugger = (struct ARMDebugger*) debugger->platform;
|
||||
ds->arm7->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
|
||||
ds->arm9->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
|
||||
ARMHotplugAttach(ds->arm7, CPU_COMPONENT_DEBUGGER);
|
||||
ARMHotplugAttach(ds->arm9, CPU_COMPONENT_DEBUGGER);
|
||||
ds->ds7.cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
|
||||
ds->ds9.cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
|
||||
ARMHotplugAttach(ds->ds7.cpu, CPU_COMPONENT_DEBUGGER);
|
||||
ARMHotplugAttach(ds->ds9.cpu, CPU_COMPONENT_DEBUGGER);
|
||||
}
|
||||
|
||||
void DSDetachDebugger(struct DS* ds) {
|
||||
ds->debugger = NULL;
|
||||
ARMHotplugDetach(ds->arm7, CPU_COMPONENT_DEBUGGER);
|
||||
ARMHotplugDetach(ds->arm9, CPU_COMPONENT_DEBUGGER);
|
||||
ds->arm7->components[CPU_COMPONENT_DEBUGGER] = NULL;
|
||||
ds->arm9->components[CPU_COMPONENT_DEBUGGER] = NULL;
|
||||
ARMHotplugDetach(ds->ds7.cpu, CPU_COMPONENT_DEBUGGER);
|
||||
ARMHotplugDetach(ds->ds9.cpu, CPU_COMPONENT_DEBUGGER);
|
||||
ds->ds7.cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
|
||||
ds->ds9.cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
|
||||
}
|
||||
|
||||
bool DSLoadROM(struct DS* ds, struct VFile* vf) {
|
||||
|
@ -442,7 +442,7 @@ void DSBreakpoint(struct ARMCore* cpu, int immediate) {
|
|||
void DS7TestIRQ(struct ARMCore* cpu) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
if (0) {
|
||||
ds->springIRQ7 = 1;
|
||||
ds->ds7.springIRQ = 1;
|
||||
cpu->nextEvent = cpu->cycles;
|
||||
}
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ void DS7TestIRQ(struct ARMCore* cpu) {
|
|||
void DS9TestIRQ(struct ARMCore* cpu) {
|
||||
struct DS* ds = (struct DS*) cpu->master;
|
||||
if (0) {
|
||||
ds->springIRQ9 = 1;
|
||||
ds->ds9.springIRQ = 1;
|
||||
cpu->nextEvent = cpu->cycles;
|
||||
}
|
||||
}
|
||||
|
@ -552,30 +552,27 @@ void DS9WriteCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode
|
|||
}
|
||||
|
||||
void DSWriteIE(struct ARMCore* cpu, uint16_t* io, uint32_t value) {
|
||||
if (io[DS7_REG_IME >> 1] && (value & io[DS7_REG_IF_LO >> 1] || (value >> 16) & io[DS7_REG_IF_HI >> 1])) {
|
||||
if (io[DS_REG_IME >> 1] && (value & io[DS_REG_IF_LO >> 1] || (value >> 16) & io[DS_REG_IF_HI >> 1])) {
|
||||
ARMRaiseIRQ(cpu);
|
||||
}
|
||||
}
|
||||
void DSWriteIME(struct ARMCore* cpu, uint16_t* io, uint16_t value) {
|
||||
if (value && (io[DS7_REG_IE_LO >> 1] & io[DS7_REG_IF_LO >> 1] || io[DS7_REG_IE_HI >> 1] & io[DS7_REG_IF_HI >> 1])) {
|
||||
if (value && (io[DS_REG_IE_LO >> 1] & io[DS_REG_IF_LO >> 1] || io[DS_REG_IE_HI >> 1] & io[DS_REG_IF_HI >> 1])) {
|
||||
ARMRaiseIRQ(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void DSRaiseIRQ(struct ARMCore* cpu, uint16_t* io, enum DSIRQ irq) {
|
||||
if (irq < 16) {
|
||||
io[DS7_REG_IF_LO >> 1] |= 1 << irq;
|
||||
io[DS_REG_IF_LO >> 1] |= 1 << irq;
|
||||
} else {
|
||||
io[DS7_REG_IF_HI >> 1] |= 1 << (irq - 16);
|
||||
io[DS_REG_IF_HI >> 1] |= 1 << (irq - 16);
|
||||
}
|
||||
cpu->halted = 0;
|
||||
|
||||
if (!io[DS7_REG_IME >> 1]) {
|
||||
return;
|
||||
}
|
||||
if (irq < 16 && (io[DS7_REG_IE_LO >> 1] & 1 << irq)) {
|
||||
ARMRaiseIRQ(cpu);
|
||||
} else if (io[DS7_REG_IE_HI >> 1] & 1 << (irq - 16)) {
|
||||
ARMRaiseIRQ(cpu);
|
||||
if ((irq < 16 && (io[DS_REG_IE_LO >> 1] & 1 << irq)) || (io[DS_REG_IE_HI >> 1] & 1 << (irq - 16))) {
|
||||
cpu->halted = 0;
|
||||
if (io[DS_REG_IME >> 1]) {
|
||||
ARMRaiseIRQ(cpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,10 +69,10 @@ static void _switchCpu(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
|
|||
struct mCore* core = dsDebugger->core;
|
||||
struct DS* ds = core->board;
|
||||
debugger->d.platform->deinit(debugger->d.platform);
|
||||
if (core->cpu == ds->arm9) {
|
||||
core->cpu = ds->arm7;
|
||||
if (core->cpu == ds->ds9.cpu) {
|
||||
core->cpu = ds->ds7.cpu;
|
||||
} else {
|
||||
core->cpu = ds->arm9;
|
||||
core->cpu = ds->ds9.cpu;
|
||||
}
|
||||
debugger->d.platform->init(core->cpu, debugger->d.platform);
|
||||
debugger->system->printStatus(debugger->system);
|
||||
|
|
198
src/ds/io.c
198
src/ds/io.c
|
@ -10,64 +10,92 @@
|
|||
mLOG_DEFINE_CATEGORY(DS_IO, "DS I/O");
|
||||
|
||||
static void _writeIPCSync(struct ARMCore* remoteCpu, uint16_t* remoteIo, int16_t value) {
|
||||
remoteIo[DS7_REG_IPCSYNC >> 1] &= 0xFFF0;
|
||||
remoteIo[DS7_REG_IPCSYNC >> 1] |= (value >> 8) & 0x0F;
|
||||
if (value & 0x2000 && remoteIo[DS7_REG_IPCSYNC >> 1] & 0x4000) {
|
||||
remoteIo[DS_REG_IPCSYNC >> 1] &= 0xFFF0;
|
||||
remoteIo[DS_REG_IPCSYNC >> 1] |= (value >> 8) & 0x0F;
|
||||
if (value & 0x2000 && remoteIo[DS_REG_IPCSYNC >> 1] & 0x4000) {
|
||||
mLOG(DS_IO, STUB, "Unimplemented IPC IRQ");
|
||||
UNUSED(remoteCpu);
|
||||
}
|
||||
}
|
||||
|
||||
static bool DSIOWrite(struct DSCommon* dscore, uint32_t address, uint16_t value) {
|
||||
switch (address) {
|
||||
// Timers
|
||||
case DS_REG_TM0CNT_LO:
|
||||
GBATimerWriteTMCNT_LO(&dscore->timers[0], value);
|
||||
return true;
|
||||
case DS_REG_TM1CNT_LO:
|
||||
GBATimerWriteTMCNT_LO(&dscore->timers[1], value);
|
||||
return true;
|
||||
case DS_REG_TM2CNT_LO:
|
||||
GBATimerWriteTMCNT_LO(&dscore->timers[2], value);
|
||||
return true;
|
||||
case DS_REG_TM3CNT_LO:
|
||||
GBATimerWriteTMCNT_LO(&dscore->timers[3], value);
|
||||
return true;
|
||||
|
||||
case DS_REG_TM0CNT_HI:
|
||||
value &= 0x00C7;
|
||||
DSTimerWriteTMCNT_HI(&dscore->timers[0], &dscore->timing, dscore->cpu, &dscore->memory.io[DS_REG_TM0CNT_LO >> 1], value);
|
||||
break;
|
||||
case DS_REG_TM1CNT_HI:
|
||||
value &= 0x00C7;
|
||||
DSTimerWriteTMCNT_HI(&dscore->timers[1], &dscore->timing, dscore->cpu, &dscore->memory.io[DS_REG_TM1CNT_LO >> 1], value);
|
||||
break;
|
||||
case DS_REG_TM2CNT_HI:
|
||||
value &= 0x00C7;
|
||||
DSTimerWriteTMCNT_HI(&dscore->timers[2], &dscore->timing, dscore->cpu, &dscore->memory.io[DS_REG_TM2CNT_LO >> 1], value);
|
||||
break;
|
||||
case DS_REG_TM3CNT_HI:
|
||||
value &= 0x00C7;
|
||||
DSTimerWriteTMCNT_HI(&dscore->timers[3], &dscore->timing, dscore->cpu, &dscore->memory.io[DS_REG_TM3CNT_LO >> 1], value);
|
||||
break;
|
||||
|
||||
case DS_REG_IPCSYNC:
|
||||
value &= 0x6F00;
|
||||
value |= dscore->memory.io[address >> 1] & 0x000F;
|
||||
_writeIPCSync(dscore->ipc->cpu, dscore->ipc->memory.io, value);
|
||||
break;
|
||||
case DS_REG_IME:
|
||||
DSWriteIME(dscore->cpu, dscore->memory.io, value);
|
||||
break;
|
||||
case DS_REG_IF_LO:
|
||||
case DS_REG_IF_HI:
|
||||
value = dscore->memory.io[address >> 1] & ~value;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DSIOUpdateTimer(struct DSCommon* dscore, uint32_t address) {
|
||||
switch (address) {
|
||||
case DS_REG_TM0CNT_LO:
|
||||
GBATimerUpdateRegisterInternal(&dscore->timers[0], &dscore->timing, dscore->cpu, &dscore->memory.io[address >> 1], 0);
|
||||
break;
|
||||
case DS_REG_TM1CNT_LO:
|
||||
GBATimerUpdateRegisterInternal(&dscore->timers[1], &dscore->timing, dscore->cpu, &dscore->memory.io[address >> 1], 0);
|
||||
break;
|
||||
case DS_REG_TM2CNT_LO:
|
||||
GBATimerUpdateRegisterInternal(&dscore->timers[2], &dscore->timing, dscore->cpu, &dscore->memory.io[address >> 1], 0);
|
||||
break;
|
||||
case DS_REG_TM3CNT_LO:
|
||||
GBATimerUpdateRegisterInternal(&dscore->timers[3], &dscore->timing, dscore->cpu, &dscore->memory.io[address >> 1], 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DS7IOInit(struct DS* ds) {
|
||||
memset(ds->memory.io7, 0, sizeof(ds->memory.io7));
|
||||
}
|
||||
|
||||
void DS7IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
|
||||
switch (address) {
|
||||
// Timers
|
||||
case DS7_REG_TM0CNT_LO:
|
||||
GBATimerWriteTMCNT_LO(&ds->timers7[0], value);
|
||||
return;
|
||||
case DS7_REG_TM1CNT_LO:
|
||||
GBATimerWriteTMCNT_LO(&ds->timers7[1], value);
|
||||
return;
|
||||
case DS7_REG_TM2CNT_LO:
|
||||
GBATimerWriteTMCNT_LO(&ds->timers7[2], value);
|
||||
return;
|
||||
case DS7_REG_TM3CNT_LO:
|
||||
GBATimerWriteTMCNT_LO(&ds->timers7[3], value);
|
||||
return;
|
||||
|
||||
case DS7_REG_TM0CNT_HI:
|
||||
value &= 0x00C7;
|
||||
DSTimerWriteTMCNT_HI(&ds->timers7[0], &ds->timing7, ds->arm7, &ds->memory.io7[DS7_REG_TM0CNT_LO >> 1], value);
|
||||
break;
|
||||
case DS7_REG_TM1CNT_HI:
|
||||
value &= 0x00C7;
|
||||
DSTimerWriteTMCNT_HI(&ds->timers7[1], &ds->timing7, ds->arm7, &ds->memory.io7[DS7_REG_TM1CNT_LO >> 1], value);
|
||||
break;
|
||||
case DS7_REG_TM2CNT_HI:
|
||||
value &= 0x00C7;
|
||||
DSTimerWriteTMCNT_HI(&ds->timers7[2], &ds->timing7, ds->arm7, &ds->memory.io7[DS7_REG_TM2CNT_LO >> 1], value);
|
||||
break;
|
||||
case DS7_REG_TM3CNT_HI:
|
||||
value &= 0x00C7;
|
||||
DSTimerWriteTMCNT_HI(&ds->timers7[3], &ds->timing7, ds->arm7, &ds->memory.io7[DS7_REG_TM3CNT_LO >> 1], value);
|
||||
break;
|
||||
|
||||
case DS7_REG_IPCSYNC:
|
||||
value &= 0x6F00;
|
||||
value |= ds->memory.io7[address >> 1] & 0x000F;
|
||||
_writeIPCSync(ds->arm9, ds->memory.io9, value);
|
||||
break;
|
||||
case DS7_REG_IME:
|
||||
DSWriteIME(ds->arm7, ds->memory.io7, value);
|
||||
break;
|
||||
case DS7_REG_IF_LO:
|
||||
case DS7_REG_IF_HI:
|
||||
value = ds->memory.io7[address >> 1] & ~value;
|
||||
break;
|
||||
default:
|
||||
if (DSIOWrite(&ds->ds7, address, value)) {
|
||||
break;
|
||||
}
|
||||
mLOG(DS_IO, STUB, "Stub DS7 I/O register write: %06X:%04X", address, value);
|
||||
if (address >= DS7_REG_MAX) {
|
||||
mLOG(DS_IO, GAME_ERROR, "Write to unused DS7 I/O register: %06X:%04X", address, value);
|
||||
|
@ -81,7 +109,7 @@ void DS7IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
|
|||
void DS7IOWrite8(struct DS* ds, uint32_t address, uint8_t value) {
|
||||
if (address < DS7_REG_MAX) {
|
||||
uint16_t value16 = value << (8 * (address & 1));
|
||||
value16 |= (ds->memory.io7[(address & 0xFFF) >> 1]) & ~(0xFF << (8 * (address & 1)));
|
||||
value16 |= (ds->ds7.memory.io[(address & 0xFFF) >> 1]) & ~(0xFF << (8 * (address & 1)));
|
||||
DS7IOWrite(ds, address & 0xFFFFFFFE, value16);
|
||||
} else {
|
||||
mLOG(DS, STUB, "Writing to unknown DS7 register: %08X:%02X", address, value);
|
||||
|
@ -90,43 +118,36 @@ void DS7IOWrite8(struct DS* ds, uint32_t address, uint8_t value) {
|
|||
|
||||
void DS7IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
|
||||
switch (address) {
|
||||
case DS7_REG_IE_LO:
|
||||
DSWriteIE(ds->arm7, ds->memory.io7, value);
|
||||
case DS_REG_IE_LO:
|
||||
DSWriteIE(ds->ds7.cpu, ds->ds7.memory.io, value);
|
||||
break;
|
||||
default:
|
||||
DS7IOWrite(ds, address, value & 0xFFFF);
|
||||
DS7IOWrite(ds, address | 2, value >> 16);
|
||||
return;
|
||||
}
|
||||
ds->memory.io7[address >> 1] = value;
|
||||
ds->memory.io7[(address >> 1) + 1] = value >> 16;
|
||||
ds->ds7.memory.io[address >> 1] = value;
|
||||
ds->ds7.memory.io[(address >> 1) + 1] = value >> 16;
|
||||
}
|
||||
|
||||
uint16_t DS7IORead(struct DS* ds, uint32_t address) {
|
||||
switch (address) {
|
||||
case DS7_REG_TM0CNT_LO:
|
||||
GBATimerUpdateRegisterInternal(&ds->timers7[0], &ds->timing7, ds->arm7, &ds->memory.io7[address >> 1], 0);
|
||||
case DS_REG_TM0CNT_LO:
|
||||
case DS_REG_TM1CNT_LO:
|
||||
case DS_REG_TM2CNT_LO:
|
||||
case DS_REG_TM3CNT_LO:
|
||||
DSIOUpdateTimer(&ds->ds7, address);
|
||||
break;
|
||||
case DS7_REG_TM1CNT_LO:
|
||||
GBATimerUpdateRegisterInternal(&ds->timers7[1], &ds->timing7, ds->arm7, &ds->memory.io7[address >> 1], 0);
|
||||
break;
|
||||
case DS7_REG_TM2CNT_LO:
|
||||
GBATimerUpdateRegisterInternal(&ds->timers7[2], &ds->timing7, ds->arm7, &ds->memory.io7[address >> 1], 0);
|
||||
break;
|
||||
case DS7_REG_TM3CNT_LO:
|
||||
GBATimerUpdateRegisterInternal(&ds->timers7[3], &ds->timing7, ds->arm7, &ds->memory.io7[address >> 1], 0);
|
||||
break;
|
||||
|
||||
case DS7_REG_TM0CNT_HI:
|
||||
case DS7_REG_TM1CNT_HI:
|
||||
case DS7_REG_TM2CNT_HI:
|
||||
case DS7_REG_TM3CNT_HI:
|
||||
case DS7_REG_IPCSYNC:
|
||||
case DS7_REG_IME:
|
||||
case DS7_REG_IE_LO:
|
||||
case DS7_REG_IE_HI:
|
||||
case DS7_REG_IF_LO:
|
||||
case DS7_REG_IF_HI:
|
||||
case DS_REG_TM0CNT_HI:
|
||||
case DS_REG_TM1CNT_HI:
|
||||
case DS_REG_TM2CNT_HI:
|
||||
case DS_REG_TM3CNT_HI:
|
||||
case DS_REG_IPCSYNC:
|
||||
case DS_REG_IME:
|
||||
case DS_REG_IE_LO:
|
||||
case DS_REG_IE_HI:
|
||||
case DS_REG_IF_LO:
|
||||
case DS_REG_IF_HI:
|
||||
// Handled transparently by the registers
|
||||
break;
|
||||
default:
|
||||
|
@ -144,12 +165,10 @@ void DS9IOInit(struct DS* ds) {
|
|||
|
||||
void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
|
||||
switch (address) {
|
||||
case DS9_REG_IPCSYNC:
|
||||
value &= 0x6F00;
|
||||
value |= ds->memory.io9[address >> 1] & 0x000F;
|
||||
_writeIPCSync(ds->arm7, ds->memory.io7, value);
|
||||
break;
|
||||
default:
|
||||
if (DSIOWrite(&ds->ds9, address, value)) {
|
||||
break;
|
||||
}
|
||||
mLOG(DS_IO, STUB, "Stub DS9 I/O register write: %06X:%04X", address, value);
|
||||
if (address >= DS7_REG_MAX) {
|
||||
mLOG(DS_IO, GAME_ERROR, "Write to unused DS9 I/O register: %06X:%04X", address, value);
|
||||
|
@ -177,20 +196,35 @@ void DS9IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
|
|||
DS9IOWrite(ds, address | 2, value >> 16);
|
||||
return;
|
||||
}
|
||||
ds->memory.io9[address >> 1] = value;
|
||||
ds->memory.io9[(address >> 1) + 1] = value >> 16;
|
||||
ds->ds9.memory.io[address >> 1] = value;
|
||||
ds->ds9.memory.io[(address >> 1) + 1] = value >> 16;
|
||||
}
|
||||
|
||||
uint16_t DS9IORead(struct DS* ds, uint32_t address) {
|
||||
switch (address) {
|
||||
case DS9_REG_IPCSYNC:
|
||||
case DS_REG_TM0CNT_LO:
|
||||
case DS_REG_TM1CNT_LO:
|
||||
case DS_REG_TM2CNT_LO:
|
||||
case DS_REG_TM3CNT_LO:
|
||||
DSIOUpdateTimer(&ds->ds9, address);
|
||||
break;
|
||||
case DS_REG_TM0CNT_HI:
|
||||
case DS_REG_TM1CNT_HI:
|
||||
case DS_REG_TM2CNT_HI:
|
||||
case DS_REG_TM3CNT_HI:
|
||||
case DS_REG_IPCSYNC:
|
||||
case DS_REG_IME:
|
||||
case DS_REG_IE_LO:
|
||||
case DS_REG_IE_HI:
|
||||
case DS_REG_IF_LO:
|
||||
case DS_REG_IF_HI:
|
||||
// Handled transparently by the registers
|
||||
break;
|
||||
default:
|
||||
mLOG(DS_IO, STUB, "Stub DS9 I/O register read: %06X", address);
|
||||
}
|
||||
if (address < DS9_REG_MAX) {
|
||||
return ds->memory.io9[address >> 1];
|
||||
return ds->ds9.memory.io[address >> 1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ 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;
|
||||
struct ARMCore* arm7 = ds->ds7.cpu;
|
||||
arm7->memory.load32 = DS7Load32;
|
||||
arm7->memory.load16 = DS7Load16;
|
||||
arm7->memory.load8 = DS7Load8;
|
||||
|
@ -91,7 +91,7 @@ void DSMemoryInit(struct DS* ds) {
|
|||
arm7->memory.storeMultiple = DS7StoreMultiple;
|
||||
arm7->memory.stall = DSMemoryStall;
|
||||
|
||||
struct ARMCore* arm9 = ds->arm9;
|
||||
struct ARMCore* arm9 = ds->ds9.cpu;
|
||||
arm9->memory.load32 = DS9Load32;
|
||||
arm9->memory.load16 = DS9Load16;
|
||||
arm9->memory.load8 = DS9Load8;
|
||||
|
@ -111,8 +111,10 @@ void DSMemoryInit(struct DS* ds) {
|
|||
ds->memory.dtcm = NULL;
|
||||
ds->memory.rom = NULL;
|
||||
|
||||
ds->memory.activeRegion7 = -1;
|
||||
ds->memory.activeRegion9 = -1;
|
||||
ds->ds7.memory.activeRegion = -1;
|
||||
ds->ds9.memory.activeRegion = -1;
|
||||
ds->ds7.memory.io = ds->memory.io7;
|
||||
ds->ds9.memory.io = ds->memory.io9;
|
||||
|
||||
arm7->memory.activeRegion = 0;
|
||||
arm7->memory.activeMask = 0;
|
||||
|
@ -165,12 +167,10 @@ void DSMemoryReset(struct DS* ds) {
|
|||
}
|
||||
ds->memory.dtcm = anonymousMemoryMap(DS9_SIZE_DTCM);
|
||||
|
||||
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;
|
||||
memset(ds->ds7.memory.dma, 0, sizeof(ds->ds7.memory.dma));
|
||||
memset(ds->ds9.memory.dma, 0, sizeof(ds->ds9.memory.dma));
|
||||
ds->ds7.memory.activeDMA = -1;
|
||||
ds->ds9.memory.activeDMA = -1;
|
||||
|
||||
// TODO: Correct size
|
||||
ds->memory.wramSize7 = 0x8000;
|
||||
|
@ -188,7 +188,7 @@ static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
|
|||
|
||||
int newRegion = address >> DS_BASE_OFFSET;
|
||||
|
||||
memory->activeRegion7 = newRegion;
|
||||
ds->ds7.memory.activeRegion = newRegion;
|
||||
switch (newRegion) {
|
||||
case DS_REGION_WORKING_RAM:
|
||||
if (address >= DS7_BASE_WORKING_RAM || !memory->wramSize7) {
|
||||
|
@ -550,7 +550,7 @@ static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t address) {
|
|||
|
||||
int newRegion = address >> DS_BASE_OFFSET;
|
||||
|
||||
memory->activeRegion9 = newRegion;
|
||||
ds->ds9.memory.activeRegion = newRegion;
|
||||
switch (newRegion) {
|
||||
case DS9_REGION_ITCM:
|
||||
case DS9_REGION_ITCM_MIRROR:
|
||||
|
|
114
src/ds/timer.c
114
src/ds/timer.c
|
@ -8,81 +8,81 @@
|
|||
#include <mgba/internal/arm/arm.h>
|
||||
#include <mgba/internal/ds/ds.h>
|
||||
|
||||
static void DS7TimerUpdate0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct DS* ds = context;
|
||||
struct GBATimer* timer = &ds->timers7[0];
|
||||
static void DSTimerUpdate0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct DSCommon* dscore = context;
|
||||
struct GBATimer* timer = &dscore->timers[0];
|
||||
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
||||
DSRaiseIRQ(ds->arm7, ds->memory.io7, DS_IRQ_TIMER0);
|
||||
DSRaiseIRQ(dscore->cpu, dscore->memory.io, DS_IRQ_TIMER0);
|
||||
}
|
||||
GBATimerUpdate(timing, &ds->timers7[0], &ds->memory.io7[DS7_REG_TM0CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdateCountUp(timing, &ds->timers7[1], &ds->memory.io7[DS7_REG_TM1CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdate(timing, &dscore->timers[0], &dscore->memory.io[DS_REG_TM0CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdateCountUp(timing, &dscore->timers[1], &dscore->memory.io[DS_REG_TM1CNT_LO >> 1], cyclesLate);
|
||||
}
|
||||
|
||||
static void DS7TimerUpdate1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct DS* ds = context;
|
||||
struct GBATimer* timer = &ds->timers7[1];
|
||||
static void DSTimerUpdate1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct DSCommon* dscore = context;
|
||||
struct GBATimer* timer = &dscore->timers[1];
|
||||
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
||||
DSRaiseIRQ(ds->arm7, ds->memory.io7, DS_IRQ_TIMER1);
|
||||
DSRaiseIRQ(dscore->cpu, dscore->memory.io, DS_IRQ_TIMER1);
|
||||
}
|
||||
GBATimerUpdate(timing, &ds->timers7[1], &ds->memory.io7[DS7_REG_TM1CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdateCountUp(timing, &ds->timers7[2], &ds->memory.io7[DS7_REG_TM2CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdate(timing, &dscore->timers[1], &dscore->memory.io[DS_REG_TM1CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdateCountUp(timing, &dscore->timers[2], &dscore->memory.io[DS_REG_TM2CNT_LO >> 1], cyclesLate);
|
||||
}
|
||||
|
||||
static void DS7TimerUpdate2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct DS* ds = context;
|
||||
struct GBATimer* timer = &ds->timers7[2];
|
||||
static void DSTimerUpdate2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct DSCommon* dscore = context;
|
||||
struct GBATimer* timer = &dscore->timers[2];
|
||||
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
||||
DSRaiseIRQ(ds->arm7, ds->memory.io7, DS_IRQ_TIMER2);
|
||||
DSRaiseIRQ(dscore->cpu, dscore->memory.io, DS_IRQ_TIMER2);
|
||||
}
|
||||
GBATimerUpdate(timing, &ds->timers7[2], &ds->memory.io7[DS7_REG_TM2CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdateCountUp(timing, &ds->timers7[3], &ds->memory.io7[DS7_REG_TM3CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdate(timing, &dscore->timers[2], &dscore->memory.io[DS_REG_TM2CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdateCountUp(timing, &dscore->timers[3], &dscore->memory.io[DS_REG_TM3CNT_LO >> 1], cyclesLate);
|
||||
}
|
||||
|
||||
static void DS7TimerUpdate3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct DS* ds = context;
|
||||
struct GBATimer* timer = &ds->timers7[3];
|
||||
static void DSTimerUpdate3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct DSCommon* dscore = context;
|
||||
struct GBATimer* timer = &dscore->timers[3];
|
||||
if (GBATimerFlagsIsDoIrq(timer->flags)) {
|
||||
DSRaiseIRQ(ds->arm7, ds->memory.io7, DS_IRQ_TIMER3);
|
||||
DSRaiseIRQ(dscore->cpu, dscore->memory.io, DS_IRQ_TIMER3);
|
||||
}
|
||||
GBATimerUpdate(timing, &ds->timers7[3], &ds->memory.io7[DS7_REG_TM3CNT_LO >> 1], cyclesLate);
|
||||
GBATimerUpdate(timing, &dscore->timers[3], &dscore->memory.io[DS_REG_TM3CNT_LO >> 1], cyclesLate);
|
||||
}
|
||||
|
||||
void DSTimerInit(struct DS* ds) {
|
||||
memset(ds->timers7, 0, sizeof(ds->timers7));
|
||||
ds->timers7[0].event.name = "DS7 Timer 0";
|
||||
ds->timers7[0].event.callback = DS7TimerUpdate0;
|
||||
ds->timers7[0].event.context = ds;
|
||||
ds->timers7[0].event.priority = 0x20;
|
||||
ds->timers7[1].event.name = "DS7 Timer 1";
|
||||
ds->timers7[1].event.callback = DS7TimerUpdate1;
|
||||
ds->timers7[1].event.context = ds;
|
||||
ds->timers7[1].event.priority = 0x21;
|
||||
ds->timers7[2].event.name = "DS7 Timer 2";
|
||||
ds->timers7[2].event.callback = DS7TimerUpdate2;
|
||||
ds->timers7[2].event.context = ds;
|
||||
ds->timers7[2].event.priority = 0x22;
|
||||
ds->timers7[3].event.name = "DS7 Timer 3";
|
||||
ds->timers7[3].event.callback = DS7TimerUpdate3;
|
||||
ds->timers7[3].event.context = ds;
|
||||
ds->timers7[3].event.priority = 0x23;
|
||||
memset(ds->ds7.timers, 0, sizeof(ds->ds7.timers));
|
||||
ds->ds7.timers[0].event.name = "DS7 Timer 0";
|
||||
ds->ds7.timers[0].event.callback = DSTimerUpdate0;
|
||||
ds->ds7.timers[0].event.context = &ds->ds7;
|
||||
ds->ds7.timers[0].event.priority = 0x20;
|
||||
ds->ds7.timers[1].event.name = "DS7 Timer 1";
|
||||
ds->ds7.timers[0].event.callback = DSTimerUpdate1;
|
||||
ds->ds7.timers[0].event.context = &ds->ds7;
|
||||
ds->ds7.timers[1].event.priority = 0x21;
|
||||
ds->ds7.timers[2].event.name = "DS7 Timer 2";
|
||||
ds->ds7.timers[0].event.callback = DSTimerUpdate2;
|
||||
ds->ds7.timers[0].event.context = &ds->ds7;
|
||||
ds->ds7.timers[2].event.priority = 0x22;
|
||||
ds->ds7.timers[3].event.name = "DS7 Timer 3";
|
||||
ds->ds7.timers[0].event.callback = DSTimerUpdate3;
|
||||
ds->ds7.timers[0].event.context = &ds->ds7;
|
||||
ds->ds7.timers[3].event.priority = 0x23;
|
||||
|
||||
memset(ds->timers9, 0, sizeof(ds->timers9));
|
||||
ds->timers9[0].event.name = "DS9 Timer 0";
|
||||
ds->timers9[0].event.callback = NULL;
|
||||
ds->timers9[0].event.context = ds;
|
||||
ds->timers9[0].event.priority = 0x20;
|
||||
ds->timers9[1].event.name = "DS9 Timer 1";
|
||||
ds->timers9[1].event.callback = NULL;
|
||||
ds->timers9[1].event.context = ds;
|
||||
ds->timers9[1].event.priority = 0x21;
|
||||
ds->timers9[2].event.name = "DS9 Timer 2";
|
||||
ds->timers9[2].event.callback = NULL;
|
||||
ds->timers9[2].event.context = ds;
|
||||
ds->timers9[2].event.priority = 0x22;
|
||||
ds->timers9[3].event.name = "DS9 Timer 3";
|
||||
ds->timers9[3].event.callback = NULL;
|
||||
ds->timers9[3].event.context = ds;
|
||||
ds->timers9[3].event.priority = 0x23;
|
||||
memset(ds->ds9.timers, 0, sizeof(ds->ds9.timers));
|
||||
ds->ds9.timers[0].event.name = "DS9 Timer 0";
|
||||
ds->ds9.timers[0].event.callback = DSTimerUpdate0;
|
||||
ds->ds9.timers[0].event.context = ds;
|
||||
ds->ds9.timers[0].event.priority = 0x20;
|
||||
ds->ds9.timers[1].event.name = "DS9 Timer 1";
|
||||
ds->ds9.timers[1].event.callback = DSTimerUpdate1;
|
||||
ds->ds9.timers[1].event.context = ds;
|
||||
ds->ds9.timers[1].event.priority = 0x21;
|
||||
ds->ds9.timers[2].event.name = "DS9 Timer 2";
|
||||
ds->ds9.timers[2].event.callback = DSTimerUpdate2;
|
||||
ds->ds9.timers[2].event.context = ds;
|
||||
ds->ds9.timers[2].event.priority = 0x22;
|
||||
ds->ds9.timers[3].event.name = "DS9 Timer 3";
|
||||
ds->ds9.timers[3].event.callback = DSTimerUpdate3;
|
||||
ds->ds9.timers[3].event.context = ds;
|
||||
ds->ds9.timers[3].event.priority = 0x23;
|
||||
}
|
||||
|
||||
void DSTimerWriteTMCNT_HI(struct GBATimer* timer, struct mTiming* timing, struct ARMCore* cpu, uint16_t* io, uint16_t value) {
|
||||
|
|
Loading…
Reference in New Issue