DS: Start work on IPC
Jeffrey Pfau jeffrey@endrift.com
Tue, 03 Jan 2017 15:30:56 -0800
6 files changed,
110 insertions(+),
13 deletions(-)
M
include/mgba/internal/ds/ds.h
→
include/mgba/internal/ds/ds.h
@@ -12,6 +12,7 @@ CXX_GUARD_START
#include <mgba/core/log.h> #include <mgba/core/timing.h> +#include <mgba-util/circle-buffer.h> #include <mgba/internal/ds/memory.h> #include <mgba/internal/ds/timer.h>@@ -64,6 +65,8 @@ int springIRQ;
struct DSCoreMemory memory; struct DSCommon* ipc; + + struct CircleBuffer fifo; }; struct DS {
M
include/mgba/internal/ds/io.h
→
include/mgba/internal/ds/io.h
@@ -51,9 +51,9 @@ 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_IPCFIFOCNT = 0x184, + DS_REG_IPCFIFOSEND_LO = 0x188, + DS_REG_IPCFIFOSEND_HI = 0x18A, DS_REG_IPCFIFORECV_LO = 0x100000, DS_REG_IPCFIFORECV_HI = 0x100002,
A
include/mgba/internal/ds/ipc.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2013-2017 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_IPC_H +#define DS_IPC_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +DECL_BITFIELD(DSIPCFIFOCNT, int16_t); +DECL_BIT(DSIPCFIFOCNT, SendEmpty, 0); +DECL_BIT(DSIPCFIFOCNT, SendFull, 1); +DECL_BIT(DSIPCFIFOCNT, SendIRQ, 2); +DECL_BIT(DSIPCFIFOCNT, SendClear, 3); +DECL_BIT(DSIPCFIFOCNT, RecvEmpty, 8); +DECL_BIT(DSIPCFIFOCNT, RecvFull, 9); +DECL_BIT(DSIPCFIFOCNT, RecvIRQ, 10); +DECL_BIT(DSIPCFIFOCNT, Error, 14); +DECL_BIT(DSIPCFIFOCNT, Enable, 15); + +struct ARMCore; +struct DSCommon; +void DSIPCWriteSYNC(struct ARMCore* remoteCpu, uint16_t* remoteIo, int16_t value); +int16_t DSIPCWriteFIFOCNT(struct DSCommon* dscore, int16_t value); +void DSIPCWriteFIFO(struct DSCommon* dscore, int32_t value); +int32_t DSIPCReadFIFO(struct DSCommon* dscore); + +CXX_GUARD_END + +#endif
M
src/ds/ds.c
→
src/ds/ds.c
@@ -105,6 +105,9 @@ ds->slice.callback = _slice;
ds->slice.context = ds; ds->slice.priority = UINT_MAX; + CircleBufferInit(&ds->ds7.fifo, 64); + CircleBufferInit(&ds->ds9.fifo, 64); + DS7InterruptHandlerInit(&ds->ds7.cpu->irqh); DS9InterruptHandlerInit(&ds->ds9.cpu->irqh); DSMemoryInit(ds);@@ -134,6 +137,8 @@ }
} void DSDestroy(struct DS* ds) { + CircleBufferDeinit(&ds->ds7.fifo); + CircleBufferDeinit(&ds->ds9.fifo); DSUnloadROM(ds); DSMemoryDeinit(ds); mTimingDeinit(&ds->ds7.timing);@@ -176,6 +181,7 @@ cpu->gprs[ARM_SP] = DS7_SP_BASE;
struct DS* ds = (struct DS*) cpu->master; mTimingClear(&ds->ds7.timing); + CircleBufferInit(&ds->ds7.fifo, 64); DSMemoryReset(ds); DS7IOInit(ds);@@ -208,6 +214,7 @@ cpu->gprs[ARM_SP] = DS9_SP_BASE;
struct DS* ds = (struct DS*) cpu->master; mTimingClear(&ds->ds9.timing); + CircleBufferInit(&ds->ds9.fifo, 64); DS9IOInit(ds); ds->activeCpu = cpu;
M
src/ds/io.c
→
src/ds/io.c
@@ -6,17 +6,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/ds/io.h> #include <mgba/internal/ds/ds.h> +#include <mgba/internal/ds/ipc.h> mLOG_DEFINE_CATEGORY(DS_IO, "DS I/O"); - -static void _writeIPCSync(struct ARMCore* remoteCpu, uint16_t* remoteIo, int16_t value) { - 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) {@@ -54,7 +46,10 @@
case DS_REG_IPCSYNC: value &= 0x6F00; value |= dscore->memory.io[address >> 1] & 0x000F; - _writeIPCSync(dscore->ipc->cpu, dscore->ipc->memory.io, value); + DSIPCWriteSYNC(dscore->ipc->cpu, dscore->ipc->memory.io, value); + break; + case DS_REG_IPCFIFOCNT: + value = DSIPCWriteFIFOCNT(dscore, value); break; case DS_REG_IME: DSWriteIME(dscore->cpu, dscore->memory.io, value);@@ -118,6 +113,9 @@ }
void DS7IOWrite32(struct DS* ds, uint32_t address, uint32_t value) { switch (address) { + case DS_REG_IPCFIFOSEND_LO: + DSIPCWriteFIFO(&ds->ds9, value); + break; case DS_REG_IE_LO: DSWriteIE(ds->ds7.cpu, ds->ds7.memory.io, value); break;@@ -191,6 +189,12 @@ }
void DS9IOWrite32(struct DS* ds, uint32_t address, uint32_t value) { switch (address) { + case DS_REG_IPCFIFOSEND_LO: + DSIPCWriteFIFO(&ds->ds9, value); + break; + case DS_REG_IE_LO: + DSWriteIE(ds->ds9.cpu, ds->ds9.memory.io, value); + break; default: DS9IOWrite(ds, address, value & 0xFFFF); DS9IOWrite(ds, address | 2, value >> 16);
A
src/ds/ipc.c
@@ -0,0 +1,50 @@
+/* Copyright (c) 2013-2017 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 <mgba/internal/ds/ipc.h> + +#include <mgba/internal/ds/ds.h> +#include <mgba/internal/ds/io.h> + +void DSIPCWriteSYNC(struct ARMCore* remoteCpu, uint16_t* remoteIo, int16_t value) { + 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); + } +} + +int16_t DSIPCWriteFIFOCNT(struct DSCommon* dscore, int16_t value) { + value &= 0xC40C; + int16_t oldValue = dscore->memory.io[DS_REG_IPCFIFOCNT >> 1] & 0x4303; + int16_t newValue = value | oldValue; + if (DSIPCFIFOCNTIsError(value)) { + newValue = DSIPCFIFOCNTClearError(0x8FFF); + } + if (DSIPCFIFOCNTIsSendClear(newValue)) { + CircleBufferClear(&dscore->ipc->fifo); + } + return newValue; +} + +void DSIPCWriteFIFO(struct DSCommon* dscore, int32_t value) { + if (!DSIPCFIFOCNTIsEnable(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1])) { + return; + } + CircleBufferWrite32(&dscore->ipc->fifo, value); + size_t fullness = CircleBufferSize(&dscore->ipc->fifo); + if (fullness == 4) { + dscore->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTClearSendEmpty(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1]); + dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTClearRecvEmpty(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1]); + if (DSIPCFIFOCNTIsRecvIRQ(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1])) { + // TODO: Adaptive time slicing? + DSRaiseIRQ(dscore->ipc->cpu, dscore->ipc->memory.io, DS_IRQ_IPC_NOT_EMPTY); + } + } else if (fullness == 64) { + dscore->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTFillSendFull(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1]); + dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTFillRecvFull(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1]); + } +}