all repos — mgba @ eb5580f719aac6d7f08186bf2a079c446e05c92f

mGBA Game Boy Advance Emulator

src/gba/gba-sio.c (view raw)

  1#include "gba-sio.h"
  2
  3#include "gba-io.h"
  4
  5#include <limits.h>
  6
  7static struct GBASIODriver* _lookupDriver(struct GBASIO* sio, enum GBASIOMode mode) {
  8	switch (mode) {
  9	case SIO_NORMAL_8:
 10	case SIO_NORMAL_32:
 11		return sio->drivers.normal;
 12	case SIO_MULTI:
 13		return sio->drivers.multiplayer;
 14	case SIO_JOYBUS:
 15		return sio->drivers.joybus;
 16	default:
 17		return 0;
 18	}
 19}
 20
 21static void _switchMode(struct GBASIO* sio) {
 22	int mode = ((sio->rcnt >> 14) & 0xC) | ((sio->siocnt >> 12) & 0x3);
 23	enum GBASIOMode oldMode = sio->mode;
 24	if (mode < 8) {
 25		sio->mode = (enum GBASIOMode) (mode & 0x3);
 26	} else {
 27		sio->mode = (enum GBASIOMode) (mode & 0xC);
 28	}
 29	if (oldMode != mode) {
 30		if (sio->activeDriver && sio->activeDriver->unload) {
 31			sio->activeDriver->unload(sio->activeDriver);
 32		}
 33		sio->activeDriver = _lookupDriver(sio, mode);
 34		if (sio->activeDriver && sio->activeDriver->load) {
 35			sio->activeDriver->load(sio->activeDriver);
 36		}
 37	}
 38}
 39
 40void GBASIOInit(struct GBASIO* sio) {
 41	sio->rcnt = RCNT_INITIAL;
 42	sio->siocnt = 0;
 43	_switchMode(sio);
 44}
 45
 46void GBASIODeinit(struct GBASIO* sio) {
 47	if (sio->drivers.multiplayer && sio->drivers.multiplayer->deinit) {
 48		sio->drivers.multiplayer->deinit(sio->drivers.multiplayer);
 49	}
 50	if (sio->drivers.joybus && sio->drivers.joybus->deinit) {
 51		sio->drivers.joybus->deinit(sio->drivers.joybus);
 52	}
 53}
 54
 55void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) {
 56	if (drivers->normal) {
 57		GBASIOSetDriver(sio, drivers->normal, SIO_NORMAL_8);
 58	}
 59	if (drivers->multiplayer) {
 60		GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI);
 61	}
 62	if (drivers->joybus) {
 63		GBASIOSetDriver(sio, drivers->multiplayer, SIO_JOYBUS);
 64	}
 65}
 66
 67void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode) {
 68	struct GBASIODriver** driverLoc;
 69	switch (mode) {
 70	case SIO_NORMAL_8:
 71	case SIO_NORMAL_32:
 72		driverLoc = &sio->drivers.normal;
 73		break;
 74	case SIO_MULTI:
 75		driverLoc = &sio->drivers.multiplayer;
 76		break;
 77	case SIO_JOYBUS:
 78		driverLoc = &sio->drivers.joybus;
 79		break;
 80	default:
 81		GBALog(sio->p, GBA_LOG_ERROR, "Setting an unsupported SIO driver: %x", mode);
 82		return;
 83	}
 84	if (*driverLoc) {
 85		if ((*driverLoc)->unload) {
 86			(*driverLoc)->unload(*driverLoc);
 87		}
 88		if ((*driverLoc)->deinit) {
 89			(*driverLoc)->deinit(*driverLoc);
 90		}
 91	}
 92	if (driver) {
 93		driver->p = sio;
 94
 95		if (driver->init) {
 96			if (!driver->init(driver)) {
 97				driver->deinit(driver);
 98				GBALog(sio->p, GBA_LOG_ERROR, "Could not initialize SIO driver");
 99				return;
100			}
101		}
102		if (sio->mode == mode) {
103			sio->activeDriver = driver;
104			if (driver->load) {
105				driver->load(driver);
106			}
107		}
108	}
109	*driverLoc = driver;
110}
111
112void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) {
113	sio->rcnt = value;
114	_switchMode(sio);
115	if (sio->activeDriver && sio->activeDriver->writeRegister) {
116		sio->activeDriver->writeRegister(sio->activeDriver, REG_RCNT, value);
117	}
118}
119
120void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
121	if (sio->activeDriver && sio->activeDriver->writeRegister) {
122		value = sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOCNT, value);
123	}
124	sio->siocnt = value;
125	_switchMode(sio);
126}
127
128void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value) {
129	if (sio->activeDriver && sio->activeDriver->writeRegister) {
130		sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOMLT_SEND, value);
131	}
132}
133
134int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles) {
135	if (sio->activeDriver && sio->activeDriver->processEvents) {
136		return sio->activeDriver->processEvents(sio->activeDriver, cycles);
137	}
138	return INT_MAX;
139}