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