all repos — mgba @ 4fd170ac38a9c312f3dd1d0dd912d2c761f60fdb

mGBA Game Boy Advance Emulator

src/ds/ipc.c (view raw)

 1/* Copyright (c) 2013-2017 Jeffrey Pfau
 2 *
 3 * This Source Code Form is subject to the terms of the Mozilla Public
 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 6#include <mgba/internal/ds/ipc.h>
 7
 8#include <mgba/internal/ds/ds.h>
 9#include <mgba/internal/ds/io.h>
10
11mLOG_DEFINE_CATEGORY(DS_IPC, "DS IPC", "ds.ipc");
12
13static void _parseIPC(struct DS* ds, uint32_t value) {
14	switch (value & 0x1F) {
15	case 0x0B: // Savedata
16		if (value & ~0x3F && ds->memory.slot1.savedataType == DS_SAVEDATA_AUTODETECT) {
17			DSSlot1ConfigureSPI(ds, value >> 6);
18		}
19		break;
20	}
21}
22
23void DSIPCWriteSYNC(struct ARMCore* remoteCpu, uint16_t* remoteIo, int16_t value) {
24	remoteIo[DS_REG_IPCSYNC >> 1] &= 0xFFF0;
25	remoteIo[DS_REG_IPCSYNC >> 1] |= (value >> 8) & 0x0F;
26	if (value & 0x2000 && remoteIo[DS_REG_IPCSYNC >> 1] & 0x4000) {
27		mLOG(DS_IPC, STUB, "Unimplemented IRQ");
28		UNUSED(remoteCpu);
29	}
30}
31
32int16_t DSIPCWriteFIFOCNT(struct DSCommon* dscore, int16_t value) {
33	value &= 0xC40C;
34	int16_t oldValue = dscore->memory.io[DS_REG_IPCFIFOCNT >> 1] & 0x4303;
35	int16_t newValue = value | oldValue;
36	// TODO: Does Enable set enabled on both ends?
37	if (DSIPCFIFOCNTIsError(value)) {
38		newValue = DSIPCFIFOCNTClearError(newValue);
39	}
40	if (DSIPCFIFOCNTIsSendClear(newValue)) {
41		CircleBufferClear(&dscore->ipc->fifo);
42		dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTFillRecvEmpty(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1]);
43		newValue = DSIPCFIFOCNTFillSendEmpty(newValue);
44		newValue = DSIPCFIFOCNTClearSendClear(newValue);
45	}
46	return newValue;
47}
48
49void DSIPCWriteFIFO(struct DSCommon* dscore, int32_t value) {
50	if (!DSIPCFIFOCNTIsEnable(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1])) {
51		return;
52	}
53	mLOG(DS_IPC, DEBUG, "Written from ARM%c: %08X", (dscore == &dscore->p->ds7) ? '7' : '9', value);
54	if (!dscore->p->isHomebrew && dscore == &dscore->p->ds9) {
55		_parseIPC(dscore->p, value);
56	}
57	CircleBufferWrite32(&dscore->ipc->fifo, value);
58	size_t fullness = CircleBufferSize(&dscore->ipc->fifo);
59	if (fullness == 4) {
60		dscore->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTClearSendEmpty(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1]);
61		dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTClearRecvEmpty(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1]);
62		if (DSIPCFIFOCNTIsRecvIRQ(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1])) {
63			// TODO: Adaptive time slicing?
64			DSRaiseIRQ(dscore->ipc->cpu, dscore->ipc->memory.io, DS_IRQ_IPC_NOT_EMPTY);
65		}
66	} else if (fullness == 64) {
67		dscore->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTFillSendFull(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1]);
68		dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTFillRecvFull(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1]);
69	}
70}
71
72int32_t DSIPCReadFIFO(struct DSCommon* dscore) {
73	if (!DSIPCFIFOCNTIsEnable(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1])) {
74		return 0;
75	}
76	int32_t value = ((int32_t*) dscore->ipc->memory.io)[DS_REG_IPCFIFOSEND_LO >> 2]; // TODO: actual last value
77	CircleBufferRead32(&dscore->fifo, &value);
78	mLOG(DS_IPC, DEBUG, "Read from ARM%c: %08X", (dscore == &dscore->p->ds7) ? '7' : '9', value);
79	size_t fullness = CircleBufferSize(&dscore->fifo);
80	dscore->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTClearRecvFull(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1]);
81	dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTClearSendFull(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1]);
82	if (fullness == 0) {
83		dscore->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTFillRecvEmpty(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1]);
84		dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1] = DSIPCFIFOCNTFillSendEmpty(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1]);
85		if (DSIPCFIFOCNTIsSendIRQ(dscore->ipc->memory.io[DS_REG_IPCFIFOCNT >> 1])) {
86			// TODO: Adaptive time slicing?
87			DSRaiseIRQ(dscore->ipc->cpu, dscore->ipc->memory.io, DS_IRQ_IPC_NOT_EMPTY);
88		}
89	}
90	return value;
91}