all repos — mgba @ 90a3872552de56c4b98945df29feb9f826e9bbb3

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