all repos — mgba @ f25821524d79469e3589ab23340d7e6b4ae6a27f

mGBA Game Boy Advance Emulator

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

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