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