all repos — mgba @ 66d1c0c55cba4265786591a1f6bf399034af8622

mGBA Game Boy Advance Emulator

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

  1#include "gba.h"
  2
  3#include "gba-gpio.h"
  4#include "gba-sensors.h"
  5
  6#include <time.h>
  7
  8static void _readPins(struct GBACartridgeGPIO* gpio);
  9static void _outputPins(struct GBACartridgeGPIO* gpio, unsigned pins);
 10
 11static void _rtcReadPins(struct GBACartridgeGPIO* gpio);
 12static unsigned _rtcOutput(struct GBACartridgeGPIO* gpio);
 13static void _rtcProcessByte(struct GBACartridgeGPIO* gpio);
 14static void _rtcUpdateClock(struct GBACartridgeGPIO* gpio);
 15static unsigned _rtcBCD(unsigned value);
 16
 17static void _gyroReadPins(struct GBACartridgeGPIO* gpio);
 18
 19static void _rumbleReadPins(struct GBACartridgeGPIO* gpio);
 20
 21static const int RTC_BYTES[8] = {
 22	0, // Force reset
 23	0, // Empty
 24	7, // Date/Time
 25	0, // Force IRQ
 26	1, // Control register
 27	0, // Empty
 28	3, // Time
 29	0 // Empty
 30};
 31
 32void GBAGPIOInit(struct GBACartridgeGPIO* gpio, uint16_t* base) {
 33	gpio->gpioDevices = GPIO_NONE;
 34	gpio->direction = GPIO_WRITE_ONLY;
 35	gpio->gpioBase = base;
 36	gpio->pinState = 0;
 37	gpio->direction = 0;
 38}
 39
 40void GBAGPIOWrite(struct GBACartridgeGPIO* gpio, uint32_t address, uint16_t value) {
 41	switch (address) {
 42	case GPIO_REG_DATA:
 43		gpio->pinState = value;
 44		_readPins(gpio);
 45		break;
 46	case GPIO_REG_DIRECTION:
 47		gpio->direction = value;
 48		break;
 49	case GPIO_REG_CONTROL:
 50		gpio->readWrite = value;
 51		break;
 52	default:
 53		GBALog(gpio->p, GBA_LOG_WARN, "Invalid GPIO address");
 54	}
 55
 56	if (gpio->readWrite) {
 57		uint16_t old = gpio->gpioBase[0];
 58		old &= ~gpio->direction;
 59		gpio->gpioBase[0] = old | (value & gpio->direction);
 60	}
 61}
 62
 63void GBAGPIOInitRTC(struct GBACartridgeGPIO* gpio) {
 64	gpio->gpioDevices |= GPIO_RTC;
 65	gpio->rtc.bytesRemaining = 0;
 66
 67	gpio->rtc.transferStep = 0;
 68
 69	gpio->rtc.bitsRead = 0;
 70	gpio->rtc.bits = 0;
 71	gpio->rtc.commandActive = 0;
 72	gpio->rtc.command.packed = 0;
 73	gpio->rtc.control.packed = 0x40;
 74	memset(gpio->rtc.time, 0, sizeof(gpio->rtc.time));
 75}
 76
 77void _readPins(struct GBACartridgeGPIO* gpio) {
 78	if (gpio->gpioDevices & GPIO_RTC) {
 79		_rtcReadPins(gpio);
 80	}
 81
 82	if (gpio->gpioDevices & GPIO_GYRO) {
 83		_gyroReadPins(gpio);
 84	}
 85
 86	if (gpio->gpioDevices & GPIO_RUMBLE) {
 87		_rumbleReadPins(gpio);
 88	}
 89}
 90
 91void _outputPins(struct GBACartridgeGPIO* gpio, unsigned pins) {
 92	if (gpio->readWrite) {
 93		uint16_t old = gpio->gpioBase[0];
 94		old &= gpio->direction;
 95		gpio->gpioBase[0] = old | (pins & ~gpio->direction & 0xF);
 96	}
 97}
 98
 99// == RTC
100
101void _rtcReadPins(struct GBACartridgeGPIO* gpio) {
102	// Transfer sequence:
103	// P: 0 | 1 |  2 | 3
104	// == Initiate
105	// > HI | - | LO | -
106	// > HI | - | HI | -
107	// == Transfer bit (x8)
108	// > LO | x | HI | -
109	// > HI | - | HI | -
110	// < ?? | x | ?? | -
111	// == Terminate
112	// >  - | - | LO | -
113	switch (gpio->rtc.transferStep) {
114	case 0:
115		if ((gpio->pinState & 5) == 1) {
116			gpio->rtc.transferStep = 1;
117		}
118		break;
119	case 1:
120		if ((gpio->pinState & 5) == 5) {
121			gpio->rtc.transferStep = 2;
122		}
123		break;
124	case 2:
125		if (!gpio->p0) {
126			gpio->rtc.bits &= ~(1 << gpio->rtc.bitsRead);
127			gpio->rtc.bits |= gpio->p1 << gpio->rtc.bitsRead;
128		} else {
129			if (gpio->p2) {
130				// GPIO direction should always != reading
131				if (gpio->dir1) {
132					if (gpio->rtc.command.reading) {
133						GBALog(gpio->p, GBA_LOG_GAME_ERROR, "Attempting to write to RTC while in read mode");
134					}
135					++gpio->rtc.bitsRead;
136					if (gpio->rtc.bitsRead == 8) {
137						_rtcProcessByte(gpio);
138					}
139				} else {
140					_outputPins(gpio, 5 | (_rtcOutput(gpio) << 1));
141					++gpio->rtc.bitsRead;
142					if (gpio->rtc.bitsRead == 8) {
143						--gpio->rtc.bytesRemaining;
144						if (gpio->rtc.bytesRemaining <= 0) {
145							gpio->rtc.commandActive = 0;
146							gpio->rtc.command.reading = 0;
147						}
148						gpio->rtc.bitsRead = 0;
149					}
150				}
151			} else {
152				gpio->rtc.bitsRead = 0;
153				gpio->rtc.bytesRemaining = 0;
154				gpio->rtc.commandActive = 0;
155				gpio->rtc.command.reading = 0;
156				gpio->rtc.transferStep = 0;
157			}
158		}
159		break;
160	}
161}
162
163void _rtcProcessByte(struct GBACartridgeGPIO* gpio) {
164	--gpio->rtc.bytesRemaining;
165	if (!gpio->rtc.commandActive) {
166		union RTCCommandData command;
167		command.packed = gpio->rtc.bits;
168		if (command.magic == 0x06) {
169			gpio->rtc.command = command;
170
171			gpio->rtc.bytesRemaining = RTC_BYTES[gpio->rtc.command.command];
172			gpio->rtc.commandActive = gpio->rtc.bytesRemaining > 0;
173			switch (command.command) {
174			case RTC_RESET:
175				gpio->rtc.control.packed = 0;
176				break;
177			case RTC_DATETIME:
178			case RTC_TIME:
179				_rtcUpdateClock(gpio);
180				break;
181			case RTC_FORCE_IRQ:
182			case RTC_CONTROL:
183				break;
184			}
185		} else {
186			GBALog(gpio->p, GBA_LOG_WARN, "Invalid RTC command byte: %02X", gpio->rtc.bits);
187		}
188	} else {
189		switch (gpio->rtc.command.command) {
190		case RTC_CONTROL:
191			gpio->rtc.control.packed = gpio->rtc.bits;
192			break;
193		case RTC_FORCE_IRQ:
194			GBALog(gpio->p, GBA_LOG_STUB, "Unimplemented RTC command %u", gpio->rtc.command.command);
195			break;
196		case RTC_RESET:
197		case RTC_DATETIME:
198		case RTC_TIME:
199			break;
200		}
201	}
202
203	gpio->rtc.bits = 0;
204	gpio->rtc.bitsRead = 0;
205	if (!gpio->rtc.bytesRemaining) {
206		gpio->rtc.commandActive = 0;
207		gpio->rtc.command.reading = 0;
208	}
209}
210
211unsigned _rtcOutput(struct GBACartridgeGPIO* gpio) {
212	uint8_t outputByte = 0;
213	switch (gpio->rtc.command.command) {
214	case RTC_CONTROL:
215		outputByte = gpio->rtc.control.packed;
216		break;
217	case RTC_DATETIME:
218	case RTC_TIME:
219		outputByte = gpio->rtc.time[7 - gpio->rtc.bytesRemaining];
220		break;
221	case RTC_FORCE_IRQ:
222	case RTC_RESET:
223		break;
224	}
225	unsigned output = (outputByte >> gpio->rtc.bitsRead) & 1;
226	return output;
227}
228
229void _rtcUpdateClock(struct GBACartridgeGPIO* gpio) {
230	time_t t = time(0);
231	struct tm date;
232#ifdef _WIN32
233	date = *localtime(&t);
234#else
235	localtime_r(&t, &date);
236#endif
237	gpio->rtc.time[0] = _rtcBCD(date.tm_year - 100);
238	gpio->rtc.time[1] = _rtcBCD(date.tm_mon + 1);
239	gpio->rtc.time[2] = _rtcBCD(date.tm_mday);
240	gpio->rtc.time[3] = _rtcBCD(date.tm_wday);
241	if (gpio->rtc.control.hour24) {
242		gpio->rtc.time[4] = _rtcBCD(date.tm_hour);
243	} else {
244		gpio->rtc.time[4] = _rtcBCD(date.tm_hour % 12);
245	}
246	gpio->rtc.time[5] = _rtcBCD(date.tm_min);
247	gpio->rtc.time[6] = _rtcBCD(date.tm_sec);
248}
249
250unsigned _rtcBCD(unsigned value) {
251	int counter = value % 10;
252	value /= 10;
253	counter += (value % 10) << 4;
254	return counter;
255}
256
257// == Gyro
258
259void GBAGPIOInitGyro(struct GBACartridgeGPIO* gpio) {
260	gpio->gpioDevices |= GPIO_GYRO;
261	gpio->gyroSample = 0;
262	gpio->gyroEdge = 0;
263}
264
265void _gyroReadPins(struct GBACartridgeGPIO* gpio) {
266	struct GBARotationSource* gyro = gpio->p->rotationSource;
267	if (!gyro) {
268		return;
269	}
270
271	if (gpio->p0) {
272		if (gyro->sample) {
273			gyro->sample(gyro);
274		}
275		int32_t sample = gyro->readGyroZ(gyro);
276
277		// Normalize to ~12 bits, focused on 0x6C0
278		gpio->gyroSample = (sample >> 21) + 0x6C0; // Crop off an extra bit so that we can't go negative
279	}
280
281	if (gpio->gyroEdge && !gpio->p1) {
282		// Write bit on falling edge
283		unsigned bit = gpio->gyroSample >> 15;
284		gpio->gyroSample <<= 1;
285		_outputPins(gpio, bit << 2);
286	}
287
288	gpio->gyroEdge = gpio->p1;
289}
290
291// == Rumble
292
293void GBAGPIOInitRumble(struct GBACartridgeGPIO* gpio) {
294	gpio->gpioDevices |= GPIO_RUMBLE;
295}
296
297void _rumbleReadPins(struct GBACartridgeGPIO* gpio) {
298	struct GBARumble* rumble = gpio->p->rumble;
299	if (!rumble) {
300		return;
301	}
302
303	rumble->setRumble(rumble, gpio->p3);
304}