all repos — mgba @ 5499ec811317f8a6b16d738c2c3d12739bccc94f

mGBA Game Boy Advance Emulator

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