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 "hardware.h"
7
8#include "gba/io.h"
9#include "gba/serialize.h"
10#include "util/formatting.h"
11#include "util/hash.h"
12
13mLOG_DEFINE_CATEGORY(GBA_HW, "GBA Pak Hardware");
14
15const int GBA_LUX_LEVELS[10] = { 5, 11, 18, 27, 42, 62, 84, 109, 139, 183 };
16
17static void _readPins(struct GBACartridgeHardware* hw);
18static void _outputPins(struct GBACartridgeHardware* hw, unsigned pins);
19
20static void _rtcReadPins(struct GBACartridgeHardware* hw);
21static unsigned _rtcOutput(struct GBACartridgeHardware* hw);
22static void _rtcProcessByte(struct GBACartridgeHardware* hw);
23static void _rtcUpdateClock(struct GBACartridgeHardware* hw);
24static unsigned _rtcBCD(unsigned value);
25
26static time_t _rtcGenericCallback(struct mRTCSource* source);
27
28static void _gyroReadPins(struct GBACartridgeHardware* hw);
29
30static void _rumbleReadPins(struct GBACartridgeHardware* hw);
31
32static void _lightReadPins(struct GBACartridgeHardware* hw);
33
34static uint16_t _gbpRead(struct mKeyCallback*);
35static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
36static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
37
38static const int RTC_BYTES[8] = {
39 0, // Force reset
40 0, // Empty
41 7, // Date/Time
42 0, // Force IRQ
43 1, // Control register
44 0, // Empty
45 3, // Time
46 0 // Empty
47};
48
49void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) {
50 hw->gpioBase = base;
51 GBAHardwareClear(hw);
52
53 hw->gbpCallback.d.readKeys = _gbpRead;
54 hw->gbpCallback.p = hw;
55 hw->gbpDriver.d.init = 0;
56 hw->gbpDriver.d.deinit = 0;
57 hw->gbpDriver.d.load = 0;
58 hw->gbpDriver.d.unload = 0;
59 hw->gbpDriver.d.writeRegister = _gbpSioWriteRegister;
60 hw->gbpDriver.p = hw;
61 hw->gbpNextEvent.context = &hw->gbpDriver;
62 hw->gbpNextEvent.name = "GBA SIO Game Boy Player";
63 hw->gbpNextEvent.callback = _gbpSioProcessEvents;
64 hw->gbpNextEvent.priority = 0x80;
65}
66
67void GBAHardwareClear(struct GBACartridgeHardware* hw) {
68 hw->devices = HW_NONE | (hw->devices & HW_GB_PLAYER_DETECTION);
69 hw->direction = GPIO_WRITE_ONLY;
70 hw->pinState = 0;
71 hw->direction = 0;
72
73 if (hw->p->sio.drivers.normal == &hw->gbpDriver.d) {
74 GBASIOSetDriver(&hw->p->sio, 0, SIO_NORMAL_32);
75 }
76}
77
78void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) {
79 switch (address) {
80 case GPIO_REG_DATA:
81 hw->pinState &= ~hw->direction;
82 hw->pinState |= value;
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 uint16_t old;
96 LOAD_16(old, 0, hw->gpioBase);
97 old &= ~hw->direction;
98 old |= hw->pinState;
99 STORE_16(old, 0, hw->gpioBase);
100 } else {
101 hw->gpioBase[0] = 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 memset(hw->rtc.time, 0, sizeof(hw->rtc.time));
117}
118
119void _readPins(struct GBACartridgeHardware* hw) {
120 if (hw->devices & HW_RTC) {
121 _rtcReadPins(hw);
122 }
123
124 if (hw->devices & HW_GYRO) {
125 _gyroReadPins(hw);
126 }
127
128 if (hw->devices & HW_RUMBLE) {
129 _rumbleReadPins(hw);
130 }
131
132 if (hw->devices & HW_LIGHT_SENSOR) {
133 _lightReadPins(hw);
134 }
135}
136
137void _outputPins(struct GBACartridgeHardware* hw, unsigned pins) {
138 if (hw->readWrite) {
139 uint16_t old;
140 LOAD_16(old, 0, hw->gpioBase);
141 old &= hw->direction;
142 hw->pinState = old | (pins & ~hw->direction & 0xF);
143 STORE_16(hw->pinState, 0, hw->gpioBase);
144 }
145}
146
147// == RTC
148
149void _rtcReadPins(struct GBACartridgeHardware* hw) {
150 // Transfer sequence:
151 // P: 0 | 1 | 2 | 3
152 // == Initiate
153 // > HI | - | LO | -
154 // > HI | - | HI | -
155 // == Transfer bit (x8)
156 // > LO | x | HI | -
157 // > HI | - | HI | -
158 // < ?? | x | ?? | -
159 // == Terminate
160 // > - | - | LO | -
161 switch (hw->rtc.transferStep) {
162 case 0:
163 if ((hw->pinState & 5) == 1) {
164 hw->rtc.transferStep = 1;
165 }
166 break;
167 case 1:
168 if ((hw->pinState & 5) == 5) {
169 hw->rtc.transferStep = 2;
170 }
171 break;
172 case 2:
173 if (!(hw->pinState & 1)) {
174 hw->rtc.bits &= ~(1 << hw->rtc.bitsRead);
175 hw->rtc.bits |= ((hw->pinState & 2) >> 1) << hw->rtc.bitsRead;
176 } else {
177 if (hw->pinState & 4) {
178 // GPIO direction should always != reading
179 if (hw->direction & 2) {
180 if (RTCCommandDataIsReading(hw->rtc.command)) {
181 mLOG(GBA_HW, GAME_ERROR, "Attempting to write to RTC while in read mode");
182 }
183 ++hw->rtc.bitsRead;
184 if (hw->rtc.bitsRead == 8) {
185 _rtcProcessByte(hw);
186 }
187 } else {
188 _outputPins(hw, 5 | (_rtcOutput(hw) << 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 = RTCCommandDataClearReading(hw->rtc.command);
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 = RTCCommandDataClearReading(hw->rtc.command);
204 hw->rtc.transferStep = 0;
205 }
206 }
207 break;
208 }
209}
210
211void _rtcProcessByte(struct GBACartridgeHardware* hw) {
212 --hw->rtc.bytesRemaining;
213 if (!hw->rtc.commandActive) {
214 RTCCommandData command;
215 command = hw->rtc.bits;
216 if (RTCCommandDataGetMagic(command) == 0x06) {
217 hw->rtc.command = command;
218
219 hw->rtc.bytesRemaining = RTC_BYTES[RTCCommandDataGetCommand(command)];
220 hw->rtc.commandActive = hw->rtc.bytesRemaining > 0;
221 switch (RTCCommandDataGetCommand(command)) {
222 case RTC_RESET:
223 hw->rtc.control = 0;
224 break;
225 case RTC_DATETIME:
226 case RTC_TIME:
227 _rtcUpdateClock(hw);
228 break;
229 case RTC_FORCE_IRQ:
230 case RTC_CONTROL:
231 break;
232 }
233 } else {
234 mLOG(GBA_HW, WARN, "Invalid RTC command byte: %02X", hw->rtc.bits);
235 }
236 } else {
237 switch (RTCCommandDataGetCommand(hw->rtc.command)) {
238 case RTC_CONTROL:
239 hw->rtc.control = hw->rtc.bits;
240 break;
241 case RTC_FORCE_IRQ:
242 mLOG(GBA_HW, STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(hw->rtc.command));
243 break;
244 case RTC_RESET:
245 case RTC_DATETIME:
246 case RTC_TIME:
247 break;
248 }
249 }
250
251 hw->rtc.bits = 0;
252 hw->rtc.bitsRead = 0;
253 if (!hw->rtc.bytesRemaining) {
254 hw->rtc.commandActive = 0;
255 hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command);
256 }
257}
258
259unsigned _rtcOutput(struct GBACartridgeHardware* hw) {
260 uint8_t outputByte = 0;
261 switch (RTCCommandDataGetCommand(hw->rtc.command)) {
262 case RTC_CONTROL:
263 outputByte = hw->rtc.control;
264 break;
265 case RTC_DATETIME:
266 case RTC_TIME:
267 outputByte = hw->rtc.time[7 - hw->rtc.bytesRemaining];
268 break;
269 case RTC_FORCE_IRQ:
270 case RTC_RESET:
271 break;
272 }
273 unsigned output = (outputByte >> hw->rtc.bitsRead) & 1;
274 return output;
275}
276
277void _rtcUpdateClock(struct GBACartridgeHardware* hw) {
278 time_t t;
279 struct mRTCSource* rtc = hw->p->rtcSource;
280 if (rtc) {
281 if (rtc->sample) {
282 rtc->sample(rtc);
283 }
284 t = rtc->unixTime(rtc);
285 } else {
286 t = time(0);
287 }
288 struct tm date;
289 localtime_r(&t, &date);
290 hw->rtc.time[0] = _rtcBCD(date.tm_year - 100);
291 hw->rtc.time[1] = _rtcBCD(date.tm_mon + 1);
292 hw->rtc.time[2] = _rtcBCD(date.tm_mday);
293 hw->rtc.time[3] = _rtcBCD(date.tm_wday);
294 if (RTCControlIsHour24(hw->rtc.control)) {
295 hw->rtc.time[4] = _rtcBCD(date.tm_hour);
296 } else {
297 hw->rtc.time[4] = _rtcBCD(date.tm_hour % 12);
298 }
299 hw->rtc.time[5] = _rtcBCD(date.tm_min);
300 hw->rtc.time[6] = _rtcBCD(date.tm_sec);
301}
302
303unsigned _rtcBCD(unsigned value) {
304 int counter = value % 10;
305 value /= 10;
306 counter += (value % 10) << 4;
307 return counter;
308}
309
310time_t _rtcGenericCallback(struct mRTCSource* source) {
311 struct GBARTCGenericSource* rtc = (struct GBARTCGenericSource*) source;
312 switch (rtc->override) {
313 case RTC_NO_OVERRIDE:
314 default:
315 return time(0);
316 case RTC_FIXED:
317 return rtc->value;
318 case RTC_FAKE_EPOCH:
319 return rtc->value + rtc->p->video.frameCounter * (int64_t) VIDEO_TOTAL_LENGTH / GBA_ARM7TDMI_FREQUENCY;
320 }
321}
322
323void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba) {
324 rtc->p = gba;
325 rtc->override = RTC_NO_OVERRIDE;
326 rtc->value = 0;
327 rtc->d.sample = 0;
328 rtc->d.unixTime = _rtcGenericCallback;
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->renderer->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 0x30F;
536 }
537 return 0x3FF;
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 mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048);
557 }
558 value &= 0x78FB;
559 }
560 return value;
561}
562
563void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
564 UNUSED(timing);
565 UNUSED(cyclesLate);
566 struct GBAGBPSIODriver* gbp = user;
567 uint32_t tx = 0;
568 int txPosition = gbp->p->gbpTxPosition;
569 if (txPosition > 16) {
570 gbp->p->gbpTxPosition = 0;
571 txPosition = 0;
572 } else if (txPosition > 12) {
573 txPosition = 12;
574 }
575 tx = _gbpTxData[txPosition];
576 ++gbp->p->gbpTxPosition;
577 gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
578 gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
579 if (gbp->d.p->normalControl.irq) {
580 GBARaiseIRQ(gbp->p->p, IRQ_SIO);
581 }
582 gbp->d.p->normalControl.start = 0;
583 gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
584}
585
586// == Serialization
587
588void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
589 GBASerializedHWFlags1 flags1 = 0;
590 GBASerializedHWFlags2 flags2 = 0;
591 flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite);
592 STORE_16(hw->pinState, 0, &state->hw.pinState);
593 STORE_16(hw->direction, 0, &state->hw.pinDirection);
594 state->hw.devices = hw->devices;
595
596 STORE_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining);
597 STORE_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep);
598 STORE_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead);
599 STORE_32(hw->rtc.bits, 0, &state->hw.rtc.bits);
600 STORE_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive);
601 STORE_32(hw->rtc.command, 0, &state->hw.rtc.command);
602 STORE_32(hw->rtc.control, 0, &state->hw.rtc.control);
603 memcpy(state->hw.rtc.time, hw->rtc.time, sizeof(state->hw.rtc.time));
604
605 STORE_16(hw->gyroSample, 0, &state->hw.gyroSample);
606 flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge);
607 STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX);
608 STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY);
609 flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
610 flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
611 state->hw.lightSample = hw->lightSample;
612 flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge);
613 flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted);
614 flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition);
615 STORE_32(hw->gbpNextEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
616 STORE_16(flags1, 0, &state->hw.flags1);
617 state->hw.flags2 = flags2;
618}
619
620void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) {
621 GBASerializedHWFlags1 flags1;
622 LOAD_16(flags1, 0, &state->hw.flags1);
623 hw->readWrite = GBASerializedHWFlags1GetReadWrite(flags1);
624 LOAD_16(hw->pinState, 0, &state->hw.pinState);
625 LOAD_16(hw->direction, 0, &state->hw.pinDirection);
626 hw->devices = state->hw.devices;
627
628 LOAD_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining);
629 LOAD_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep);
630 LOAD_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead);
631 LOAD_32(hw->rtc.bits, 0, &state->hw.rtc.bits);
632 LOAD_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive);
633 LOAD_32(hw->rtc.command, 0, &state->hw.rtc.command);
634 LOAD_32(hw->rtc.control, 0, &state->hw.rtc.control);
635 memcpy(hw->rtc.time, state->hw.rtc.time, sizeof(hw->rtc.time));
636
637 LOAD_16(hw->gyroSample, 0, &state->hw.gyroSample);
638 hw->gyroEdge = GBASerializedHWFlags1GetGyroEdge(flags1);
639 LOAD_16(hw->tiltX, 0, &state->hw.tiltSampleX);
640 LOAD_16(hw->tiltY, 0, &state->hw.tiltSampleY);
641 hw->tiltState = GBASerializedHWFlags2GetTiltState(state->hw.flags2);
642 hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1);
643 hw->lightSample = state->hw.lightSample;
644 hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1);
645 hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
646 hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
647
648 uint32_t when;
649 LOAD_32(when, 0, &state->hw.gbpNextEvent);
650 if (hw->devices & HW_GB_PLAYER) {
651 GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32);
652 if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) {
653 mTimingSchedule(&hw->p->timing, &hw->gbpNextEvent, when);
654 }
655 }
656}