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