all repos — mgba @ e6c10428ce32753b1727aa2afd10884d451d41d1

mGBA Game Boy Advance Emulator

src/gba/hardware.c (view raw)

  1/* Copyright (c) 2013-2015 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 "hardware.h"
  7
  8#include "gba/serialize.h"
  9
 10#include <time.h>
 11
 12static void _readPins(struct GBACartridgeHardware* hw);
 13static void _outputPins(struct GBACartridgeHardware* hw, unsigned pins);
 14
 15static void _rtcReadPins(struct GBACartridgeHardware* hw);
 16static unsigned _rtcOutput(struct GBACartridgeHardware* hw);
 17static void _rtcProcessByte(struct GBACartridgeHardware* hw);
 18static void _rtcUpdateClock(struct GBACartridgeHardware* hw);
 19static unsigned _rtcBCD(unsigned value);
 20
 21static void _gyroReadPins(struct GBACartridgeHardware* hw);
 22
 23static void _rumbleReadPins(struct GBACartridgeHardware* hw);
 24
 25static void _lightReadPins(struct GBACartridgeHardware* hw);
 26
 27static const int RTC_BYTES[8] = {
 28	0, // Force reset
 29	0, // Empty
 30	7, // Date/Time
 31	0, // Force IRQ
 32	1, // Control register
 33	0, // Empty
 34	3, // Time
 35	0 // Empty
 36};
 37
 38void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) {
 39	hw->gpioBase = base;
 40	GBAHardwareClear(hw);
 41}
 42
 43void GBAHardwareClear(struct GBACartridgeHardware* hw) {
 44	hw->devices = HW_NONE;
 45	hw->direction = GPIO_WRITE_ONLY;
 46	hw->pinState = 0;
 47	hw->direction = 0;
 48}
 49
 50void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) {
 51	switch (address) {
 52	case GPIO_REG_DATA:
 53		hw->pinState &= ~hw->direction;
 54		hw->pinState |= value;
 55		_readPins(hw);
 56		break;
 57	case GPIO_REG_DIRECTION:
 58		hw->direction = value;
 59		break;
 60	case GPIO_REG_CONTROL:
 61		hw->readWrite = value;
 62		break;
 63	default:
 64		GBALog(hw->p, GBA_LOG_WARN, "Invalid GPIO address");
 65	}
 66	if (hw->readWrite) {
 67		uint16_t old = hw->gpioBase[0];
 68		old &= ~hw->direction;
 69		hw->gpioBase[0] = old | hw->pinState;
 70	} else {
 71		hw->gpioBase[0] = 0;
 72	}
 73}
 74
 75void GBAHardwareInitRTC(struct GBACartridgeHardware* hw) {
 76	hw->devices |= HW_RTC;
 77	hw->rtc.bytesRemaining = 0;
 78
 79	hw->rtc.transferStep = 0;
 80
 81	hw->rtc.bitsRead = 0;
 82	hw->rtc.bits = 0;
 83	hw->rtc.commandActive = 0;
 84	hw->rtc.command.packed = 0;
 85	hw->rtc.control.packed = 0x40;
 86	memset(hw->rtc.time, 0, sizeof(hw->rtc.time));
 87}
 88
 89void _readPins(struct GBACartridgeHardware* hw) {
 90	if (hw->devices & HW_RTC) {
 91		_rtcReadPins(hw);
 92	}
 93
 94	if (hw->devices & HW_GYRO) {
 95		_gyroReadPins(hw);
 96	}
 97
 98	if (hw->devices & HW_RUMBLE) {
 99		_rumbleReadPins(hw);
100	}
101
102	if (hw->devices & HW_LIGHT_SENSOR) {
103		_lightReadPins(hw);
104	}
105}
106
107void _outputPins(struct GBACartridgeHardware* hw, unsigned pins) {
108	if (hw->readWrite) {
109		uint16_t old = hw->gpioBase[0];
110		old &= hw->direction;
111		hw->pinState = old | (pins & ~hw->direction & 0xF);
112		hw->gpioBase[0] = hw->pinState;
113	}
114}
115
116// == RTC
117
118void _rtcReadPins(struct GBACartridgeHardware* hw) {
119	// Transfer sequence:
120	// P: 0 | 1 |  2 | 3
121	// == Initiate
122	// > HI | - | LO | -
123	// > HI | - | HI | -
124	// == Transfer bit (x8)
125	// > LO | x | HI | -
126	// > HI | - | HI | -
127	// < ?? | x | ?? | -
128	// == Terminate
129	// >  - | - | LO | -
130	switch (hw->rtc.transferStep) {
131	case 0:
132		if ((hw->pinState & 5) == 1) {
133			hw->rtc.transferStep = 1;
134		}
135		break;
136	case 1:
137		if ((hw->pinState & 5) == 5) {
138			hw->rtc.transferStep = 2;
139		}
140		break;
141	case 2:
142		if (!hw->p0) {
143			hw->rtc.bits &= ~(1 << hw->rtc.bitsRead);
144			hw->rtc.bits |= hw->p1 << hw->rtc.bitsRead;
145		} else {
146			if (hw->p2) {
147				// GPIO direction should always != reading
148				if (hw->dir1) {
149					if (hw->rtc.command.reading) {
150						GBALog(hw->p, GBA_LOG_GAME_ERROR, "Attempting to write to RTC while in read mode");
151					}
152					++hw->rtc.bitsRead;
153					if (hw->rtc.bitsRead == 8) {
154						_rtcProcessByte(hw);
155					}
156				} else {
157					_outputPins(hw, 5 | (_rtcOutput(hw) << 1));
158					++hw->rtc.bitsRead;
159					if (hw->rtc.bitsRead == 8) {
160						--hw->rtc.bytesRemaining;
161						if (hw->rtc.bytesRemaining <= 0) {
162							hw->rtc.commandActive = 0;
163							hw->rtc.command.reading = 0;
164						}
165						hw->rtc.bitsRead = 0;
166					}
167				}
168			} else {
169				hw->rtc.bitsRead = 0;
170				hw->rtc.bytesRemaining = 0;
171				hw->rtc.commandActive = 0;
172				hw->rtc.command.reading = 0;
173				hw->rtc.transferStep = 0;
174			}
175		}
176		break;
177	}
178}
179
180void _rtcProcessByte(struct GBACartridgeHardware* hw) {
181	--hw->rtc.bytesRemaining;
182	if (!hw->rtc.commandActive) {
183		union RTCCommandData command;
184		command.packed = hw->rtc.bits;
185		if (command.magic == 0x06) {
186			hw->rtc.command = command;
187
188			hw->rtc.bytesRemaining = RTC_BYTES[hw->rtc.command.command];
189			hw->rtc.commandActive = hw->rtc.bytesRemaining > 0;
190			switch (command.command) {
191			case RTC_RESET:
192				hw->rtc.control.packed = 0;
193				break;
194			case RTC_DATETIME:
195			case RTC_TIME:
196				_rtcUpdateClock(hw);
197				break;
198			case RTC_FORCE_IRQ:
199			case RTC_CONTROL:
200				break;
201			}
202		} else {
203			GBALog(hw->p, GBA_LOG_WARN, "Invalid RTC command byte: %02X", hw->rtc.bits);
204		}
205	} else {
206		switch (hw->rtc.command.command) {
207		case RTC_CONTROL:
208			hw->rtc.control.packed = hw->rtc.bits;
209			break;
210		case RTC_FORCE_IRQ:
211			GBALog(hw->p, GBA_LOG_STUB, "Unimplemented RTC command %u", hw->rtc.command.command);
212			break;
213		case RTC_RESET:
214		case RTC_DATETIME:
215		case RTC_TIME:
216			break;
217		}
218	}
219
220	hw->rtc.bits = 0;
221	hw->rtc.bitsRead = 0;
222	if (!hw->rtc.bytesRemaining) {
223		hw->rtc.commandActive = 0;
224		hw->rtc.command.reading = 0;
225	}
226}
227
228unsigned _rtcOutput(struct GBACartridgeHardware* hw) {
229	uint8_t outputByte = 0;
230	switch (hw->rtc.command.command) {
231	case RTC_CONTROL:
232		outputByte = hw->rtc.control.packed;
233		break;
234	case RTC_DATETIME:
235	case RTC_TIME:
236		outputByte = hw->rtc.time[7 - hw->rtc.bytesRemaining];
237		break;
238	case RTC_FORCE_IRQ:
239	case RTC_RESET:
240		break;
241	}
242	unsigned output = (outputByte >> hw->rtc.bitsRead) & 1;
243	return output;
244}
245
246void _rtcUpdateClock(struct GBACartridgeHardware* hw) {
247	time_t t;
248	struct GBARTCSource* rtc = hw->p->rtcSource;
249	if (rtc) {
250		rtc->sample(rtc);
251		t = rtc->unixTime(rtc);
252	} else {
253		t = time(0);
254	}
255	struct tm date;
256#ifdef _WIN32
257	date = *localtime(&t);
258#else
259	localtime_r(&t, &date);
260#endif
261	hw->rtc.time[0] = _rtcBCD(date.tm_year - 100);
262	hw->rtc.time[1] = _rtcBCD(date.tm_mon + 1);
263	hw->rtc.time[2] = _rtcBCD(date.tm_mday);
264	hw->rtc.time[3] = _rtcBCD(date.tm_wday);
265	if (hw->rtc.control.hour24) {
266		hw->rtc.time[4] = _rtcBCD(date.tm_hour);
267	} else {
268		hw->rtc.time[4] = _rtcBCD(date.tm_hour % 12);
269	}
270	hw->rtc.time[5] = _rtcBCD(date.tm_min);
271	hw->rtc.time[6] = _rtcBCD(date.tm_sec);
272}
273
274unsigned _rtcBCD(unsigned value) {
275	int counter = value % 10;
276	value /= 10;
277	counter += (value % 10) << 4;
278	return counter;
279}
280
281// == Gyro
282
283void GBAHardwareInitGyro(struct GBACartridgeHardware* hw) {
284	hw->devices |= HW_GYRO;
285	hw->gyroSample = 0;
286	hw->gyroEdge = 0;
287}
288
289void _gyroReadPins(struct GBACartridgeHardware* hw) {
290	struct GBARotationSource* gyro = hw->p->rotationSource;
291	if (!gyro) {
292		return;
293	}
294
295	if (hw->p0) {
296		if (gyro->sample) {
297			gyro->sample(gyro);
298		}
299		int32_t sample = gyro->readGyroZ(gyro);
300
301		// Normalize to ~12 bits, focused on 0x6C0
302		hw->gyroSample = (sample >> 21) + 0x6C0; // Crop off an extra bit so that we can't go negative
303	}
304
305	if (hw->gyroEdge && !hw->p1) {
306		// Write bit on falling edge
307		unsigned bit = hw->gyroSample >> 15;
308		hw->gyroSample <<= 1;
309		_outputPins(hw, bit << 2);
310	}
311
312	hw->gyroEdge = hw->p1;
313}
314
315// == Rumble
316
317void GBAHardwareInitRumble(struct GBACartridgeHardware* hw) {
318	hw->devices |= HW_RUMBLE;
319}
320
321void _rumbleReadPins(struct GBACartridgeHardware* hw) {
322	struct GBARumble* rumble = hw->p->rumble;
323	if (!rumble) {
324		return;
325	}
326
327	rumble->setRumble(rumble, hw->p3);
328}
329
330// == Light sensor
331
332void GBAHardwareInitLight(struct GBACartridgeHardware* hw) {
333	hw->devices |= HW_LIGHT_SENSOR;
334	hw->lightCounter = 0;
335	hw->lightEdge = false;
336	hw->lightSample = 0xFF;
337}
338
339void _lightReadPins(struct GBACartridgeHardware* hw) {
340	if (hw->p2) {
341		// Boktai chip select
342		return;
343	}
344	if (hw->p1) {
345		struct GBALuminanceSource* lux = hw->p->luminanceSource;
346		GBALog(hw->p, GBA_LOG_DEBUG, "[SOLAR] Got reset");
347		hw->lightCounter = 0;
348		if (lux) {
349			lux->sample(lux);
350			hw->lightSample = lux->readLuminance(lux);
351		} else {
352			hw->lightSample = 0xFF;
353		}
354	}
355	if (hw->p0 && hw->lightEdge) {
356		++hw->lightCounter;
357	}
358	hw->lightEdge = !hw->p0;
359
360	bool sendBit = hw->lightCounter >= hw->lightSample;
361	_outputPins(hw, sendBit << 3);
362	GBALog(hw->p, GBA_LOG_DEBUG, "[SOLAR] Output %u with pins %u", hw->lightCounter, hw->pinState);
363}
364
365// == Tilt
366
367void GBAHardwareInitTilt(struct GBACartridgeHardware* hw) {
368	hw->devices |= HW_TILT;
369	hw->tiltX = 0xFFF;
370	hw->tiltY = 0xFFF;
371	hw->tiltState = 0;
372}
373
374void GBAHardwareTiltWrite(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value) {
375	switch (address) {
376	case 0x8000:
377		if (value == 0x55) {
378			hw->tiltState = 1;
379		} else {
380			GBALog(hw->p, GBA_LOG_GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
381		}
382		break;
383	case 0x8100:
384		if (value == 0xAA && hw->tiltState == 1) {
385			hw->tiltState = 0;
386			struct GBARotationSource* rotationSource = hw->p->rotationSource;
387			if (!rotationSource || !rotationSource->readTiltX || !rotationSource->readTiltY) {
388				return;
389			}
390			if (rotationSource->sample) {
391				rotationSource->sample(rotationSource);
392			}
393			int32_t x = rotationSource->readTiltX(rotationSource);
394			int32_t y = rotationSource->readTiltY(rotationSource);
395			// Normalize to ~12 bits, focused on 0x3A0
396			hw->tiltX = (x >> 21) + 0x3A0; // Crop off an extra bit so that we can't go negative
397			hw->tiltY = (y >> 21) + 0x3A0;
398		} else {
399			GBALog(hw->p, GBA_LOG_GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
400		}
401		break;
402	default:
403		GBALog(hw->p, GBA_LOG_GAME_ERROR, "Invalid tilt sensor write to %04x: %02x", address, value);
404		break;
405	}
406}
407
408uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* hw, uint32_t address) {
409	switch (address) {
410	case 0x8200:
411		return hw->tiltX & 0xFF;
412	case 0x8300:
413		return ((hw->tiltX >> 8) & 0xF) | 0x80;
414	case 0x8400:
415		return hw->tiltY & 0xFF;
416	case 0x8500:
417		return (hw->tiltY >> 8) & 0xF;
418	default:
419		GBALog(hw->p, GBA_LOG_GAME_ERROR, "Invalid tilt sensor read from %04x", address);
420		break;
421	}
422	return 0xFF;
423}
424
425// == Serialization
426
427void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
428	state->hw.readWrite = hw->readWrite;
429	state->hw.pinState = hw->pinState;
430	state->hw.pinDirection = hw->direction;
431	state->hw.devices = hw->devices;
432	state->hw.rtc = hw->rtc;
433	state->hw.gyroSample = hw->gyroSample;
434	state->hw.gyroEdge = hw->gyroEdge;
435	state->hw.tiltSampleX = hw->tiltX;
436	state->hw.tiltSampleY = hw->tiltY;
437	state->hw.tiltState = hw->tiltState;
438	state->hw.lightCounter = hw->lightCounter;
439	state->hw.lightSample = hw->lightSample;
440	state->hw.lightEdge = hw->lightEdge;
441}
442
443void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) {
444	hw->readWrite = state->hw.readWrite;
445	hw->pinState = state->hw.pinState;
446	hw->direction = state->hw.pinDirection;
447	// TODO: Deterministic RTC
448	hw->rtc = state->hw.rtc;
449	hw->gyroSample = state->hw.gyroSample;
450	hw->gyroEdge = state->hw.gyroEdge;
451	hw->tiltX = state->hw.tiltSampleX;
452	hw->tiltY = state->hw.tiltSampleY;
453	hw->tiltState = state->hw.tiltState;
454	hw->lightCounter = state->hw.lightCounter;
455	hw->lightSample = state->hw.lightSample;
456	hw->lightEdge = state->hw.lightEdge;
457}