all repos — mgba @ bdf8f73ba57d1d4738023bde436c38e9948f37ed

mGBA Game Boy Advance Emulator

src/ds/slot1.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/slot1.h>
 7
 8#include <mgba/internal/arm/macros.h>
 9#include <mgba/internal/ds/ds.h>
10#include <mgba-util/vfs.h>
11
12mLOG_DEFINE_CATEGORY(DS_SLOT1, "DS Slot-1");
13
14static void DSSlot1StepTransfer(struct DS* ds) {
15	DSSlot1ROMCNT romcnt;
16	LOAD_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io7);
17	if (ds->memory.slot1.transferRemaining) {
18		ds->romVf->read(ds->romVf, ds->memory.slot1.readBuffer, 4);
19		// TODO: Error check
20		ds->memory.slot1.address += 4;
21		ds->memory.slot1.transferRemaining -= 4;
22		romcnt = DSSlot1ROMCNTFillWordReady(romcnt);
23	} else {
24		memset(ds->memory.slot1.readBuffer, 0, 4);
25		romcnt = DSSlot1ROMCNTClearWordReady(romcnt);
26		// TODO: IRQ
27		romcnt = DSSlot1ROMCNTClearBlockBusy(romcnt);
28	}
29	STORE_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io7);
30	STORE_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io9);
31}
32
33static void DSSlot1StartTransfer(struct DS* ds) {
34	size_t i;
35	for (i = 0; i < 8; i += 2) {
36		uint16_t bytes;
37		LOAD_16(bytes, DS_REG_ROMCMD_0 + i, ds->memory.io7);
38		ds->memory.slot1.command[i] = bytes & 0xFF;
39		ds->memory.slot1.command[i + 1] = bytes >> 8;
40	}
41	switch (ds->memory.slot1.command[0]) {
42	case 0xB7:
43		ds->memory.slot1.address = ds->memory.slot1.command[1] << 24;
44		ds->memory.slot1.address |= ds->memory.slot1.command[2] << 16;
45		ds->memory.slot1.address |= ds->memory.slot1.command[3] << 8;
46		ds->memory.slot1.address |= ds->memory.slot1.command[4];
47		if (ds->romVf) {
48			ds->romVf->seek(ds->romVf, ds->memory.slot1.address, SEEK_SET);
49		}
50		ds->memory.slot1.transferRemaining = ds->memory.slot1.transferSize;
51		DSSlot1StepTransfer(ds);
52		break;
53	case 0xB8:
54		memcpy(ds->memory.slot1.readBuffer, DS_CHIP_ID, 4);
55		ds->memory.slot1.transferRemaining = 0;
56		break;
57	default:
58		mLOG(DS_SLOT1, STUB, "Unimplemented card command: %02X%02X%02X%02X%02X%02X%02X%02X",
59		     ds->memory.slot1.command[0], ds->memory.slot1.command[1],
60		     ds->memory.slot1.command[2], ds->memory.slot1.command[3],
61		     ds->memory.slot1.command[4], ds->memory.slot1.command[5],
62		     ds->memory.slot1.command[6], ds->memory.slot1.command[7]);
63		break;
64	}
65}
66
67DSSlot1AUXSPICNT DSSlot1Configure(struct DS* ds, DSSlot1AUXSPICNT config) {
68	mLOG(DS_SLOT1, STUB, "Unimplemented SPI AUX config: %04X", config);
69	return config;
70}
71
72DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control) {
73	ds->memory.slot1.transferSize = DSSlot1ROMCNTGetBlockSize(control);
74	if (ds->memory.slot1.transferSize != 0 && ds->memory.slot1.transferSize != 7) {
75		ds->memory.slot1.transferSize = 0x100 << ds->memory.slot1.transferSize;
76	}
77	if (DSSlot1ROMCNTIsBlockBusy(control)) {
78		DSSlot1StartTransfer(ds);
79		// TODO timing
80		control = DSSlot1ROMCNTFillWordReady(control);
81	}
82	return control;
83}
84
85uint32_t DSSlot1Read(struct DS* ds) {
86	uint32_t result;
87	LOAD_32(result, 0, ds->memory.slot1.readBuffer);
88	DSSlot1StepTransfer(ds);
89	return result;
90}