all repos — mgba @ 0053f85922a69fade4c543e53d8ef6e90c6e0a6b

mGBA Game Boy Advance Emulator

DS: Start work on IPC
Jeffrey Pfau jeffrey@endrift.com
Tue, 03 Jan 2017 15:30:56 -0800
commit

0053f85922a69fade4c543e53d8ef6e90c6e0a6b

parent

c037dada3e13727bb41ce807fe9a6caa8fd4cf95

M include/mgba/internal/ds/ds.hinclude/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.hinclude/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.csrc/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.csrc/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]); + } +}