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