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
14mLOG_DEFINE_CATEGORY(GBA_HW, "GBA Pak Hardware", "gba.hardware");
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 void _rtcUpdateClock(struct GBARTC* rtc, struct mRTCSource*);
23static unsigned _rtcBCD(unsigned value);
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 mKeyCallback*);
32static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
33static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
34
35static const int RTC_BYTES[8] = {
36 1, // Status register 1
37 1, // Duty/alarm 1
38 7, // Date/Time
39 1, // Force IRQ
40 1, // Status register 2
41 3, // Alarm 2
42 3, // Time
43 1 // Free register
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.p = hw;
58 hw->gbpNextEvent.context = &hw->gbpDriver;
59 hw->gbpNextEvent.name = "GBA SIO Game Boy Player";
60 hw->gbpNextEvent.callback = _gbpSioProcessEvents;
61 hw->gbpNextEvent.priority = 0x80;
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 if (!hw->gpioBase) {
77 return;
78 }
79 switch (address) {
80 case GPIO_REG_DATA:
81 hw->pinState &= ~hw->direction;
82 hw->pinState |= value;
83 _readPins(hw);
84 break;
85 case GPIO_REG_DIRECTION:
86 hw->direction = value;
87 break;
88 case GPIO_REG_CONTROL:
89 hw->readWrite = value;
90 break;
91 default:
92 mLOG(GBA_HW, WARN, "Invalid GPIO address");
93 }
94 if (hw->readWrite) {
95 uint16_t old;
96 LOAD_16(old, 0, hw->gpioBase);
97 old &= ~hw->direction;
98 old |= hw->pinState;
99 STORE_16(old, 0, hw->gpioBase);
100 } else {
101 hw->gpioBase[0] = 0;
102 }
103}
104
105void GBAHardwareInitRTC(struct GBACartridgeHardware* hw) {
106 hw->devices |= HW_RTC;
107 hw->rtc.bytesRemaining = 0;
108
109 hw->rtc.transferStep = 0;
110
111 hw->rtc.bitsRead = 0;
112 hw->rtc.bits = 0;
113 hw->rtc.commandActive = 0;
114 hw->rtc.command = 0;
115 hw->rtc.control = 0x40;
116 hw->rtc.freeReg = 0;
117 hw->rtc.status2 = 0;
118 memset(hw->rtc.time, 0, sizeof(hw->rtc.time));
119}
120
121void _readPins(struct GBACartridgeHardware* hw) {
122 if (hw->devices & HW_RTC) {
123 _rtcReadPins(hw);
124 }
125
126 if (hw->devices & HW_GYRO) {
127 _gyroReadPins(hw);
128 }
129
130 if (hw->devices & HW_RUMBLE) {
131 _rumbleReadPins(hw);
132 }
133
134 if (hw->devices & HW_LIGHT_SENSOR) {
135 _lightReadPins(hw);
136 }
137}
138
139void _outputPins(struct GBACartridgeHardware* hw, unsigned pins) {
140 if (hw->readWrite) {
141 uint16_t old;
142 LOAD_16(old, 0, hw->gpioBase);
143 old &= hw->direction;
144 hw->pinState = old | (pins & ~hw->direction & 0xF);
145 STORE_16(hw->pinState, 0, hw->gpioBase);
146 }
147}
148
149// == RTC
150
151void _rtcReadPins(struct GBACartridgeHardware* hw) {
152 // Transfer sequence:
153 // P: 0 | 1 | 2 | 3
154 // == Initiate
155 // > HI | - | LO | -
156 // > HI | - | HI | -
157 // == Transfer bit (x8)
158 // > LO | x | HI | -
159 // > HI | - | HI | -
160 // < ?? | x | ?? | -
161 // == Terminate
162 // > - | - | LO | -
163 switch (hw->rtc.transferStep) {
164 case 0:
165 if ((hw->pinState & 5) == 1) {
166 hw->rtc.transferStep = 1;
167 }
168 break;
169 case 1:
170 if ((hw->pinState & 5) == 5) {
171 hw->rtc.transferStep = 2;
172 }
173 break;
174 case 2:
175 if (!(hw->pinState & 1)) {
176 hw->rtc.bits &= ~(1 << hw->rtc.bitsRead);
177 hw->rtc.bits |= ((hw->pinState & 2) >> 1) << hw->rtc.bitsRead;
178 } else {
179 if (hw->pinState & 4) {
180 // GPIO direction should always != reading
181 if (hw->direction & 2) {
182 if (RTCCommandDataIsReading(hw->rtc.command)) {
183 mLOG(GBA_HW, GAME_ERROR, "Attempting to write to RTC while in read mode");
184 }
185 ++hw->rtc.bitsRead;
186 if (hw->rtc.bitsRead == 8) {
187 GBARTCProcessByte(&hw->rtc, hw->p->rtcSource);
188 }
189 } else {
190 _outputPins(hw, 5 | (GBARTCOutput(&hw->rtc) << 1));
191 ++hw->rtc.bitsRead;
192 if (hw->rtc.bitsRead == 8) {
193 --hw->rtc.bytesRemaining;
194 if (hw->rtc.bytesRemaining <= 0) {
195 hw->rtc.commandActive = 0;
196 hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command);
197 }
198 hw->rtc.bitsRead = 0;
199 }
200 }
201 } else {
202 hw->rtc.bitsRead = 0;
203 hw->rtc.bytesRemaining = 0;
204 hw->rtc.commandActive = 0;
205 hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command);
206 hw->rtc.transferStep = 0;
207 }
208 }
209 break;
210 }
211}
212
213void GBARTCProcessByte(struct GBARTC* rtc, struct mRTCSource* source) {
214 --rtc->bytesRemaining;
215 if (!rtc->commandActive) {
216 RTCCommandData command;
217 command = rtc->bits;
218 if (RTCCommandDataGetMagic(command) == 0x06) {
219 rtc->command = command;
220
221 rtc->bytesRemaining = RTC_BYTES[RTCCommandDataGetCommand(command)];
222 rtc->commandActive = rtc->bytesRemaining > 0;
223 switch (RTCCommandDataGetCommand(command)) {
224 case RTC_DATETIME:
225 case RTC_TIME:
226 _rtcUpdateClock(rtc, source);
227 break;
228 case RTC_FORCE_IRQ:
229 break;
230 case RTC_ALARM1:
231 if (RTCStatus2GetINT1(rtc->status2) == 4) {
232 rtc->bytesRemaining = 3;
233 }
234 }
235 } else {
236 mLOG(GBA_HW, WARN, "Invalid RTC command byte: %02X", rtc->bits);
237 }
238 } else {
239 switch (RTCCommandDataGetCommand(rtc->command)) {
240 case RTC_STATUS1:
241 rtc->control = rtc->bits & 0xFE;
242 break;
243 case RTC_FORCE_IRQ:
244 mLOG(GBA_HW, STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(rtc->command));
245 break;
246 case RTC_STATUS2:
247 rtc->status2 = rtc->bits;
248 break;
249 case RTC_FREE_REG:
250 rtc->freeReg = rtc->bits;
251 break;
252 case RTC_DATETIME:
253 case RTC_TIME:
254 break;
255 case RTC_ALARM1:
256 case RTC_ALARM2:
257 mLOG(GBA_HW, STUB, "Unimplemented RTC command %u:%02X", RTCCommandDataGetCommand(rtc->command), rtc->bits);
258 break;
259 }
260 }
261
262 rtc->bits = 0;
263 rtc->bitsRead = 0;
264 if (!rtc->bytesRemaining) {
265 rtc->commandActive = 0;
266 rtc->command = RTCCommandDataClearReading(rtc->command);
267 }
268}
269
270unsigned GBARTCOutput(struct GBARTC* rtc) {
271 uint8_t outputByte = 0;
272 switch (RTCCommandDataGetCommand(rtc->command)) {
273 case RTC_STATUS1:
274 outputByte = rtc->control;
275 break;
276 case RTC_STATUS2:
277 outputByte = rtc->status2;
278 break;
279 case RTC_DATETIME:
280 case RTC_TIME:
281 outputByte = rtc->time[7 - rtc->bytesRemaining];
282 break;
283 case RTC_FREE_REG:
284 outputByte = rtc->freeReg;
285 case RTC_FORCE_IRQ:
286 case RTC_ALARM1:
287 case RTC_ALARM2:
288 mLOG(GBA_HW, STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(rtc->command));
289 break;
290 }
291 unsigned output = (outputByte >> rtc->bitsRead) & 1;
292 return output;
293}
294
295void _rtcUpdateClock(struct GBARTC* rtc, struct mRTCSource* source) {
296 time_t t;
297 if (source) {
298 if (source->sample) {
299 source->sample(source);
300 }
301 t = source->unixTime(source);
302 } else {
303 t = time(0);
304 }
305 struct tm date;
306 localtime_r(&t, &date);
307 rtc->time[0] = _rtcBCD(date.tm_year - 100);
308 rtc->time[1] = _rtcBCD(date.tm_mon + 1);
309 rtc->time[2] = _rtcBCD(date.tm_mday);
310 rtc->time[3] = _rtcBCD(date.tm_wday);
311 if (RTCControlIsHour24(rtc->control)) {
312 rtc->time[4] = _rtcBCD(date.tm_hour);
313 } else {
314 rtc->time[4] = _rtcBCD(date.tm_hour % 12);
315 rtc->time[4] |= (date.tm_hour >= 12) ? 0xC0 : 0;
316 }
317 rtc->time[5] = _rtcBCD(date.tm_min);
318 rtc->time[6] = _rtcBCD(date.tm_sec);
319}
320
321unsigned _rtcBCD(unsigned value) {
322 int counter = value % 10;
323 value /= 10;
324 counter += (value % 10) << 4;
325 return counter;
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
497bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) {
498 if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
499 return false;
500 }
501 uint32_t hash = hash32(&video->vram[0x4000], 0x4000, 0);
502 return hash == _logoHash;
503}
504
505void GBAHardwarePlayerUpdate(struct GBA* gba) {
506 if (gba->memory.hw.devices & HW_GB_PLAYER) {
507 if (GBAHardwarePlayerCheckScreen(&gba->video)) {
508 ++gba->memory.hw.gbpInputsPosted;
509 gba->memory.hw.gbpInputsPosted %= 3;
510 gba->keyCallback = &gba->memory.hw.gbpCallback.d;
511 } else {
512 // TODO: Save and restore
513 gba->keyCallback = 0;
514 }
515 gba->memory.hw.gbpTxPosition = 0;
516 return;
517 }
518 if (gba->keyCallback || gba->sio.drivers.normal) {
519 return;
520 }
521 if (GBAHardwarePlayerCheckScreen(&gba->video)) {
522 gba->memory.hw.devices |= HW_GB_PLAYER;
523 gba->memory.hw.gbpInputsPosted = 0;
524 gba->keyCallback = &gba->memory.hw.gbpCallback.d;
525 GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32);
526 }
527}
528
529uint16_t _gbpRead(struct mKeyCallback* callback) {
530 struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback;
531 if (gbpCallback->p->gbpInputsPosted == 2) {
532 return 0x30F;
533 }
534 return 0x3FF;
535}
536
537uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
538 struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver;
539 if (address == REG_SIOCNT) {
540 if (value & 0x0080) {
541 uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16);
542 if (gbp->p->gbpTxPosition < 12 && gbp->p->gbpTxPosition > 0) {
543 // TODO: Check expected
544 } else if (gbp->p->gbpTxPosition >= 12) {
545 uint32_t mask = 0x33;
546 // 0x00 = Stop
547 // 0x11 = Hard Stop
548 // 0x22 = Start
549 if (gbp->p->p->rumble) {
550 gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == 0x22);
551 }
552 }
553 mTimingDeschedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent);
554 mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048);
555 }
556 value &= 0x78FB;
557 }
558 return value;
559}
560
561void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
562 UNUSED(timing);
563 UNUSED(cyclesLate);
564 struct GBAGBPSIODriver* gbp = user;
565 uint32_t tx = 0;
566 int txPosition = gbp->p->gbpTxPosition;
567 if (txPosition > 16) {
568 gbp->p->gbpTxPosition = 0;
569 txPosition = 0;
570 } else if (txPosition > 12) {
571 txPosition = 12;
572 }
573 tx = _gbpTxData[txPosition];
574 ++gbp->p->gbpTxPosition;
575 gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
576 gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
577 if (gbp->d.p->normalControl.irq) {
578 GBARaiseIRQ(gbp->p->p, IRQ_SIO);
579 }
580 gbp->d.p->normalControl.start = 0;
581 gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
582}
583
584// == Serialization
585
586void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
587 GBASerializedHWFlags1 flags1 = 0;
588 GBASerializedHWFlags2 flags2 = 0;
589 flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite);
590 STORE_16(hw->pinState, 0, &state->hw.pinState);
591 STORE_16(hw->direction, 0, &state->hw.pinDirection);
592 state->hw.devices = hw->devices;
593
594 STORE_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining);
595 STORE_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep);
596 STORE_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead);
597 STORE_32(hw->rtc.bits, 0, &state->hw.rtc.bits);
598 state->hw.rtc.commandActive = hw->rtc.commandActive;
599 state->hw.rtc.command = hw->rtc.command;
600 state->hw.rtc.control = hw->rtc.control;
601 memcpy(state->hw.rtc.time, hw->rtc.time, sizeof(state->hw.rtc.time));
602
603 STORE_16(hw->gyroSample, 0, &state->hw.gyroSample);
604 flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge);
605 STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX);
606 STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY);
607 flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
608 flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
609 state->hw.lightSample = hw->lightSample;
610 flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge);
611 flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted);
612 flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition);
613 STORE_32(hw->gbpNextEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
614 STORE_16(flags1, 0, &state->hw.flags1);
615 state->hw.flags2 = flags2;
616}
617
618void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) {
619 GBASerializedHWFlags1 flags1;
620 LOAD_16(flags1, 0, &state->hw.flags1);
621 hw->readWrite = GBASerializedHWFlags1GetReadWrite(flags1);
622 LOAD_16(hw->pinState, 0, &state->hw.pinState);
623 LOAD_16(hw->direction, 0, &state->hw.pinDirection);
624 hw->devices = state->hw.devices;
625
626 LOAD_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining);
627 LOAD_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep);
628 LOAD_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead);
629 LOAD_32(hw->rtc.bits, 0, &state->hw.rtc.bits);
630 hw->rtc.commandActive = state->hw.rtc.commandActive;
631 hw->rtc.command = state->hw.rtc.command;
632 hw->rtc.control = state->hw.rtc.control;
633 memcpy(hw->rtc.time, state->hw.rtc.time, sizeof(hw->rtc.time));
634
635 LOAD_16(hw->gyroSample, 0, &state->hw.gyroSample);
636 hw->gyroEdge = GBASerializedHWFlags1GetGyroEdge(flags1);
637 LOAD_16(hw->tiltX, 0, &state->hw.tiltSampleX);
638 LOAD_16(hw->tiltY, 0, &state->hw.tiltSampleY);
639 hw->tiltState = GBASerializedHWFlags2GetTiltState(state->hw.flags2);
640 hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1);
641 hw->lightSample = state->hw.lightSample;
642 hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1);
643 hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
644 hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
645
646 uint32_t when;
647 LOAD_32(when, 0, &state->hw.gbpNextEvent);
648 if (hw->devices & HW_GB_PLAYER) {
649 GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32);
650 if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) {
651 mTimingSchedule(&hw->p->timing, &hw->gbpNextEvent, when);
652 }
653 }
654}