all repos — mgba @ fe2f67e2aa2246e8ec2c2599a480d6ff7557f3f7

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