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 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 mRTCSource* 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 mKeyCallback*);
36static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
37static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
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.p = hw;
62 hw->gbpNextEvent.context = &hw->gbpDriver;
63 hw->gbpNextEvent.name = "GBA SIO Game Boy Player";
64 hw->gbpNextEvent.callback = _gbpSioProcessEvents;
65 hw->gbpNextEvent.priority = 0x80;
66}
67
68void GBAHardwareClear(struct GBACartridgeHardware* hw) {
69 hw->devices = HW_NONE | (hw->devices & HW_GB_PLAYER_DETECTION);
70 hw->readWrite = GPIO_WRITE_ONLY;
71 hw->pinState = 0;
72 hw->direction = 0;
73
74 if (hw->p->sio.drivers.normal == &hw->gbpDriver.d) {
75 GBASIOSetDriver(&hw->p->sio, 0, SIO_NORMAL_32);
76 }
77}
78
79void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) {
80 if (!hw->gpioBase) {
81 return;
82 }
83 switch (address) {
84 case GPIO_REG_DATA:
85 hw->pinState &= ~hw->direction;
86 hw->pinState |= value & hw->direction;
87 _readPins(hw);
88 break;
89 case GPIO_REG_DIRECTION:
90 hw->direction = value;
91 break;
92 case GPIO_REG_CONTROL:
93 hw->readWrite = value;
94 break;
95 default:
96 mLOG(GBA_HW, WARN, "Invalid GPIO address");
97 }
98 if (hw->readWrite) {
99 STORE_16(hw->pinState, 0, hw->gpioBase);
100 STORE_16(hw->direction, 2, hw->gpioBase);
101 STORE_16(hw->readWrite, 4, hw->gpioBase);
102 } else {
103 hw->gpioBase[0] = 0;
104 hw->gpioBase[1] = 0;
105 hw->gpioBase[2] = 0;
106 }
107}
108
109void GBAHardwareInitRTC(struct GBACartridgeHardware* hw) {
110 hw->devices |= HW_RTC;
111 hw->rtc.bytesRemaining = 0;
112
113 hw->rtc.transferStep = 0;
114
115 hw->rtc.bitsRead = 0;
116 hw->rtc.bits = 0;
117 hw->rtc.commandActive = 0;
118 hw->rtc.command = 0;
119 hw->rtc.control = 0x40;
120 memset(hw->rtc.time, 0, sizeof(hw->rtc.time));
121}
122
123void _readPins(struct GBACartridgeHardware* hw) {
124 if (hw->devices & HW_RTC) {
125 _rtcReadPins(hw);
126 }
127
128 if (hw->devices & HW_GYRO) {
129 _gyroReadPins(hw);
130 }
131
132 if (hw->devices & HW_RUMBLE) {
133 _rumbleReadPins(hw);
134 }
135
136 if (hw->devices & HW_LIGHT_SENSOR) {
137 _lightReadPins(hw);
138 }
139}
140
141void _outputPins(struct GBACartridgeHardware* hw, unsigned pins) {
142 if (hw->readWrite) {
143 uint16_t old;
144 LOAD_16(old, 0, hw->gpioBase);
145 old &= hw->direction;
146 hw->pinState = old | (pins & ~hw->direction & 0xF);
147 STORE_16(hw->pinState, 0, hw->gpioBase);
148 }
149}
150
151// == RTC
152
153void _rtcReadPins(struct GBACartridgeHardware* hw) {
154 // Transfer sequence:
155 // P: 0 | 1 | 2 | 3
156 // == Initiate
157 // > HI | - | LO | -
158 // > HI | - | HI | -
159 // == Transfer bit (x8)
160 // > LO | x | HI | -
161 // > HI | - | HI | -
162 // < ?? | x | ?? | -
163 // == Terminate
164 // > - | - | LO | -
165 switch (hw->rtc.transferStep) {
166 case 0:
167 if ((hw->pinState & 5) == 1) {
168 hw->rtc.transferStep = 1;
169 }
170 _outputPins(hw, 1);
171 break;
172 case 1:
173 if ((hw->pinState & 5) == 5) {
174 hw->rtc.transferStep = 2;
175 } else {
176 hw->rtc.transferStep = 0;
177 }
178 _outputPins(hw, 5);
179 break;
180 case 2:
181 if (!(hw->pinState & 1)) {
182 hw->rtc.bits &= ~(1 << hw->rtc.bitsRead);
183 hw->rtc.bits |= ((hw->pinState & 2) >> 1) << hw->rtc.bitsRead;
184 } else {
185 if (hw->pinState & 4) {
186 if (!RTCCommandDataIsReading(hw->rtc.command)) {
187 ++hw->rtc.bitsRead;
188 if (hw->rtc.bitsRead == 8) {
189 _rtcProcessByte(hw);
190 }
191 } else {
192 _outputPins(hw, 5 | (_rtcOutput(hw) << 1));
193 ++hw->rtc.bitsRead;
194 if (hw->rtc.bitsRead == 8) {
195 --hw->rtc.bytesRemaining;
196 if (hw->rtc.bytesRemaining <= 0) {
197 hw->rtc.commandActive = 0;
198 hw->rtc.command = 0;
199 }
200 hw->rtc.bitsRead = 0;
201 }
202 }
203 } else {
204 hw->rtc.bitsRead = 0;
205 hw->rtc.bytesRemaining = 0;
206 hw->rtc.commandActive = 0;
207 hw->rtc.command = 0;
208 hw->rtc.transferStep = hw->pinState & 1;
209 _outputPins(hw, 1);
210 }
211 }
212 break;
213 }
214}
215
216void _rtcProcessByte(struct GBACartridgeHardware* hw) {
217 --hw->rtc.bytesRemaining;
218 if (!hw->rtc.commandActive) {
219 RTCCommandData command;
220 command = hw->rtc.bits;
221 if (RTCCommandDataGetMagic(command) == 0x06) {
222 hw->rtc.command = command;
223
224 hw->rtc.bytesRemaining = RTC_BYTES[RTCCommandDataGetCommand(command)];
225 hw->rtc.commandActive = hw->rtc.bytesRemaining > 0;
226 switch (RTCCommandDataGetCommand(command)) {
227 case RTC_RESET:
228 hw->rtc.control = 0;
229 break;
230 case RTC_DATETIME:
231 case RTC_TIME:
232 _rtcUpdateClock(hw);
233 break;
234 case RTC_FORCE_IRQ:
235 case RTC_CONTROL:
236 break;
237 }
238 } else {
239 mLOG(GBA_HW, WARN, "Invalid RTC command byte: %02X", hw->rtc.bits);
240 }
241 } else {
242 switch (RTCCommandDataGetCommand(hw->rtc.command)) {
243 case RTC_CONTROL:
244 hw->rtc.control = hw->rtc.bits;
245 break;
246 case RTC_FORCE_IRQ:
247 mLOG(GBA_HW, STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(hw->rtc.command));
248 break;
249 case RTC_RESET:
250 case RTC_DATETIME:
251 case RTC_TIME:
252 break;
253 }
254 }
255
256 hw->rtc.bits = 0;
257 hw->rtc.bitsRead = 0;
258 if (!hw->rtc.bytesRemaining) {
259 hw->rtc.commandActive = 0;
260 hw->rtc.command = 0;
261 }
262}
263
264unsigned _rtcOutput(struct GBACartridgeHardware* hw) {
265 uint8_t outputByte = 0;
266 if (!hw->rtc.commandActive) {
267 mLOG(GBA_HW, GAME_ERROR, "Attempting to use RTC without an active command");
268 return 0;
269 }
270 switch (RTCCommandDataGetCommand(hw->rtc.command)) {
271 case RTC_CONTROL:
272 outputByte = hw->rtc.control;
273 break;
274 case RTC_DATETIME:
275 case RTC_TIME:
276 outputByte = hw->rtc.time[7 - hw->rtc.bytesRemaining];
277 break;
278 case RTC_FORCE_IRQ:
279 case RTC_RESET:
280 break;
281 }
282 unsigned output = (outputByte >> hw->rtc.bitsRead) & 1;
283 return output;
284}
285
286void _rtcUpdateClock(struct GBACartridgeHardware* hw) {
287 time_t t;
288 struct mRTCSource* rtc = hw->p->rtcSource;
289 if (rtc) {
290 if (rtc->sample) {
291 rtc->sample(rtc);
292 }
293 t = rtc->unixTime(rtc);
294 } else {
295 t = time(0);
296 }
297 struct tm date;
298 localtime_r(&t, &date);
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 mRTCSource* 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 mRotationSource* 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 mRumble* 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 mLOG(GBA_HW, 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 mLOG(GBA_HW, 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 mLOG(GBA_HW, 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 mRotationSource* 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 mLOG(GBA_HW, GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value);
459 }
460 break;
461 default:
462 mLOG(GBA_HW, 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 mLOG(GBA_HW, 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
507};
508
509bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) {
510 if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
511 return false;
512 }
513 uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0);
514 return hash == _logoHash;
515}
516
517void GBAHardwarePlayerUpdate(struct GBA* gba) {
518 if (gba->memory.hw.devices & HW_GB_PLAYER) {
519 if (GBAHardwarePlayerCheckScreen(&gba->video)) {
520 ++gba->memory.hw.gbpInputsPosted;
521 gba->memory.hw.gbpInputsPosted %= 3;
522 gba->keyCallback = &gba->memory.hw.gbpCallback.d;
523 } else {
524 // TODO: Save and restore
525 gba->keyCallback = 0;
526 }
527 gba->memory.hw.gbpTxPosition = 0;
528 return;
529 }
530 if (gba->keyCallback || gba->sio.drivers.normal) {
531 return;
532 }
533 if (GBAHardwarePlayerCheckScreen(&gba->video)) {
534 gba->memory.hw.devices |= HW_GB_PLAYER;
535 gba->memory.hw.gbpInputsPosted = 0;
536 gba->keyCallback = &gba->memory.hw.gbpCallback.d;
537 GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32);
538 }
539}
540
541uint16_t _gbpRead(struct mKeyCallback* callback) {
542 struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback;
543 if (gbpCallback->p->gbpInputsPosted == 2) {
544 return 0x30F;
545 }
546 return 0x3FF;
547}
548
549uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
550 struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver;
551 if (address == REG_SIOCNT) {
552 if (value & 0x0080) {
553 uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16);
554 if (gbp->p->gbpTxPosition < 12 && gbp->p->gbpTxPosition > 0) {
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 mTimingDeschedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent);
566 mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048);
567 }
568 value &= 0x78FB;
569 }
570 return value;
571}
572
573void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
574 UNUSED(timing);
575 UNUSED(cyclesLate);
576 struct GBAGBPSIODriver* gbp = user;
577 uint32_t tx = 0;
578 int txPosition = gbp->p->gbpTxPosition;
579 if (txPosition > 16) {
580 gbp->p->gbpTxPosition = 0;
581 txPosition = 0;
582 } else if (txPosition > 12) {
583 txPosition = 12;
584 }
585 tx = _gbpTxData[txPosition];
586 ++gbp->p->gbpTxPosition;
587 gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
588 gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
589 if (gbp->d.p->normalControl.irq) {
590 GBARaiseIRQ(gbp->p->p, IRQ_SIO);
591 }
592 gbp->d.p->normalControl.start = 0;
593 gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
594}
595
596// == Serialization
597
598void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
599 GBASerializedHWFlags1 flags1 = 0;
600 GBASerializedHWFlags2 flags2 = 0;
601 flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite);
602 STORE_16(hw->pinState, 0, &state->hw.pinState);
603 STORE_16(hw->direction, 0, &state->hw.pinDirection);
604 state->hw.devices = hw->devices;
605
606 STORE_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining);
607 STORE_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep);
608 STORE_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead);
609 STORE_32(hw->rtc.bits, 0, &state->hw.rtc.bits);
610 STORE_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive);
611 STORE_32(hw->rtc.command, 0, &state->hw.rtc.command);
612 STORE_32(hw->rtc.control, 0, &state->hw.rtc.control);
613 memcpy(state->hw.rtc.time, hw->rtc.time, sizeof(state->hw.rtc.time));
614
615 STORE_16(hw->gyroSample, 0, &state->hw.gyroSample);
616 flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge);
617 STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX);
618 STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY);
619 flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
620 flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
621 state->hw.lightSample = hw->lightSample;
622 flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge);
623 flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted);
624 flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition);
625 STORE_32(hw->gbpNextEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
626 STORE_16(flags1, 0, &state->hw.flags1);
627 state->hw.flags2 = flags2;
628}
629
630void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) {
631 GBASerializedHWFlags1 flags1;
632 LOAD_16(flags1, 0, &state->hw.flags1);
633 hw->readWrite = GBASerializedHWFlags1GetReadWrite(flags1);
634 LOAD_16(hw->pinState, 0, &state->hw.pinState);
635 LOAD_16(hw->direction, 0, &state->hw.pinDirection);
636 hw->devices = state->hw.devices;
637
638 LOAD_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining);
639 LOAD_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep);
640 LOAD_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead);
641 LOAD_32(hw->rtc.bits, 0, &state->hw.rtc.bits);
642 LOAD_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive);
643 LOAD_32(hw->rtc.command, 0, &state->hw.rtc.command);
644 LOAD_32(hw->rtc.control, 0, &state->hw.rtc.control);
645 memcpy(hw->rtc.time, state->hw.rtc.time, sizeof(hw->rtc.time));
646
647 LOAD_16(hw->gyroSample, 0, &state->hw.gyroSample);
648 hw->gyroEdge = GBASerializedHWFlags1GetGyroEdge(flags1);
649 LOAD_16(hw->tiltX, 0, &state->hw.tiltSampleX);
650 LOAD_16(hw->tiltY, 0, &state->hw.tiltSampleY);
651 hw->tiltState = GBASerializedHWFlags2GetTiltState(state->hw.flags2);
652 hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1);
653 hw->lightSample = state->hw.lightSample;
654 hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1);
655 hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
656 hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
657
658 uint32_t when;
659 LOAD_32(when, 0, &state->hw.gbpNextEvent);
660 if (hw->devices & HW_GB_PLAYER) {
661 GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32);
662 if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) {
663 mTimingSchedule(&hw->p->timing, &hw->gbpNextEvent, when);
664 }
665 }
666}