all repos — mgba @ 709149458319ec6bdf1a95c615a3ce5a6bbe1cb0

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