all repos — mgba @ 3f2426ef4c90bd89c7fb6189ff63c6f844220730

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 time_t _rtcGenericCallback(struct GBARTCSource* source);
 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 = 0;
 86	hw->rtc.control = 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->pinState & 1)) {
144			hw->rtc.bits &= ~(1 << hw->rtc.bitsRead);
145			hw->rtc.bits |= ((hw->pinState & 2) >> 1) << hw->rtc.bitsRead;
146		} else {
147			if (hw->pinState & 4) {
148				// GPIO direction should always != reading
149				if (hw->direction & 2) {
150					if (RTCCommandDataIsReading(hw->rtc.command)) {
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 = RTCCommandDataClearReading(hw->rtc.command);
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 = RTCCommandDataClearReading(hw->rtc.command);
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		RTCCommandData command;
185		command = hw->rtc.bits;
186		if (RTCCommandDataGetMagic(command) == 0x06) {
187			hw->rtc.command = command;
188
189			hw->rtc.bytesRemaining = RTC_BYTES[RTCCommandDataGetCommand(command)];
190			hw->rtc.commandActive = hw->rtc.bytesRemaining > 0;
191			switch (RTCCommandDataGetCommand(command)) {
192			case RTC_RESET:
193				hw->rtc.control = 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 (RTCCommandDataGetCommand(hw->rtc.command)) {
208		case RTC_CONTROL:
209			hw->rtc.control = hw->rtc.bits;
210			break;
211		case RTC_FORCE_IRQ:
212			GBALog(hw->p, GBA_LOG_STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(hw->rtc.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 = RTCCommandDataClearReading(hw->rtc.command);
226	}
227}
228
229unsigned _rtcOutput(struct GBACartridgeHardware* hw) {
230	uint8_t outputByte = 0;
231	switch (RTCCommandDataGetCommand(hw->rtc.command)) {
232	case RTC_CONTROL:
233		outputByte = hw->rtc.control;
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		if (rtc->sample) {
252			rtc->sample(rtc);
253		}
254		t = rtc->unixTime(rtc);
255	} else {
256		t = time(0);
257	}
258	struct tm date;
259#ifdef _WIN32
260	date = *localtime(&t);
261#else
262	localtime_r(&t, &date);
263#endif
264	hw->rtc.time[0] = _rtcBCD(date.tm_year - 100);
265	hw->rtc.time[1] = _rtcBCD(date.tm_mon + 1);
266	hw->rtc.time[2] = _rtcBCD(date.tm_mday);
267	hw->rtc.time[3] = _rtcBCD(date.tm_wday);
268	if (RTCControlIsHour24(hw->rtc.control)) {
269		hw->rtc.time[4] = _rtcBCD(date.tm_hour);
270	} else {
271		hw->rtc.time[4] = _rtcBCD(date.tm_hour % 12);
272	}
273	hw->rtc.time[5] = _rtcBCD(date.tm_min);
274	hw->rtc.time[6] = _rtcBCD(date.tm_sec);
275}
276
277unsigned _rtcBCD(unsigned value) {
278	int counter = value % 10;
279	value /= 10;
280	counter += (value % 10) << 4;
281	return counter;
282}
283
284time_t _rtcGenericCallback(struct GBARTCSource* source) {
285	struct GBARTCGenericSource* rtc = (struct GBARTCGenericSource*) source;
286	switch (rtc->override) {
287	case RTC_NO_OVERRIDE:
288	default:
289		return time(0);
290	case RTC_FIXED:
291		return rtc->value;
292	case RTC_FAKE_EPOCH:
293		return rtc->value + rtc->p->video.frameCounter * (int64_t) VIDEO_TOTAL_LENGTH / GBA_ARM7TDMI_FREQUENCY;
294	}
295}
296
297void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba) {
298	rtc->p = gba;
299	rtc->override = RTC_NO_OVERRIDE;
300	rtc->value = 0;
301	rtc->d.sample = 0;
302	rtc->d.unixTime = _rtcGenericCallback;
303}
304
305// == Gyro
306
307void GBAHardwareInitGyro(struct GBACartridgeHardware* hw) {
308	hw->devices |= HW_GYRO;
309	hw->gyroSample = 0;
310	hw->gyroEdge = 0;
311}
312
313void _gyroReadPins(struct GBACartridgeHardware* hw) {
314	struct GBARotationSource* gyro = hw->p->rotationSource;
315	if (!gyro || !gyro->readGyroZ) {
316		return;
317	}
318
319	if (hw->pinState & 1) {
320		if (gyro->sample) {
321			gyro->sample(gyro);
322		}
323		int32_t sample = gyro->readGyroZ(gyro);
324
325		// Normalize to ~12 bits, focused on 0x6C0
326		hw->gyroSample = (sample >> 21) + 0x6C0; // Crop off an extra bit so that we can't go negative
327	}
328
329	if (hw->gyroEdge && !(hw->pinState & 2)) {
330		// Write bit on falling edge
331		unsigned bit = hw->gyroSample >> 15;
332		hw->gyroSample <<= 1;
333		_outputPins(hw, bit << 2);
334	}
335
336	hw->gyroEdge = !!(hw->pinState & 2);
337}
338
339// == Rumble
340
341void GBAHardwareInitRumble(struct GBACartridgeHardware* hw) {
342	hw->devices |= HW_RUMBLE;
343}
344
345void _rumbleReadPins(struct GBACartridgeHardware* hw) {
346	struct GBARumble* rumble = hw->p->rumble;
347	if (!rumble) {
348		return;
349	}
350
351	rumble->setRumble(rumble, !!(hw->pinState & 8));
352}
353
354// == Light sensor
355
356void GBAHardwareInitLight(struct GBACartridgeHardware* hw) {
357	hw->devices |= HW_LIGHT_SENSOR;
358	hw->lightCounter = 0;
359	hw->lightEdge = false;
360	hw->lightSample = 0xFF;
361}
362
363void _lightReadPins(struct GBACartridgeHardware* hw) {
364	if (hw->pinState & 4) {
365		// Boktai chip select
366		return;
367	}
368	if (hw->pinState & 2) {
369		struct GBALuminanceSource* lux = hw->p->luminanceSource;
370		GBALog(hw->p, GBA_LOG_DEBUG, "[SOLAR] Got reset");
371		hw->lightCounter = 0;
372		if (lux) {
373			lux->sample(lux);
374			hw->lightSample = lux->readLuminance(lux);
375		} else {
376			hw->lightSample = 0xFF;
377		}
378	}
379	if ((hw->pinState & 1) && hw->lightEdge) {
380		++hw->lightCounter;
381	}
382	hw->lightEdge = !(hw->pinState & 1);
383
384	bool sendBit = hw->lightCounter >= hw->lightSample;
385	_outputPins(hw, sendBit << 3);
386	GBALog(hw->p, GBA_LOG_DEBUG, "[SOLAR] Output %u with pins %u", hw->lightCounter, hw->pinState);
387}
388
389// == Tilt
390
391void GBAHardwareInitTilt(struct GBACartridgeHardware* hw) {
392	hw->devices |= HW_TILT;
393	hw->tiltX = 0xFFF;
394	hw->tiltY = 0xFFF;
395	hw->tiltState = 0;
396}
397
398void GBAHardwareTiltWrite(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value) {
399	switch (address) {
400	case 0x8000:
401		if (value == 0x55) {
402			hw->tiltState = 1;
403		} else {
404			GBALog(hw->p, GBA_LOG_GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
405		}
406		break;
407	case 0x8100:
408		if (value == 0xAA && hw->tiltState == 1) {
409			hw->tiltState = 0;
410			struct GBARotationSource* rotationSource = hw->p->rotationSource;
411			if (!rotationSource || !rotationSource->readTiltX || !rotationSource->readTiltY) {
412				return;
413			}
414			if (rotationSource->sample) {
415				rotationSource->sample(rotationSource);
416			}
417			int32_t x = rotationSource->readTiltX(rotationSource);
418			int32_t y = rotationSource->readTiltY(rotationSource);
419			// Normalize to ~12 bits, focused on 0x3A0
420			hw->tiltX = (x >> 21) + 0x3A0; // Crop off an extra bit so that we can't go negative
421			hw->tiltY = (y >> 21) + 0x3A0;
422		} else {
423			GBALog(hw->p, GBA_LOG_GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
424		}
425		break;
426	default:
427		GBALog(hw->p, GBA_LOG_GAME_ERROR, "Invalid tilt sensor write to %04x: %02x", address, value);
428		break;
429	}
430}
431
432uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* hw, uint32_t address) {
433	switch (address) {
434	case 0x8200:
435		return hw->tiltX & 0xFF;
436	case 0x8300:
437		return ((hw->tiltX >> 8) & 0xF) | 0x80;
438	case 0x8400:
439		return hw->tiltY & 0xFF;
440	case 0x8500:
441		return (hw->tiltY >> 8) & 0xF;
442	default:
443		GBALog(hw->p, GBA_LOG_GAME_ERROR, "Invalid tilt sensor read from %04x", address);
444		break;
445	}
446	return 0xFF;
447}
448
449// == Game Boy Player
450
451static const uint16_t _logoPalette[] = {
452	0xFFDF, 0x640C, 0xE40C, 0xE42D, 0x644E, 0xE44E, 0xE46E, 0x68AF,
453	0xE8B0, 0x68D0, 0x68F0, 0x6911, 0xE911, 0x6D32, 0xED32, 0xED73,
454	0x6D93, 0xED94, 0x6DB4, 0xF1D5, 0x71F5, 0xF1F6, 0x7216, 0x7257,
455	0xF657, 0x7678, 0xF678, 0xF699, 0xF6B9, 0x76D9, 0xF6DA, 0x7B1B,
456	0xFB1B, 0xFB3C, 0x7B5C, 0x7B7D, 0xFF7D, 0x7F9D, 0x7FBE, 0x7FFF,
457	0x642D, 0x648E, 0xE88F, 0xE8F1, 0x6D52, 0x6D73, 0xF1B4, 0xF216,
458	0x7237, 0x7698, 0x7AFA, 0xFAFA, 0xFB5C, 0xFFBE, 0x7FDE, 0xFFFF,
459	0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
460};
461
462static const uint32_t _logoHash = 0xEEDA6963;
463
464bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) {
465	if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
466		return false;
467	}
468	uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0);
469	return hash == _logoHash;
470}
471
472// == Serialization
473
474void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
475	state->hw.readWrite = hw->readWrite;
476	state->hw.pinState = hw->pinState;
477	state->hw.pinDirection = hw->direction;
478	state->hw.devices = hw->devices;
479	state->hw.rtc = hw->rtc;
480	state->hw.gyroSample = hw->gyroSample;
481	state->hw.gyroEdge = hw->gyroEdge;
482	state->hw.tiltSampleX = hw->tiltX;
483	state->hw.tiltSampleY = hw->tiltY;
484	state->hw.tiltState = hw->tiltState;
485	state->hw.lightCounter = hw->lightCounter;
486	state->hw.lightSample = hw->lightSample;
487	state->hw.lightEdge = hw->lightEdge;
488}
489
490void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) {
491	hw->readWrite = state->hw.readWrite;
492	hw->pinState = state->hw.pinState;
493	hw->direction = state->hw.pinDirection;
494	hw->rtc = state->hw.rtc;
495	hw->gyroSample = state->hw.gyroSample;
496	hw->gyroEdge = state->hw.gyroEdge;
497	hw->tiltX = state->hw.tiltSampleX;
498	hw->tiltY = state->hw.tiltSampleY;
499	hw->tiltState = state->hw.tiltState;
500	hw->lightCounter = state->hw.lightCounter;
501	hw->lightSample = state->hw.lightSample;
502	hw->lightEdge = state->hw.lightEdge;
503}