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