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