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