all repos — mgba @ ceea51b55ea2f112c49b4ad22e6d70b08ad430e7

mGBA Game Boy Advance Emulator

src/gb/sio.c (view raw)

 1/* Copyright (c) 2013-2016 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 "sio.h"
 7
 8#include "gb/gb.h"
 9#include "gb/io.h"
10#include "gb/serialize.h"
11
12mLOG_DEFINE_CATEGORY(GB_SIO, "GB Serial I/O");
13
14const int GBSIOCyclesPerTransfer[2] = {
15	512,
16	16
17};
18
19void _GBSIOProcessEvents(struct mTiming* timing, void* context, uint32_t cyclesLate);
20
21void GBSIOInit(struct GBSIO* sio) {
22	sio->pendingSB = 0xFF;
23	sio->event.context = sio;
24	sio->event.name = "GB SIO";
25	sio->event.callback = _GBSIOProcessEvents;
26	sio->event.priority = 0x30;
27
28	sio->driver = NULL;
29}
30
31void GBSIOReset(struct GBSIO* sio) {
32	sio->nextEvent = INT_MAX;
33	sio->remainingBits = 0;
34}
35
36void GBSIODeinit(struct GBSIO* sio) {
37	UNUSED(sio);
38	// Nothing to do yet
39}
40
41void GBSIOSetDriver(struct GBSIO* sio, struct GBSIODriver* driver) {
42	if (sio->driver) {
43		if (sio->driver->deinit) {
44			sio->driver->deinit(sio->driver);
45		}
46	}
47	if (driver) {
48		driver->p = sio;
49
50		if (driver->init) {
51			if (!driver->init(driver)) {
52				driver->deinit(driver);
53				mLOG(GB_SIO, ERROR, "Could not initialize SIO driver");
54				return;
55			}
56		}
57	}
58	sio->driver = driver;
59}
60
61void _GBSIOProcessEvents(struct mTiming* timing, void* context, uint32_t cyclesLate) {
62	UNUSED(cyclesLate);
63	struct GBSIO* sio = context;
64	--sio->remainingBits;
65	sio->p->memory.io[REG_SB] &= ~(8 >> sio->remainingBits);
66	sio->p->memory.io[REG_SB] |= sio->pendingSB & ~(8 >> sio->remainingBits);
67	if (!sio->remainingBits) {
68		sio->p->memory.io[REG_IF] |= (1 << GB_IRQ_SIO);
69		sio->p->memory.io[REG_SC] = GBRegisterSCClearEnable(sio->p->memory.io[REG_SC]);
70		sio->pendingSB = 0xFF;
71		GBUpdateIRQs(sio->p);
72	} else {
73		mTimingSchedule(timing, &sio->event, sio->period);
74	}
75}
76
77void GBSIOWriteSB(struct GBSIO* sio, uint8_t sb) {
78	if (!sio->driver) {
79		return;
80	}
81	sio->driver->writeSB(sio->driver, sb);
82}
83
84void GBSIOWriteSC(struct GBSIO* sio, uint8_t sc) {
85	sio->period = GBSIOCyclesPerTransfer[GBRegisterSCGetClockSpeed(sc)]; // TODO Shift Clock
86	if (GBRegisterSCIsEnable(sc)) {
87		mTimingDeschedule(&sio->p->timing, &sio->event);
88		mTimingSchedule(&sio->p->timing, &sio->event, sio->period);
89		sio->remainingBits = 8;
90	}
91	if (sio->driver) {
92		sio->driver->writeSC(sio->driver, sc);
93	}
94}
95