all repos — mgba @ 3ccffdc29eab88906a6cbb9d686f474261da4e16

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