all repos — mgba @ c39162732d966e379c68a11fed6371276c3f9eb5

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/io.h"
  9#include "gba/serialize.h"
 10#include "util/hash.h"
 11
 12const int GBA_LUX_LEVELS[10] = { 5, 11, 18, 27, 42, 62, 84, 109, 139, 183 };
 13
 14static void _readPins(struct GBACartridgeHardware* hw);
 15static void _outputPins(struct GBACartridgeHardware* hw, unsigned pins);
 16
 17static void _rtcReadPins(struct GBACartridgeHardware* hw);
 18static unsigned _rtcOutput(struct GBACartridgeHardware* hw);
 19static void _rtcProcessByte(struct GBACartridgeHardware* hw);
 20static void _rtcUpdateClock(struct GBACartridgeHardware* hw);
 21static unsigned _rtcBCD(unsigned value);
 22
 23static time_t _rtcGenericCallback(struct GBARTCSource* source);
 24
 25static void _gyroReadPins(struct GBACartridgeHardware* hw);
 26
 27static void _rumbleReadPins(struct GBACartridgeHardware* hw);
 28
 29static void _lightReadPins(struct GBACartridgeHardware* hw);
 30
 31static uint16_t _gbpRead(struct GBAKeyCallback*);
 32static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
 33static int32_t _gbpSioProcessEvents(struct GBASIODriver* driver, int32_t cycles);
 34
 35static const int RTC_BYTES[8] = {
 36	0, // Force reset
 37	0, // Empty
 38	7, // Date/Time
 39	0, // Force IRQ
 40	1, // Control register
 41	0, // Empty
 42	3, // Time
 43	0 // Empty
 44};
 45
 46void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) {
 47	hw->gpioBase = base;
 48	GBAHardwareClear(hw);
 49
 50	hw->gbpCallback.d.readKeys = _gbpRead;
 51	hw->gbpCallback.p = hw;
 52	hw->gbpDriver.d.init = 0;
 53	hw->gbpDriver.d.deinit = 0;
 54	hw->gbpDriver.d.load = 0;
 55	hw->gbpDriver.d.unload = 0;
 56	hw->gbpDriver.d.writeRegister = _gbpSioWriteRegister;
 57	hw->gbpDriver.d.processEvents = _gbpSioProcessEvents;
 58	hw->gbpDriver.p = hw;
 59}
 60
 61void GBAHardwareClear(struct GBACartridgeHardware* hw) {
 62	hw->devices = HW_NONE | (hw->devices & HW_GB_PLAYER_DETECTION);
 63	hw->direction = GPIO_WRITE_ONLY;
 64	hw->pinState = 0;
 65	hw->direction = 0;
 66
 67	if (hw->p->sio.drivers.normal == &hw->gbpDriver.d) {
 68		GBASIOSetDriver(&hw->p->sio, 0, SIO_NORMAL_32);
 69	}
 70}
 71
 72void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) {
 73	switch (address) {
 74	case GPIO_REG_DATA:
 75		hw->pinState &= ~hw->direction;
 76		hw->pinState |= value;
 77		_readPins(hw);
 78		break;
 79	case GPIO_REG_DIRECTION:
 80		hw->direction = value;
 81		break;
 82	case GPIO_REG_CONTROL:
 83		hw->readWrite = value;
 84		break;
 85	default:
 86		GBALog(hw->p, GBA_LOG_WARN, "Invalid GPIO address");
 87	}
 88	if (hw->readWrite) {
 89		uint16_t old = hw->gpioBase[0];
 90		old &= ~hw->direction;
 91		hw->gpioBase[0] = old | hw->pinState;
 92	} else {
 93		hw->gpioBase[0] = 0;
 94	}
 95}
 96
 97void GBAHardwareInitRTC(struct GBACartridgeHardware* hw) {
 98	hw->devices |= HW_RTC;
 99	hw->rtc.bytesRemaining = 0;
100
101	hw->rtc.transferStep = 0;
102
103	hw->rtc.bitsRead = 0;
104	hw->rtc.bits = 0;
105	hw->rtc.commandActive = 0;
106	hw->rtc.command = 0;
107	hw->rtc.control = 0x40;
108	memset(hw->rtc.time, 0, sizeof(hw->rtc.time));
109}
110
111void _readPins(struct GBACartridgeHardware* hw) {
112	if (hw->devices & HW_RTC) {
113		_rtcReadPins(hw);
114	}
115
116	if (hw->devices & HW_GYRO) {
117		_gyroReadPins(hw);
118	}
119
120	if (hw->devices & HW_RUMBLE) {
121		_rumbleReadPins(hw);
122	}
123
124	if (hw->devices & HW_LIGHT_SENSOR) {
125		_lightReadPins(hw);
126	}
127}
128
129void _outputPins(struct GBACartridgeHardware* hw, unsigned pins) {
130	if (hw->readWrite) {
131		uint16_t old = hw->gpioBase[0];
132		old &= hw->direction;
133		hw->pinState = old | (pins & ~hw->direction & 0xF);
134		hw->gpioBase[0] = hw->pinState;
135	}
136}
137
138// == RTC
139
140void _rtcReadPins(struct GBACartridgeHardware* hw) {
141	// Transfer sequence:
142	// P: 0 | 1 |  2 | 3
143	// == Initiate
144	// > HI | - | LO | -
145	// > HI | - | HI | -
146	// == Transfer bit (x8)
147	// > LO | x | HI | -
148	// > HI | - | HI | -
149	// < ?? | x | ?? | -
150	// == Terminate
151	// >  - | - | LO | -
152	switch (hw->rtc.transferStep) {
153	case 0:
154		if ((hw->pinState & 5) == 1) {
155			hw->rtc.transferStep = 1;
156		}
157		break;
158	case 1:
159		if ((hw->pinState & 5) == 5) {
160			hw->rtc.transferStep = 2;
161		}
162		break;
163	case 2:
164		if (!(hw->pinState & 1)) {
165			hw->rtc.bits &= ~(1 << hw->rtc.bitsRead);
166			hw->rtc.bits |= ((hw->pinState & 2) >> 1) << hw->rtc.bitsRead;
167		} else {
168			if (hw->pinState & 4) {
169				// GPIO direction should always != reading
170				if (hw->direction & 2) {
171					if (RTCCommandDataIsReading(hw->rtc.command)) {
172						GBALog(hw->p, GBA_LOG_GAME_ERROR, "Attempting to write to RTC while in read mode");
173					}
174					++hw->rtc.bitsRead;
175					if (hw->rtc.bitsRead == 8) {
176						_rtcProcessByte(hw);
177					}
178				} else {
179					_outputPins(hw, 5 | (_rtcOutput(hw) << 1));
180					++hw->rtc.bitsRead;
181					if (hw->rtc.bitsRead == 8) {
182						--hw->rtc.bytesRemaining;
183						if (hw->rtc.bytesRemaining <= 0) {
184							hw->rtc.commandActive = 0;
185							hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command);
186						}
187						hw->rtc.bitsRead = 0;
188					}
189				}
190			} else {
191				hw->rtc.bitsRead = 0;
192				hw->rtc.bytesRemaining = 0;
193				hw->rtc.commandActive = 0;
194				hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command);
195				hw->rtc.transferStep = 0;
196			}
197		}
198		break;
199	}
200}
201
202void _rtcProcessByte(struct GBACartridgeHardware* hw) {
203	--hw->rtc.bytesRemaining;
204	if (!hw->rtc.commandActive) {
205		RTCCommandData command;
206		command = hw->rtc.bits;
207		if (RTCCommandDataGetMagic(command) == 0x06) {
208			hw->rtc.command = command;
209
210			hw->rtc.bytesRemaining = RTC_BYTES[RTCCommandDataGetCommand(command)];
211			hw->rtc.commandActive = hw->rtc.bytesRemaining > 0;
212			switch (RTCCommandDataGetCommand(command)) {
213			case RTC_RESET:
214				hw->rtc.control = 0;
215				break;
216			case RTC_DATETIME:
217			case RTC_TIME:
218				_rtcUpdateClock(hw);
219				break;
220			case RTC_FORCE_IRQ:
221			case RTC_CONTROL:
222				break;
223			}
224		} else {
225			GBALog(hw->p, GBA_LOG_WARN, "Invalid RTC command byte: %02X", hw->rtc.bits);
226		}
227	} else {
228		switch (RTCCommandDataGetCommand(hw->rtc.command)) {
229		case RTC_CONTROL:
230			hw->rtc.control = hw->rtc.bits;
231			break;
232		case RTC_FORCE_IRQ:
233			GBALog(hw->p, GBA_LOG_STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(hw->rtc.command));
234			break;
235		case RTC_RESET:
236		case RTC_DATETIME:
237		case RTC_TIME:
238			break;
239		}
240	}
241
242	hw->rtc.bits = 0;
243	hw->rtc.bitsRead = 0;
244	if (!hw->rtc.bytesRemaining) {
245		hw->rtc.commandActive = 0;
246		hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command);
247	}
248}
249
250unsigned _rtcOutput(struct GBACartridgeHardware* hw) {
251	uint8_t outputByte = 0;
252	switch (RTCCommandDataGetCommand(hw->rtc.command)) {
253	case RTC_CONTROL:
254		outputByte = hw->rtc.control;
255		break;
256	case RTC_DATETIME:
257	case RTC_TIME:
258		outputByte = hw->rtc.time[7 - hw->rtc.bytesRemaining];
259		break;
260	case RTC_FORCE_IRQ:
261	case RTC_RESET:
262		break;
263	}
264	unsigned output = (outputByte >> hw->rtc.bitsRead) & 1;
265	return output;
266}
267
268void _rtcUpdateClock(struct GBACartridgeHardware* hw) {
269	time_t t;
270	struct GBARTCSource* rtc = hw->p->rtcSource;
271	if (rtc) {
272		if (rtc->sample) {
273			rtc->sample(rtc);
274		}
275		t = rtc->unixTime(rtc);
276	} else {
277		t = time(0);
278	}
279	struct tm date;
280#ifdef _WIN32
281	date = *localtime(&t);
282#else
283	localtime_r(&t, &date);
284#endif
285	hw->rtc.time[0] = _rtcBCD(date.tm_year - 100);
286	hw->rtc.time[1] = _rtcBCD(date.tm_mon + 1);
287	hw->rtc.time[2] = _rtcBCD(date.tm_mday);
288	hw->rtc.time[3] = _rtcBCD(date.tm_wday);
289	if (RTCControlIsHour24(hw->rtc.control)) {
290		hw->rtc.time[4] = _rtcBCD(date.tm_hour);
291	} else {
292		hw->rtc.time[4] = _rtcBCD(date.tm_hour % 12);
293	}
294	hw->rtc.time[5] = _rtcBCD(date.tm_min);
295	hw->rtc.time[6] = _rtcBCD(date.tm_sec);
296}
297
298unsigned _rtcBCD(unsigned value) {
299	int counter = value % 10;
300	value /= 10;
301	counter += (value % 10) << 4;
302	return counter;
303}
304
305time_t _rtcGenericCallback(struct GBARTCSource* source) {
306	struct GBARTCGenericSource* rtc = (struct GBARTCGenericSource*) source;
307	switch (rtc->override) {
308	case RTC_NO_OVERRIDE:
309	default:
310		return time(0);
311	case RTC_FIXED:
312		return rtc->value;
313	case RTC_FAKE_EPOCH:
314		return rtc->value + rtc->p->video.frameCounter * (int64_t) VIDEO_TOTAL_LENGTH / GBA_ARM7TDMI_FREQUENCY;
315	}
316}
317
318void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba) {
319	rtc->p = gba;
320	rtc->override = RTC_NO_OVERRIDE;
321	rtc->value = 0;
322	rtc->d.sample = 0;
323	rtc->d.unixTime = _rtcGenericCallback;
324}
325
326// == Gyro
327
328void GBAHardwareInitGyro(struct GBACartridgeHardware* hw) {
329	hw->devices |= HW_GYRO;
330	hw->gyroSample = 0;
331	hw->gyroEdge = 0;
332}
333
334void _gyroReadPins(struct GBACartridgeHardware* hw) {
335	struct GBARotationSource* gyro = hw->p->rotationSource;
336	if (!gyro || !gyro->readGyroZ) {
337		return;
338	}
339
340	if (hw->pinState & 1) {
341		if (gyro->sample) {
342			gyro->sample(gyro);
343		}
344		int32_t sample = gyro->readGyroZ(gyro);
345
346		// Normalize to ~12 bits, focused on 0x6C0
347		hw->gyroSample = (sample >> 21) + 0x6C0; // Crop off an extra bit so that we can't go negative
348	}
349
350	if (hw->gyroEdge && !(hw->pinState & 2)) {
351		// Write bit on falling edge
352		unsigned bit = hw->gyroSample >> 15;
353		hw->gyroSample <<= 1;
354		_outputPins(hw, bit << 2);
355	}
356
357	hw->gyroEdge = !!(hw->pinState & 2);
358}
359
360// == Rumble
361
362void GBAHardwareInitRumble(struct GBACartridgeHardware* hw) {
363	hw->devices |= HW_RUMBLE;
364}
365
366void _rumbleReadPins(struct GBACartridgeHardware* hw) {
367	struct GBARumble* rumble = hw->p->rumble;
368	if (!rumble) {
369		return;
370	}
371
372	rumble->setRumble(rumble, !!(hw->pinState & 8));
373}
374
375// == Light sensor
376
377void GBAHardwareInitLight(struct GBACartridgeHardware* hw) {
378	hw->devices |= HW_LIGHT_SENSOR;
379	hw->lightCounter = 0;
380	hw->lightEdge = false;
381	hw->lightSample = 0xFF;
382}
383
384void _lightReadPins(struct GBACartridgeHardware* hw) {
385	if (hw->pinState & 4) {
386		// Boktai chip select
387		return;
388	}
389	if (hw->pinState & 2) {
390		struct GBALuminanceSource* lux = hw->p->luminanceSource;
391		GBALog(hw->p, GBA_LOG_DEBUG, "[SOLAR] Got reset");
392		hw->lightCounter = 0;
393		if (lux) {
394			lux->sample(lux);
395			hw->lightSample = lux->readLuminance(lux);
396		} else {
397			hw->lightSample = 0xFF;
398		}
399	}
400	if ((hw->pinState & 1) && hw->lightEdge) {
401		++hw->lightCounter;
402	}
403	hw->lightEdge = !(hw->pinState & 1);
404
405	bool sendBit = hw->lightCounter >= hw->lightSample;
406	_outputPins(hw, sendBit << 3);
407	GBALog(hw->p, GBA_LOG_DEBUG, "[SOLAR] Output %u with pins %u", hw->lightCounter, hw->pinState);
408}
409
410// == Tilt
411
412void GBAHardwareInitTilt(struct GBACartridgeHardware* hw) {
413	hw->devices |= HW_TILT;
414	hw->tiltX = 0xFFF;
415	hw->tiltY = 0xFFF;
416	hw->tiltState = 0;
417}
418
419void GBAHardwareTiltWrite(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value) {
420	switch (address) {
421	case 0x8000:
422		if (value == 0x55) {
423			hw->tiltState = 1;
424		} else {
425			GBALog(hw->p, GBA_LOG_GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
426		}
427		break;
428	case 0x8100:
429		if (value == 0xAA && hw->tiltState == 1) {
430			hw->tiltState = 0;
431			struct GBARotationSource* rotationSource = hw->p->rotationSource;
432			if (!rotationSource || !rotationSource->readTiltX || !rotationSource->readTiltY) {
433				return;
434			}
435			if (rotationSource->sample) {
436				rotationSource->sample(rotationSource);
437			}
438			int32_t x = rotationSource->readTiltX(rotationSource);
439			int32_t y = rotationSource->readTiltY(rotationSource);
440			// Normalize to ~12 bits, focused on 0x3A0
441			hw->tiltX = (x >> 21) + 0x3A0; // Crop off an extra bit so that we can't go negative
442			hw->tiltY = (y >> 21) + 0x3A0;
443		} else {
444			GBALog(hw->p, GBA_LOG_GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
445		}
446		break;
447	default:
448		GBALog(hw->p, GBA_LOG_GAME_ERROR, "Invalid tilt sensor write to %04x: %02x", address, value);
449		break;
450	}
451}
452
453uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* hw, uint32_t address) {
454	switch (address) {
455	case 0x8200:
456		return hw->tiltX & 0xFF;
457	case 0x8300:
458		return ((hw->tiltX >> 8) & 0xF) | 0x80;
459	case 0x8400:
460		return hw->tiltY & 0xFF;
461	case 0x8500:
462		return (hw->tiltY >> 8) & 0xF;
463	default:
464		GBALog(hw->p, GBA_LOG_GAME_ERROR, "Invalid tilt sensor read from %04x", address);
465		break;
466	}
467	return 0xFF;
468}
469
470// == Game Boy Player
471
472static const uint16_t _logoPalette[] = {
473	0xFFDF, 0x640C, 0xE40C, 0xE42D, 0x644E, 0xE44E, 0xE46E, 0x68AF,
474	0xE8B0, 0x68D0, 0x68F0, 0x6911, 0xE911, 0x6D32, 0xED32, 0xED73,
475	0x6D93, 0xED94, 0x6DB4, 0xF1D5, 0x71F5, 0xF1F6, 0x7216, 0x7257,
476	0xF657, 0x7678, 0xF678, 0xF699, 0xF6B9, 0x76D9, 0xF6DA, 0x7B1B,
477	0xFB1B, 0xFB3C, 0x7B5C, 0x7B7D, 0xFF7D, 0x7F9D, 0x7FBE, 0x7FFF,
478	0x642D, 0x648E, 0xE88F, 0xE8F1, 0x6D52, 0x6D73, 0xF1B4, 0xF216,
479	0x7237, 0x7698, 0x7AFA, 0xFAFA, 0xFB5C, 0xFFBE, 0x7FDE, 0xFFFF,
480	0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
481};
482
483static const uint32_t _logoHash = 0xEEDA6963;
484
485static const uint32_t _gbpTxData[] = {
486	0x0000494E, 0x0000494E,
487	0xB6B1494E, 0xB6B1544E,
488	0xABB1544E, 0xABB14E45,
489	0xB1BA4E45, 0xB1BA4F44,
490	0xB0BB4F44, 0xB0BB8002,
491	0x10000010, 0x20000013,
492	0x30000003, 0x30000003,
493	0x30000003, 0x30000003,
494	0x30000003, 0x00000000,
495};
496
497static const uint32_t _gbpRxData[] = {
498	0x00000000, 0x494EB6B1,
499	0x494EB6B1, 0x544EB6B1,
500	0x544EABB1, 0x4E45ABB1,
501	0x4E45B1BA, 0x4F44B1BA,
502	0x4F44B0BB, 0x8000B0BB,
503	0x10000010, 0x20000013,
504	0x40000004, 0x40000004,
505	0x40000004, 0x40000004,
506	0x40000004, 0x40000004
507};
508
509bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) {
510	if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
511		return false;
512	}
513	uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0);
514	return hash == _logoHash;
515}
516
517void GBAHardwarePlayerUpdate(struct GBA* gba) {
518	if (gba->memory.hw.devices & HW_GB_PLAYER) {
519		if (GBAHardwarePlayerCheckScreen(&gba->video)) {
520			++gba->memory.hw.gbpInputsPosted;
521			gba->memory.hw.gbpInputsPosted %= 3;
522			gba->keyCallback = &gba->memory.hw.gbpCallback.d;
523		} else {
524			// TODO: Save and restore
525			gba->keyCallback = 0;
526		}
527		gba->memory.hw.gbpTxPosition = 0;
528		return;
529	}
530	if (gba->keyCallback || gba->sio.drivers.normal) {
531		return;
532	}
533	if (GBAHardwarePlayerCheckScreen(&gba->video)) {
534		gba->memory.hw.devices |= HW_GB_PLAYER;
535		gba->memory.hw.gbpInputsPosted = 0;
536		gba->memory.hw.gbpNextEvent = INT_MAX;
537		gba->keyCallback = &gba->memory.hw.gbpCallback.d;
538		GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32);
539	}
540}
541
542uint16_t _gbpRead(struct GBAKeyCallback* callback) {
543	struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback;
544	if (gbpCallback->p->gbpInputsPosted == 2) {
545		return 0x30F;
546	}
547	return 0x3FF;
548}
549
550uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
551	struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver;
552	if (address == REG_SIOCNT) {
553		if (value & 0x0080) {
554			if (gbp->p->gbpTxPosition <= 16 && gbp->p->gbpTxPosition > 0) {
555				uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16);
556				uint32_t expected = _gbpRxData[gbp->p->gbpTxPosition];
557				// TODO: Check expected
558				uint32_t mask = 0;
559				if (gbp->p->gbpTxPosition == 15) {
560					mask = 0x22;
561					if (gbp->p->p->rumble) {
562						gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == mask);
563					}
564				}
565			}
566			gbp->p->gbpNextEvent = 2048;
567		}
568		value &= 0x78FB;
569	}
570	return value;
571}
572
573int32_t _gbpSioProcessEvents(struct GBASIODriver* driver, int32_t cycles) {
574	struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver;
575	gbp->p->gbpNextEvent -= cycles;
576	if (gbp->p->gbpNextEvent <= 0) {
577		uint32_t tx = 0;
578		if (gbp->p->gbpTxPosition <= 16) {
579			tx = _gbpTxData[gbp->p->gbpTxPosition];
580			++gbp->p->gbpTxPosition;
581		}
582		gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
583		gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
584		if (gbp->d.p->normalControl.irq) {
585			GBARaiseIRQ(gbp->p->p, IRQ_SIO);
586		}
587		gbp->d.p->normalControl.start = 0;
588		gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt;
589		gbp->p->gbpNextEvent = INT_MAX;
590	}
591	return gbp->p->gbpNextEvent;
592}
593
594// == Serialization
595
596void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
597	state->hw.readWrite = hw->readWrite;
598	state->hw.pinState = hw->pinState;
599	state->hw.pinDirection = hw->direction;
600	state->hw.devices = hw->devices;
601	state->hw.rtc = hw->rtc;
602	state->hw.gyroSample = hw->gyroSample;
603	state->hw.gyroEdge = hw->gyroEdge;
604	state->hw.tiltSampleX = hw->tiltX;
605	state->hw.tiltSampleY = hw->tiltY;
606	state->hw.tiltState = hw->tiltState;
607	state->hw.lightCounter = hw->lightCounter;
608	state->hw.lightSample = hw->lightSample;
609	state->hw.lightEdge = hw->lightEdge;
610	state->hw.gbpInputsPosted = hw->gbpInputsPosted;
611	state->hw.gbpTxPosition = hw->gbpTxPosition;
612	state->hw.gbpNextEvent = hw->gbpNextEvent;
613}
614
615void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) {
616	hw->readWrite = state->hw.readWrite;
617	hw->pinState = state->hw.pinState;
618	hw->direction = state->hw.pinDirection;
619	hw->devices = state->hw.devices;
620	hw->rtc = state->hw.rtc;
621	hw->gyroSample = state->hw.gyroSample;
622	hw->gyroEdge = state->hw.gyroEdge;
623	hw->tiltX = state->hw.tiltSampleX;
624	hw->tiltY = state->hw.tiltSampleY;
625	hw->tiltState = state->hw.tiltState;
626	hw->lightCounter = state->hw.lightCounter;
627	hw->lightSample = state->hw.lightSample;
628	hw->lightEdge = state->hw.lightEdge;
629	hw->gbpInputsPosted = state->hw.gbpInputsPosted;
630	hw->gbpTxPosition = state->hw.gbpTxPosition;
631	hw->gbpNextEvent = state->hw.gbpNextEvent;
632	if (hw->devices & HW_GB_PLAYER) {
633		GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32);
634	}
635}