all repos — mgba @ medusa

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