all repos — mgba @ 1f156921732db400cfbb4a0ff3f8efc0faf5dd1e

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