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