all repos — mgba @ a309e38e33d0a964ba7b0a1747d0be13e45ced67

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