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 "Platforms:")
|
||||||
message(STATUS " Game Boy Advance: ${M_CORE_GBA}")
|
message(STATUS " Game Boy Advance: ${M_CORE_GBA}")
|
||||||
message(STATUS " Game Boy: ${M_CORE_GB}")
|
message(STATUS " Game Boy: ${M_CORE_GB}")
|
||||||
|
message(STATUS " DS: ${M_CORE_DS}")
|
||||||
message(STATUS "Features:")
|
message(STATUS "Features:")
|
||||||
message(STATUS " Debuggers: ${USE_DEBUGGERS}")
|
message(STATUS " Debuggers: ${USE_DEBUGGERS}")
|
||||||
message(STATUS " CLI debugger: ${USE_EDITLINE}")
|
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) {
|
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) {
|
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) {
|
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) {
|
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/decoder.h"
|
||||||
#include "arm/debugger/debugger.h"
|
#include "arm/debugger/debugger.h"
|
||||||
#include "arm/isa-inlines.h"
|
#include "arm/isa-inlines.h"
|
||||||
|
#include "ds/bios.h"
|
||||||
|
|
||||||
#include "util/crc32.h"
|
#include "util/crc32.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/math.h"
|
#include "util/math.h"
|
||||||
#include "util/patch.h"
|
|
||||||
#include "util/vfs.h"
|
#include "util/vfs.h"
|
||||||
|
|
||||||
mLOG_DEFINE_CATEGORY(DS, "DS");
|
mLOG_DEFINE_CATEGORY(DS, "DS");
|
||||||
|
@ -67,8 +67,11 @@ static void DSInit(void* cpu, struct mCPUComponent* component) {
|
||||||
}
|
}
|
||||||
ds->arm9 = cpu;
|
ds->arm9 = cpu;
|
||||||
|
|
||||||
|
ds->arm9->cp15.r1.c0 = ARMControlRegFillVE(0);
|
||||||
|
|
||||||
DS7InterruptHandlerInit(&ds->arm7->irqh);
|
DS7InterruptHandlerInit(&ds->arm7->irqh);
|
||||||
DS9InterruptHandlerInit(&ds->arm9->irqh);
|
DS9InterruptHandlerInit(&ds->arm9->irqh);
|
||||||
|
DSMemoryInit(ds);
|
||||||
|
|
||||||
ds->video.p = ds;
|
ds->video.p = ds;
|
||||||
|
|
||||||
|
@ -92,6 +95,7 @@ void DSUnloadROM(struct DS* ds) {
|
||||||
|
|
||||||
void DSDestroy(struct DS* ds) {
|
void DSDestroy(struct DS* ds) {
|
||||||
DSUnloadROM(ds);
|
DSUnloadROM(ds);
|
||||||
|
DSMemoryDeinit(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh) {
|
void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh) {
|
||||||
|
@ -134,6 +138,9 @@ void DS9Reset(struct ARMCore* cpu) {
|
||||||
cpu->gprs[ARM_SP] = DS9_SP_BASE_SVC;
|
cpu->gprs[ARM_SP] = DS9_SP_BASE_SVC;
|
||||||
ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
|
ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
|
||||||
cpu->gprs[ARM_SP] = DS9_SP_BASE;
|
cpu->gprs[ARM_SP] = DS9_SP_BASE;
|
||||||
|
|
||||||
|
struct DS* ds = (struct DS*) cpu->master;
|
||||||
|
DSMemoryReset(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSProcessEvents(struct ARMCore* cpu) {
|
static void DSProcessEvents(struct ARMCore* cpu) {
|
||||||
|
@ -198,6 +205,35 @@ bool DSIsROM(struct VFile* vf) {
|
||||||
return memcmp(signature, DS_ROM_MAGIC, sizeof(signature)) == 0;
|
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) {
|
void DSGetGameCode(struct DS* ds, char* out) {
|
||||||
memset(out, 0, 8);
|
memset(out, 0, 8);
|
||||||
if (!ds->romVf) {
|
if (!ds->romVf) {
|
||||||
|
|
10
src/ds/ds.h
10
src/ds/ds.h
|
@ -11,6 +11,7 @@
|
||||||
#include "arm/arm.h"
|
#include "arm/arm.h"
|
||||||
#include "core/log.h"
|
#include "core/log.h"
|
||||||
|
|
||||||
|
#include "ds/memory.h"
|
||||||
#include "ds/video.h"
|
#include "ds/video.h"
|
||||||
|
|
||||||
extern const uint32_t DS_ARM946ES_FREQUENCY;
|
extern const uint32_t DS_ARM946ES_FREQUENCY;
|
||||||
|
@ -54,6 +55,7 @@ struct DS {
|
||||||
|
|
||||||
struct ARMCore* arm7;
|
struct ARMCore* arm7;
|
||||||
struct ARMCore* arm9;
|
struct ARMCore* arm9;
|
||||||
|
struct DSMemory memory;
|
||||||
struct DSVideo video;
|
struct DSVideo video;
|
||||||
|
|
||||||
struct mCoreSync* sync;
|
struct mCoreSync* sync;
|
||||||
|
@ -63,13 +65,15 @@ struct DS {
|
||||||
int springIRQ7;
|
int springIRQ7;
|
||||||
int springIRQ9;
|
int springIRQ9;
|
||||||
|
|
||||||
uint32_t biosChecksum;
|
uint32_t bios7Checksum;
|
||||||
|
uint32_t bios9Checksum;
|
||||||
int* keySource;
|
int* keySource;
|
||||||
struct mRTCSource* rtcSource;
|
struct mRTCSource* rtcSource;
|
||||||
struct mRumble* rumble;
|
struct mRumble* rumble;
|
||||||
|
|
||||||
uint32_t romCrc32;
|
|
||||||
struct VFile* romVf;
|
struct VFile* romVf;
|
||||||
|
struct VFile* bios7Vf;
|
||||||
|
struct VFile* bios9Vf;
|
||||||
|
|
||||||
struct mKeyCallback* keyCallback;
|
struct mKeyCallback* keyCallback;
|
||||||
};
|
};
|
||||||
|
@ -121,6 +125,8 @@ bool DSLoadROM(struct DS* ds, struct VFile* vf);
|
||||||
void DSUnloadROM(struct DS* ds);
|
void DSUnloadROM(struct DS* ds);
|
||||||
void DSApplyPatch(struct DS* ds, struct Patch* patch);
|
void DSApplyPatch(struct DS* ds, struct Patch* patch);
|
||||||
|
|
||||||
|
bool DSLoadBIOS(struct DS* ds, struct VFile* vf);
|
||||||
|
|
||||||
bool DSIsROM(struct VFile* vf);
|
bool DSIsROM(struct VFile* vf);
|
||||||
void DSGetGameCode(struct DS* ds, char* out);
|
void DSGetGameCode(struct DS* ds, char* out);
|
||||||
void DSGetGameTitle(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