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