all repos — mgba @ cb0f95b07053e63e817bd05df0a36bf917667d09

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