all repos — mgba @ 3b363bb2c17a5269ffcf9312e52c271563f43646

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			mLOG(GBA_HW, DEBUG, "Got RTC command %x", RTCCommandDataGetCommand(command));
242			switch (RTCCommandDataGetCommand(command)) {
243			case RTC_RESET:
244				hw->rtc.control = 0;
245				break;
246			case RTC_DATETIME:
247			case RTC_TIME:
248				_rtcUpdateClock(hw);
249				break;
250			case RTC_FORCE_IRQ:
251			case RTC_CONTROL:
252				break;
253			}
254		} else {
255			mLOG(GBA_HW, WARN, "Invalid RTC command byte: %02X", hw->rtc.bits);
256		}
257	} else {
258		switch (RTCCommandDataGetCommand(hw->rtc.command)) {
259		case RTC_CONTROL:
260			hw->rtc.control = hw->rtc.bits;
261			break;
262		case RTC_FORCE_IRQ:
263			mLOG(GBA_HW, STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(hw->rtc.command));
264			break;
265		case RTC_RESET:
266		case RTC_DATETIME:
267		case RTC_TIME:
268			break;
269		}
270	}
271
272	hw->rtc.bits = 0;
273	hw->rtc.bitsRead = 0;
274	if (!hw->rtc.bytesRemaining) {
275		hw->rtc.commandActive = 0;
276		hw->rtc.command = 0;
277	}
278}
279
280unsigned _rtcOutput(struct GBACartridgeHardware* hw) {
281	uint8_t outputByte = 0;
282	if (!hw->rtc.commandActive) {
283		mLOG(GBA_HW, GAME_ERROR, "Attempting to use RTC without an active command");
284		return 0;
285	}
286	switch (RTCCommandDataGetCommand(hw->rtc.command)) {
287	case RTC_CONTROL:
288		outputByte = hw->rtc.control;
289		break;
290	case RTC_DATETIME:
291	case RTC_TIME:
292		outputByte = hw->rtc.time[7 - hw->rtc.bytesRemaining];
293		break;
294	case RTC_FORCE_IRQ:
295	case RTC_RESET:
296		break;
297	}
298	unsigned output = (outputByte >> hw->rtc.bitsRead) & 1;
299	if (hw->rtc.bitsRead == 0) {
300		mLOG(GBA_HW, DEBUG, "RTC output byte %02X", outputByte);
301	}
302	return output;
303}
304
305void _rtcUpdateClock(struct GBACartridgeHardware* hw) {
306	time_t t;
307	struct mRTCSource* rtc = hw->p->rtcSource;
308	if (rtc) {
309		if (rtc->sample) {
310			rtc->sample(rtc);
311		}
312		t = rtc->unixTime(rtc);
313	} else {
314		t = time(0);
315	}
316	struct tm date;
317	localtime_r(&t, &date);
318	hw->rtc.time[0] = _rtcBCD(date.tm_year - 100);
319	hw->rtc.time[1] = _rtcBCD(date.tm_mon + 1);
320	hw->rtc.time[2] = _rtcBCD(date.tm_mday);
321	hw->rtc.time[3] = _rtcBCD(date.tm_wday);
322	if (RTCControlIsHour24(hw->rtc.control)) {
323		hw->rtc.time[4] = _rtcBCD(date.tm_hour);
324	} else {
325		hw->rtc.time[4] = _rtcBCD(date.tm_hour % 12);
326	}
327	hw->rtc.time[5] = _rtcBCD(date.tm_min);
328	hw->rtc.time[6] = _rtcBCD(date.tm_sec);
329}
330
331unsigned _rtcBCD(unsigned value) {
332	int counter = value % 10;
333	value /= 10;
334	counter += (value % 10) << 4;
335	return counter;
336}
337
338time_t _rtcGenericCallback(struct mRTCSource* source) {
339	struct GBARTCGenericSource* rtc = (struct GBARTCGenericSource*) source;
340	switch (rtc->override) {
341	case RTC_NO_OVERRIDE:
342	default:
343		return time(0);
344	case RTC_FIXED:
345		return rtc->value;
346	case RTC_FAKE_EPOCH:
347		return rtc->value + rtc->p->video.frameCounter * (int64_t) VIDEO_TOTAL_LENGTH / GBA_ARM7TDMI_FREQUENCY;
348	}
349}
350
351void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba) {
352	rtc->p = gba;
353	rtc->override = RTC_NO_OVERRIDE;
354	rtc->value = 0;
355	rtc->d.sample = 0;
356	rtc->d.unixTime = _rtcGenericCallback;
357}
358
359// == Gyro
360
361void GBAHardwareInitGyro(struct GBACartridgeHardware* hw) {
362	hw->devices |= HW_GYRO;
363	hw->gyroSample = 0;
364	hw->gyroEdge = 0;
365}
366
367void _gyroReadPins(struct GBACartridgeHardware* hw) {
368	struct mRotationSource* gyro = hw->p->rotationSource;
369	if (!gyro || !gyro->readGyroZ) {
370		return;
371	}
372
373	if (hw->pinState & 1) {
374		if (gyro->sample) {
375			gyro->sample(gyro);
376		}
377		int32_t sample = gyro->readGyroZ(gyro);
378
379		// Normalize to ~12 bits, focused on 0x6C0
380		hw->gyroSample = (sample >> 21) + 0x6C0; // Crop off an extra bit so that we can't go negative
381	}
382
383	if (hw->gyroEdge && !(hw->pinState & 2)) {
384		// Write bit on falling edge
385		unsigned bit = hw->gyroSample >> 15;
386		hw->gyroSample <<= 1;
387		_outputPins(hw, bit << 2);
388	}
389
390	hw->gyroEdge = !!(hw->pinState & 2);
391}
392
393// == Rumble
394
395void GBAHardwareInitRumble(struct GBACartridgeHardware* hw) {
396	hw->devices |= HW_RUMBLE;
397}
398
399void _rumbleReadPins(struct GBACartridgeHardware* hw) {
400	struct mRumble* rumble = hw->p->rumble;
401	if (!rumble) {
402		return;
403	}
404
405	rumble->setRumble(rumble, !!(hw->pinState & 8));
406}
407
408// == Light sensor
409
410void GBAHardwareInitLight(struct GBACartridgeHardware* hw) {
411	hw->devices |= HW_LIGHT_SENSOR;
412	hw->lightCounter = 0;
413	hw->lightEdge = false;
414	hw->lightSample = 0xFF;
415}
416
417void _lightReadPins(struct GBACartridgeHardware* hw) {
418	if (hw->pinState & 4) {
419		// Boktai chip select
420		return;
421	}
422	if (hw->pinState & 2) {
423		struct GBALuminanceSource* lux = hw->p->luminanceSource;
424		mLOG(GBA_HW, DEBUG, "[SOLAR] Got reset");
425		hw->lightCounter = 0;
426		if (lux) {
427			lux->sample(lux);
428			hw->lightSample = lux->readLuminance(lux);
429		} else {
430			hw->lightSample = 0xFF;
431		}
432	}
433	if ((hw->pinState & 1) && hw->lightEdge) {
434		++hw->lightCounter;
435	}
436	hw->lightEdge = !(hw->pinState & 1);
437
438	bool sendBit = hw->lightCounter >= hw->lightSample;
439	_outputPins(hw, sendBit << 3);
440	mLOG(GBA_HW, DEBUG, "[SOLAR] Output %u with pins %u", hw->lightCounter, hw->pinState);
441}
442
443// == Tilt
444
445void GBAHardwareInitTilt(struct GBACartridgeHardware* hw) {
446	hw->devices |= HW_TILT;
447	hw->tiltX = 0xFFF;
448	hw->tiltY = 0xFFF;
449	hw->tiltState = 0;
450}
451
452void GBAHardwareTiltWrite(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value) {
453	switch (address) {
454	case 0x8000:
455		if (value == 0x55) {
456			hw->tiltState = 1;
457		} else {
458			mLOG(GBA_HW, GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
459		}
460		break;
461	case 0x8100:
462		if (value == 0xAA && hw->tiltState == 1) {
463			hw->tiltState = 0;
464			struct mRotationSource* rotationSource = hw->p->rotationSource;
465			if (!rotationSource || !rotationSource->readTiltX || !rotationSource->readTiltY) {
466				return;
467			}
468			if (rotationSource->sample) {
469				rotationSource->sample(rotationSource);
470			}
471			int32_t x = rotationSource->readTiltX(rotationSource);
472			int32_t y = rotationSource->readTiltY(rotationSource);
473			// Normalize to ~12 bits, focused on 0x3A0
474			hw->tiltX = (x >> 21) + 0x3A0; // Crop off an extra bit so that we can't go negative
475			hw->tiltY = (y >> 21) + 0x3A0;
476		} else {
477			mLOG(GBA_HW, GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
478		}
479		break;
480	default:
481		mLOG(GBA_HW, GAME_ERROR, "Invalid tilt sensor write to %04x: %02x", address, value);
482		break;
483	}
484}
485
486uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* hw, uint32_t address) {
487	switch (address) {
488	case 0x8200:
489		return hw->tiltX & 0xFF;
490	case 0x8300:
491		return ((hw->tiltX >> 8) & 0xF) | 0x80;
492	case 0x8400:
493		return hw->tiltY & 0xFF;
494	case 0x8500:
495		return (hw->tiltY >> 8) & 0xF;
496	default:
497		mLOG(GBA_HW, GAME_ERROR, "Invalid tilt sensor read from %04x", address);
498		break;
499	}
500	return 0xFF;
501}
502
503// == Game Boy Player
504
505static const uint8_t _logoPalette[] = {
506	0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68,
507	0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED,
508	0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72,
509	0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B,
510	0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F,
511	0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2,
512	0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF,
513	0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
514};
515
516static const uint32_t _logoHash = 0xEEDA6963;
517
518static const uint32_t _gbpTxData[] = {
519	0x0000494E, 0x0000494E,
520	0xB6B1494E, 0xB6B1544E,
521	0xABB1544E, 0xABB14E45,
522	0xB1BA4E45, 0xB1BA4F44,
523	0xB0BB4F44, 0xB0BB8002,
524	0x10000010, 0x20000013,
525	0x30000003
526};
527
528bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) {
529	if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
530		return false;
531	}
532	uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0);
533	return hash == _logoHash;
534}
535
536void GBAHardwarePlayerUpdate(struct GBA* gba) {
537	if (gba->memory.hw.devices & HW_GB_PLAYER) {
538		if (GBAHardwarePlayerCheckScreen(&gba->video)) {
539			++gba->memory.hw.gbpInputsPosted;
540			gba->memory.hw.gbpInputsPosted %= 3;
541			gba->keyCallback = &gba->memory.hw.gbpCallback.d;
542		} else {
543			// TODO: Save and restore
544			gba->keyCallback = 0;
545		}
546		gba->memory.hw.gbpTxPosition = 0;
547		return;
548	}
549	if (gba->keyCallback || gba->sio.drivers.normal) {
550		return;
551	}
552	if (GBAHardwarePlayerCheckScreen(&gba->video)) {
553		gba->memory.hw.devices |= HW_GB_PLAYER;
554		gba->memory.hw.gbpInputsPosted = 0;
555		gba->keyCallback = &gba->memory.hw.gbpCallback.d;
556		GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32);
557	}
558}
559
560uint16_t _gbpRead(struct mKeyCallback* callback) {
561	struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback;
562	if (gbpCallback->p->gbpInputsPosted == 2) {
563		return 0xF0;
564	}
565	return 0;
566}
567
568uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
569	struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver;
570	if (address == REG_SIOCNT) {
571		if (value & 0x0080) {
572			uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16);
573			if (gbp->p->gbpTxPosition < 12 && gbp->p->gbpTxPosition > 0) {
574				// TODO: Check expected
575			} else if (gbp->p->gbpTxPosition >= 12) {
576				uint32_t mask = 0x33;
577				// 0x00 = Stop
578				// 0x11 = Hard Stop
579				// 0x22 = Start
580				if (gbp->p->p->rumble) {
581					gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == 0x22);
582				}
583			}
584			mTimingDeschedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent);
585			mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048);
586		}
587		value &= 0x78FB;
588	}
589	return value;
590}
591
592void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
593	UNUSED(timing);
594	UNUSED(cyclesLate);
595	struct GBAGBPSIODriver* gbp = user;
596	uint32_t tx = 0;
597	int txPosition = gbp->p->gbpTxPosition;
598	if (txPosition > 16) {
599		gbp->p->gbpTxPosition = 0;
600		txPosition = 0;
601	} else if (txPosition > 12) {
602		txPosition = 12;
603	}
604	tx = _gbpTxData[txPosition];
605	++gbp->p->gbpTxPosition;
606	gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
607	gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
608	if (GBASIONormalIsIrq(gbp->d.p->siocnt)) {
609		GBARaiseIRQ(gbp->p->p, IRQ_SIO, cyclesLate);
610	}
611	gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt);
612	gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
613}
614
615// == Serialization
616
617void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
618	GBASerializedHWFlags1 flags1 = 0;
619	GBASerializedHWFlags2 flags2 = 0;
620	flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite);
621	STORE_16(hw->pinState, 0, &state->hw.pinState);
622	STORE_16(hw->direction, 0, &state->hw.pinDirection);
623	state->hw.devices = hw->devices;
624
625	STORE_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining);
626	STORE_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep);
627	STORE_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead);
628	STORE_32(hw->rtc.bits, 0, &state->hw.rtc.bits);
629	STORE_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive);
630	STORE_32(hw->rtc.command, 0, &state->hw.rtc.command);
631	STORE_32(hw->rtc.control, 0, &state->hw.rtc.control);
632	memcpy(state->hw.rtc.time, hw->rtc.time, sizeof(state->hw.rtc.time));
633
634	STORE_16(hw->gyroSample, 0, &state->hw.gyroSample);
635	flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge);
636	STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX);
637	STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY);
638	flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
639	flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
640	state->hw.lightSample = hw->lightSample;
641	flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge);
642	flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted);
643	flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition);
644	STORE_32(hw->gbpNextEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
645	STORE_16(flags1, 0, &state->hw.flags1);
646	state->hw.flags2 = flags2;
647}
648
649void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) {
650	GBASerializedHWFlags1 flags1;
651	LOAD_16(flags1, 0, &state->hw.flags1);
652	hw->readWrite = GBASerializedHWFlags1GetReadWrite(flags1);
653	LOAD_16(hw->pinState, 0, &state->hw.pinState);
654	LOAD_16(hw->direction, 0, &state->hw.pinDirection);
655	hw->devices = state->hw.devices;
656
657	LOAD_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining);
658	LOAD_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep);
659	LOAD_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead);
660	LOAD_32(hw->rtc.bits, 0, &state->hw.rtc.bits);
661	LOAD_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive);
662	LOAD_32(hw->rtc.command, 0, &state->hw.rtc.command);
663	LOAD_32(hw->rtc.control, 0, &state->hw.rtc.control);
664	memcpy(hw->rtc.time, state->hw.rtc.time, sizeof(hw->rtc.time));
665
666	LOAD_16(hw->gyroSample, 0, &state->hw.gyroSample);
667	hw->gyroEdge = GBASerializedHWFlags1GetGyroEdge(flags1);
668	LOAD_16(hw->tiltX, 0, &state->hw.tiltSampleX);
669	LOAD_16(hw->tiltY, 0, &state->hw.tiltSampleY);
670	hw->tiltState = GBASerializedHWFlags2GetTiltState(state->hw.flags2);
671	hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1);
672	hw->lightSample = state->hw.lightSample;
673	hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1);
674	hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
675	hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
676
677	uint32_t when;
678	LOAD_32(when, 0, &state->hw.gbpNextEvent);
679	if (hw->devices & HW_GB_PLAYER) {
680		GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32);
681		if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) {
682			mTimingSchedule(&hw->p->timing, &hw->gbpNextEvent, when);
683		}
684	}
685}