all repos — mgba @ 44175d9381936c0445f30a611e034a9c23103649

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