all repos — mgba @ 401bc9e9d632869c25072694b3c491f86e93ba8c

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