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