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