all repos — mgba @ 3c18fe162c2c76eca80692d37083f6809bae4c8d

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