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