all repos — mgba @ 6758c97c1e0be4eaff46bbafa9251d96c7d27464

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