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 <mgba/internal/gb/sio.h>
7
8#include <mgba/internal/gb/gb.h>
9#include <mgba/internal/gb/io.h>
10#include <mgba/internal/gb/serialize.h>
11
12mLOG_DEFINE_CATEGORY(GB_SIO, "GB Serial I/O", "gb.sio");
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 bool doIRQ = false;
65 if (sio->remainingBits) {
66 doIRQ = true;
67 --sio->remainingBits;
68 sio->p->memory.io[REG_SB] &= ~(128 >> sio->remainingBits);
69 sio->p->memory.io[REG_SB] |= sio->pendingSB & (128 >> sio->remainingBits);
70 }
71 if (!sio->remainingBits) {
72 sio->p->memory.io[REG_SC] = GBRegisterSCClearEnable(sio->p->memory.io[REG_SC]);
73 if (doIRQ) {
74 sio->p->memory.io[REG_IF] |= (1 << GB_IRQ_SIO);
75 GBUpdateIRQs(sio->p);
76 sio->pendingSB = 0xFF;
77 }
78 } else {
79 mTimingSchedule(timing, &sio->event, sio->period);
80 }
81}
82
83void GBSIOWriteSB(struct GBSIO* sio, uint8_t sb) {
84 if (!sio->driver) {
85 return;
86 }
87 sio->driver->writeSB(sio->driver, sb);
88}
89
90void GBSIOWriteSC(struct GBSIO* sio, uint8_t sc) {
91 sio->period = GBSIOCyclesPerTransfer[GBRegisterSCGetClockSpeed(sc)]; // TODO Shift Clock
92 if (GBRegisterSCIsEnable(sc)) {
93 mTimingDeschedule(&sio->p->timing, &sio->event);
94 if (GBRegisterSCIsShiftClock(sc)) {
95 mTimingSchedule(&sio->p->timing, &sio->event, sio->period);
96 sio->remainingBits = 8;
97 }
98 }
99 if (sio->driver) {
100 sio->driver->writeSC(sio->driver, sc);
101 }
102}
103