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