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}