all repos — mgba @ 527fbf0fc5bbe2c8f82d06e38cfabd4b0b8fd6cb

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