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 GBSIOSetDriver(sio, sio->driver);
35}
36
37void GBSIODeinit(struct GBSIO* sio) {
38 UNUSED(sio);
39 // Nothing to do yet
40}
41
42void GBSIOSetDriver(struct GBSIO* sio, struct GBSIODriver* driver) {
43 if (sio->driver) {
44 if (sio->driver->deinit) {
45 sio->driver->deinit(sio->driver);
46 }
47 }
48 if (driver) {
49 driver->p = sio;
50
51 if (driver->init) {
52 if (!driver->init(driver)) {
53 driver->deinit(driver);
54 mLOG(GB_SIO, ERROR, "Could not initialize SIO driver");
55 return;
56 }
57 }
58 }
59 sio->driver = driver;
60}
61
62void _GBSIOProcessEvents(struct mTiming* timing, void* context, uint32_t cyclesLate) {
63 UNUSED(cyclesLate);
64 struct GBSIO* sio = context;
65 bool doIRQ = false;
66 if (sio->remainingBits) {
67 doIRQ = true;
68 --sio->remainingBits;
69 sio->p->memory.io[REG_SB] &= ~(128 >> sio->remainingBits);
70 sio->p->memory.io[REG_SB] |= sio->pendingSB & (128 >> sio->remainingBits);
71 }
72 if (!sio->remainingBits) {
73 sio->p->memory.io[REG_SC] = GBRegisterSCClearEnable(sio->p->memory.io[REG_SC]);
74 if (doIRQ) {
75 sio->p->memory.io[REG_IF] |= (1 << GB_IRQ_SIO);
76 GBUpdateIRQs(sio->p);
77 sio->pendingSB = 0xFF;
78 }
79 } else {
80 mTimingSchedule(timing, &sio->event, sio->period);
81 }
82}
83
84void GBSIOWriteSB(struct GBSIO* sio, uint8_t sb) {
85 if (!sio->driver) {
86 return;
87 }
88 sio->driver->writeSB(sio->driver, sb);
89}
90
91void GBSIOWriteSC(struct GBSIO* sio, uint8_t sc) {
92 sio->period = GBSIOCyclesPerTransfer[GBRegisterSCGetClockSpeed(sc)]; // TODO Shift Clock
93 if (GBRegisterSCIsEnable(sc)) {
94 mTimingDeschedule(&sio->p->timing, &sio->event);
95 if (GBRegisterSCIsShiftClock(sc)) {
96 mTimingSchedule(&sio->p->timing, &sio->event, sio->period);
97 sio->remainingBits = 8;
98 }
99 }
100 if (sio->driver) {
101 sio->driver->writeSC(sio->driver, sc);
102 }
103}
104