all repos — mgba @ 659b929f3e58d50762f3054ba634877e458cdb4c

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