all repos — mgba @ 918caf87c476a60685dffab94c3b6f615991c231

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 <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