1 #include <stdio.h>
2 #include <time.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "gba.h"
7 #include "globals.h"
8 #include "memory.h"
9 #include "port.h"
10 #include "system.h"
11
12 /*============================================================
13 UTIL
14 ============================================================ */
15
16 extern bool cpuIsMultiBoot;
17
utilIsGBAImage(const char * file)18 bool utilIsGBAImage(const char * file)
19 {
20 cpuIsMultiBoot = false;
21 if(strlen(file) > 4)
22 {
23 const char * p = strrchr(file,'.');
24
25 if(p != NULL)
26 {
27 if(
28 !strcasecmp(p, ".agb") ||
29 !strcasecmp(p, ".gba") ||
30 !strcasecmp(p, ".bin") ||
31 !strcasecmp(p, ".elf")
32 )
33 return true;
34
35 if(!strcasecmp(p, ".mb"))
36 {
37 cpuIsMultiBoot = true;
38 return true;
39 }
40 }
41 }
42
43 return false;
44 }
45
utilGetSize(int size)46 static int utilGetSize(int size)
47 {
48 int res = 1;
49
50 while(res < size)
51 res <<= 1;
52
53 return res;
54 }
55
utilLoad(const char * file,bool (* accept)(const char *),uint8_t * data,int & size)56 uint8_t *utilLoad(const char *file, bool (*accept)(const char *), uint8_t *data, int &size)
57 {
58 uint8_t *image = NULL;
59 FILE *fp = fopen(file,"rb");
60 if(!fp) return NULL;
61
62 fseek(fp, 0, SEEK_END); /*go to end*/
63 size = ftell(fp); /* get position at end (length)*/
64 rewind(fp);
65
66 image = data;
67
68 if(image == NULL)
69 {
70 /*allocate buffer memory if none was passed to the function*/
71 image = (uint8_t *)malloc(utilGetSize(size));
72 if(image == NULL)
73 {
74 systemMessage("Failed to allocate memory for data");
75 return NULL;
76 }
77 }
78
79 fread(image, 1, size, fp); /* read into buffer*/
80 fclose(fp);
81 return image;
82 }
83
84 /* Not endian safe, but VBA itself doesn't seem to care */
utilWriteIntMem(uint8_t * & data,int val)85 void utilWriteIntMem(uint8_t *& data, int val)
86 {
87 memcpy(data, &val, sizeof(int));
88 data += sizeof(int);
89 }
90
utilWriteMem(uint8_t * & data,const void * in_data,unsigned size)91 void utilWriteMem(uint8_t *& data, const void *in_data, unsigned size)
92 {
93 memcpy(data, in_data, size);
94 data += size;
95 }
96
utilWriteDataMem(uint8_t * & data,variable_desc * desc)97 void utilWriteDataMem(uint8_t *& data, variable_desc *desc)
98 {
99 while (desc->address)
100 {
101 utilWriteMem(data, desc->address, desc->size);
102 desc++;
103 }
104 }
105
utilReadIntMem(const uint8_t * & data)106 int utilReadIntMem(const uint8_t *& data)
107 {
108 int res;
109
110 memcpy(&res, data, sizeof(int));
111 data += sizeof(int);
112 return res;
113 }
114
utilReadMem(void * buf,const uint8_t * & data,unsigned size)115 void utilReadMem(void *buf, const uint8_t *& data, unsigned size)
116 {
117 memcpy(buf, data, size);
118 data += size;
119 }
120
utilReadDataMem(const uint8_t * & data,variable_desc * desc)121 void utilReadDataMem(const uint8_t *& data, variable_desc *desc)
122 {
123 while (desc->address)
124 {
125 utilReadMem(desc->address, data, desc->size);
126 desc++;
127 }
128 }
129
130 /*============================================================
131 FLASH
132 ============================================================ */
133
134
135 #define FLASH_READ_ARRAY 0
136 #define FLASH_CMD_1 1
137 #define FLASH_CMD_2 2
138 #define FLASH_AUTOSELECT 3
139 #define FLASH_CMD_3 4
140 #define FLASH_CMD_4 5
141 #define FLASH_CMD_5 6
142 #define FLASH_ERASE_COMPLETE 7
143 #define FLASH_PROGRAM 8
144 #define FLASH_SETBANK 9
145
146 extern uint8_t libretro_save_buf[0x20000 + 0x2000];
147 uint8_t *flashSaveMemory = libretro_save_buf;
148
149 int flashState = FLASH_READ_ARRAY;
150 int flashReadState = FLASH_READ_ARRAY;
151 int flashSize = 0x10000;
152 int flashDeviceID = 0x1b;
153 int flashManufacturerID = 0x32;
154 int flashBank = 0;
155
156 static variable_desc flashSaveData3[] = {
157 { &flashState, sizeof(int) },
158 { &flashReadState, sizeof(int) },
159 { &flashSize, sizeof(int) },
160 { &flashBank, sizeof(int) },
161 { &flashSaveMemory[0], 0x20000 },
162 { NULL, 0 }
163 };
164
flashInit(void)165 void flashInit (void)
166 {
167 memset(flashSaveMemory, 0xff, 0x20000);
168 }
169
flashReset()170 void flashReset()
171 {
172 flashState = FLASH_READ_ARRAY;
173 flashReadState = FLASH_READ_ARRAY;
174 flashBank = 0;
175 }
176
flashSaveGameMem(uint8_t * & data)177 void flashSaveGameMem(uint8_t *& data)
178 {
179 utilWriteDataMem(data, flashSaveData3);
180 }
181
flashReadGameMem(const uint8_t * & data,int)182 void flashReadGameMem(const uint8_t *& data, int)
183 {
184 utilReadDataMem(data, flashSaveData3);
185 }
186
flashSetSize(int size)187 void flashSetSize(int size)
188 {
189 if(size == 0x10000) {
190 flashDeviceID = 0x1b;
191 flashManufacturerID = 0x32;
192 } else {
193 flashDeviceID = 0x13; //0x09;
194 flashManufacturerID = 0x62; //0xc2;
195 }
196 // Added to make 64k saves compatible with 128k ones
197 // (allow wrongfuly set 64k saves to work for Pokemon games)
198 if ((size == 0x20000) && (flashSize == 0x10000))
199 memcpy((uint8_t *)(flashSaveMemory+0x10000), (uint8_t *)(flashSaveMemory), 0x10000);
200 flashSize = size;
201 }
202
flashRead(uint32_t address)203 uint8_t flashRead(uint32_t address)
204 {
205 address &= 0xFFFF;
206
207 switch(flashReadState) {
208 case FLASH_READ_ARRAY:
209 return flashSaveMemory[(flashBank << 16) + address];
210 case FLASH_AUTOSELECT:
211 switch(address & 0xFF)
212 {
213 case 0:
214 // manufacturer ID
215 return flashManufacturerID;
216 case 1:
217 // device ID
218 return flashDeviceID;
219 }
220 break;
221 case FLASH_ERASE_COMPLETE:
222 flashState = FLASH_READ_ARRAY;
223 flashReadState = FLASH_READ_ARRAY;
224 return 0xFF;
225 };
226 return 0;
227 }
228
flashSaveDecide(uint32_t address,uint8_t byte)229 void flashSaveDecide(uint32_t address, uint8_t byte)
230 {
231 if(address == 0x0e005555) {
232 saveType = 2;
233 cpuSaveGameFunc = flashWrite;
234 } else {
235 saveType = 1;
236 cpuSaveGameFunc = sramWrite;
237 }
238
239 (*cpuSaveGameFunc)(address, byte);
240 }
241
flashDelayedWrite(uint32_t address,uint8_t byte)242 void flashDelayedWrite(uint32_t address, uint8_t byte)
243 {
244 saveType = 2;
245 cpuSaveGameFunc = flashWrite;
246 flashWrite(address, byte);
247 }
248
flashWrite(uint32_t address,uint8_t byte)249 void flashWrite(uint32_t address, uint8_t byte)
250 {
251 address &= 0xFFFF;
252 switch(flashState) {
253 case FLASH_READ_ARRAY:
254 if(address == 0x5555 && byte == 0xAA)
255 flashState = FLASH_CMD_1;
256 break;
257 case FLASH_CMD_1:
258 if(address == 0x2AAA && byte == 0x55)
259 flashState = FLASH_CMD_2;
260 else
261 flashState = FLASH_READ_ARRAY;
262 break;
263 case FLASH_CMD_2:
264 if(address == 0x5555) {
265 if(byte == 0x90) {
266 flashState = FLASH_AUTOSELECT;
267 flashReadState = FLASH_AUTOSELECT;
268 } else if(byte == 0x80) {
269 flashState = FLASH_CMD_3;
270 } else if(byte == 0xF0) {
271 flashState = FLASH_READ_ARRAY;
272 flashReadState = FLASH_READ_ARRAY;
273 } else if(byte == 0xA0) {
274 flashState = FLASH_PROGRAM;
275 } else if(byte == 0xB0 && flashSize == 0x20000) {
276 flashState = FLASH_SETBANK;
277 } else {
278 flashState = FLASH_READ_ARRAY;
279 flashReadState = FLASH_READ_ARRAY;
280 }
281 } else {
282 flashState = FLASH_READ_ARRAY;
283 flashReadState = FLASH_READ_ARRAY;
284 }
285 break;
286 case FLASH_CMD_3:
287 if(address == 0x5555 && byte == 0xAA) {
288 flashState = FLASH_CMD_4;
289 } else {
290 flashState = FLASH_READ_ARRAY;
291 flashReadState = FLASH_READ_ARRAY;
292 }
293 break;
294 case FLASH_CMD_4:
295 if(address == 0x2AAA && byte == 0x55) {
296 flashState = FLASH_CMD_5;
297 } else {
298 flashState = FLASH_READ_ARRAY;
299 flashReadState = FLASH_READ_ARRAY;
300 }
301 break;
302 case FLASH_CMD_5:
303 if(byte == 0x30) {
304 // SECTOR ERASE
305 memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)],
306 0,
307 0x1000);
308 flashReadState = FLASH_ERASE_COMPLETE;
309 } else if(byte == 0x10) {
310 // CHIP ERASE
311 memset(flashSaveMemory, 0, flashSize);
312 flashReadState = FLASH_ERASE_COMPLETE;
313 } else {
314 flashState = FLASH_READ_ARRAY;
315 flashReadState = FLASH_READ_ARRAY;
316 }
317 break;
318 case FLASH_AUTOSELECT:
319 if(byte == 0xF0) {
320 flashState = FLASH_READ_ARRAY;
321 flashReadState = FLASH_READ_ARRAY;
322 } else if(address == 0x5555 && byte == 0xAA)
323 flashState = FLASH_CMD_1;
324 else {
325 flashState = FLASH_READ_ARRAY;
326 flashReadState = FLASH_READ_ARRAY;
327 }
328 break;
329 case FLASH_PROGRAM:
330 flashSaveMemory[(flashBank<<16)+address] = byte;
331 flashState = FLASH_READ_ARRAY;
332 flashReadState = FLASH_READ_ARRAY;
333 break;
334 case FLASH_SETBANK:
335 if(address == 0) {
336 flashBank = (byte & 1);
337 }
338 flashState = FLASH_READ_ARRAY;
339 flashReadState = FLASH_READ_ARRAY;
340 break;
341 }
342 }
343
344 /*============================================================
345 EEPROM
346 ============================================================ */
347 int eepromMode = EEPROM_IDLE;
348 int eepromByte = 0;
349 int eepromBits = 0;
350 int eepromAddress = 0;
351
352 // Workaround for broken-by-design GBA save semantics.
353 extern u8 libretro_save_buf[0x20000 + 0x2000];
354 u8 *eepromData = libretro_save_buf + 0x20000;
355
356 u8 eepromBuffer[16];
357 bool eepromInUse = false;
358 int eepromSize = 512;
359
360 variable_desc eepromSaveData[] = {
361 { &eepromMode, sizeof(int) },
362 { &eepromByte, sizeof(int) },
363 { &eepromBits , sizeof(int) },
364 { &eepromAddress , sizeof(int) },
365 { &eepromInUse, sizeof(bool) },
366 { &eepromData[0], 512 },
367 { &eepromBuffer[0], 16 },
368 { NULL, 0 }
369 };
370
eepromInit(void)371 void eepromInit (void)
372 {
373 memset(eepromData, 255, 0x2000);
374 }
375
eepromReset(void)376 void eepromReset (void)
377 {
378 eepromMode = EEPROM_IDLE;
379 eepromByte = 0;
380 eepromBits = 0;
381 eepromAddress = 0;
382 eepromInUse = false;
383 eepromSize = 512;
384 }
385
eepromSaveGameMem(uint8_t * & data)386 void eepromSaveGameMem(uint8_t *& data)
387 {
388 utilWriteDataMem(data, eepromSaveData);
389 utilWriteIntMem(data, eepromSize);
390 utilWriteMem(data, eepromData, 0x2000);
391 }
392
eepromReadGameMem(const uint8_t * & data,int version)393 void eepromReadGameMem(const uint8_t *& data, int version)
394 {
395 utilReadDataMem(data, eepromSaveData);
396 eepromSize = utilReadIntMem(data);
397 utilReadMem(eepromData, data, 0x2000);
398 }
399
eepromRead(void)400 int eepromRead (void)
401 {
402 switch(eepromMode)
403 {
404 case EEPROM_IDLE:
405 case EEPROM_READADDRESS:
406 case EEPROM_WRITEDATA:
407 return 1;
408 case EEPROM_READDATA:
409 {
410 eepromBits++;
411 if(eepromBits == 4) {
412 eepromMode = EEPROM_READDATA2;
413 eepromBits = 0;
414 eepromByte = 0;
415 }
416 return 0;
417 }
418 case EEPROM_READDATA2:
419 {
420 int data = 0;
421 int address = eepromAddress << 3;
422 int mask = 1 << (7 - (eepromBits & 7));
423 data = (eepromData[address+eepromByte] & mask) ? 1 : 0;
424 eepromBits++;
425 if((eepromBits & 7) == 0)
426 eepromByte++;
427 if(eepromBits == 0x40)
428 eepromMode = EEPROM_IDLE;
429 return data;
430 }
431 default:
432 break;
433 }
434
435 return 0;
436 }
437
eepromWrite(u8 value)438 void eepromWrite(u8 value)
439 {
440 if(cpuDmaCount == 0)
441 return;
442 int bit = value & 1;
443 switch(eepromMode) {
444 case EEPROM_IDLE:
445 eepromByte = 0;
446 eepromBits = 1;
447 eepromBuffer[eepromByte] = bit;
448 eepromMode = EEPROM_READADDRESS;
449 break;
450 case EEPROM_READADDRESS:
451 eepromBuffer[eepromByte] <<= 1;
452 eepromBuffer[eepromByte] |= bit;
453 eepromBits++;
454 if((eepromBits & 7) == 0) {
455 eepromByte++;
456 }
457 if(cpuDmaCount == 0x11 || cpuDmaCount == 0x51) {
458 if(eepromBits == 0x11) {
459 eepromInUse = true;
460 eepromSize = 0x2000;
461 eepromAddress = ((eepromBuffer[0] & 0x3F) << 8) |
462 ((eepromBuffer[1] & 0xFF));
463 if(!(eepromBuffer[0] & 0x40)) {
464 eepromBuffer[0] = bit;
465 eepromBits = 1;
466 eepromByte = 0;
467 eepromMode = EEPROM_WRITEDATA;
468 } else {
469 eepromMode = EEPROM_READDATA;
470 eepromByte = 0;
471 eepromBits = 0;
472 }
473 }
474 } else {
475 if(eepromBits == 9) {
476 eepromInUse = true;
477 eepromAddress = (eepromBuffer[0] & 0x3F);
478 if(!(eepromBuffer[0] & 0x40)) {
479 eepromBuffer[0] = bit;
480 eepromBits = 1;
481 eepromByte = 0;
482 eepromMode = EEPROM_WRITEDATA;
483 } else {
484 eepromMode = EEPROM_READDATA;
485 eepromByte = 0;
486 eepromBits = 0;
487 }
488 }
489 }
490 break;
491 case EEPROM_READDATA:
492 case EEPROM_READDATA2:
493 // should we reset here?
494 eepromMode = EEPROM_IDLE;
495 break;
496 case EEPROM_WRITEDATA:
497 eepromBuffer[eepromByte] <<= 1;
498 eepromBuffer[eepromByte] |= bit;
499 eepromBits++;
500 if((eepromBits & 7) == 0)
501 eepromByte++;
502 if(eepromBits == 0x40)
503 {
504 eepromInUse = true;
505 // write data;
506 for(int i = 0; i < 8; i++)
507 eepromData[(eepromAddress << 3) + i] = eepromBuffer[i];
508 }
509 else if(eepromBits == 0x41)
510 {
511 eepromMode = EEPROM_IDLE;
512 eepromByte = 0;
513 eepromBits = 0;
514 }
515 break;
516 }
517 }
518
519 /*============================================================
520 SRAM
521 ============================================================ */
522
sramRead(u32 address)523 u8 sramRead(u32 address)
524 {
525 return flashSaveMemory[address & 0xFFFF];
526 }
527
sramDelayedWrite(u32 address,u8 byte)528 void sramDelayedWrite(u32 address, u8 byte)
529 {
530 saveType = 1;
531 cpuSaveGameFunc = sramWrite;
532 sramWrite(address, byte);
533 }
534
sramWrite(u32 address,u8 byte)535 void sramWrite(u32 address, u8 byte)
536 {
537 flashSaveMemory[address & 0xFFFF] = byte;
538 }
539
540 /*============================================================
541 GYRO
542 ============================================================ */
543
544 #if USE_MOTION_SENSOR
545 static u16 gyro_data[3];
546
gyroWritePins(unsigned pins)547 static void gyroWritePins(unsigned pins) {
548 if (!hardware.readWrite) return;
549
550 uint16_t& t = gyro_data[0];
551 t &= hardware.direction;
552 hardware.pinState = t | (pins & ~hardware.direction & 0xF);
553 t = hardware.pinState;
554 }
555
gyroReadPins()556 static void gyroReadPins() {
557 if (hardware.pinState & 1) {
558 // Normalize to ~12 bits, focused on 0x6C0
559 hardware.gyroSample = (systemGetGyroZ() >> 21) + 0x6C0; // Crop off an extra bit so that we can't go negative
560 }
561
562 if (hardware.gyroEdge && !(hardware.pinState & 2)) {
563 // Write bit on falling edge
564 unsigned bit = hardware.gyroSample >> 15;
565 hardware.gyroSample <<= 1;
566 gyroWritePins(bit << 2);
567 }
568
569 hardware.gyroEdge = !!(hardware.pinState & 2);
570 }
571
gyroWrite(u32 address,u16 value)572 bool gyroWrite(u32 address, u16 value) {
573 switch (address) {
574 case 0x80000c4:
575 hardware.pinState &= ~hardware.direction;
576 hardware.pinState |= value;
577 gyroReadPins();
578 break;
579 case 0x80000c6:
580 hardware.direction = value;
581 break;
582 case 0x80000c8:
583 hardware.readWrite = value;
584 break;
585 default:
586 break;
587 }
588 if (hardware.readWrite) {
589 uint16_t& t = gyro_data[0];
590 t &= ~hardware.direction;
591 t |= hardware.pinState;
592 } else {
593 gyro_data[0] = 0;
594 }
595 return true;
596 }
597
gyroRead(u32 address)598 u16 gyroRead(u32 address) {
599 return gyro_data[(address - 0x80000c4) >> 1];
600 }
601 #endif
602
603 /*============================================================
604 RTC
605 ============================================================ */
606
607 #define IDLE 0
608 #define COMMAND 1
609 #define DATA 2
610 #define READDATA 3
611
612 typedef struct
613 {
614 u8 byte0;
615 u8 byte1;
616 u8 byte2;
617 u8 command;
618 int dataLen;
619 int bits;
620 int state;
621 u8 data[12];
622 // reserved variables for future
623 u8 reserved[12];
624 bool reserved2;
625 u32 reserved3;
626 } RTCCLOCKDATA;
627
628 static RTCCLOCKDATA rtcClockData;
629 static bool rtcEnabled = false;
630
rtcEnable(bool e)631 void rtcEnable(bool e)
632 {
633 rtcEnabled = e;
634 }
635
rtcIsEnabled(void)636 bool rtcIsEnabled (void)
637 {
638 return rtcEnabled;
639 }
640
rtcRead(u32 address)641 u16 rtcRead(u32 address)
642 {
643 if(rtcEnabled)
644 {
645 switch(address)
646 {
647 case 0x80000c8:
648 return rtcClockData.byte2;
649 case 0x80000c6:
650 return rtcClockData.byte1;
651 case 0x80000c4:
652 return rtcClockData.byte0;
653 }
654 }
655
656 return READ16LE((&rom[address & 0x1FFFFFE]));
657 }
658
toBCD(u8 value)659 static u8 toBCD(u8 value)
660 {
661 value = value % 100;
662 int l = value % 10;
663 int h = value / 10;
664 return h * 16 + l;
665 };
666
rtcWrite(u32 address,u16 value)667 bool rtcWrite(u32 address, u16 value)
668 {
669 if(!rtcEnabled)
670 return false;
671
672 if(address == 0x80000c8)
673 rtcClockData.byte2 = (u8)value; // enable ?
674 else if(address == 0x80000c6)
675 rtcClockData.byte1 = (u8)value; // read/write
676 else if(address == 0x80000c4)
677 {
678 if(rtcClockData.byte2 & 1)
679 {
680 if(rtcClockData.state == IDLE && rtcClockData.byte0 == 1 && value == 5)
681 {
682 rtcClockData.state = COMMAND;
683 rtcClockData.bits = 0;
684 rtcClockData.command = 0;
685 }
686 else if(!(rtcClockData.byte0 & 1) && (value & 1))
687 { // bit transfer
688 rtcClockData.byte0 = (u8)value;
689 switch(rtcClockData.state)
690 {
691 case COMMAND:
692 rtcClockData.command |= ((value & 2) >> 1) << (7-rtcClockData.bits);
693 rtcClockData.bits++;
694 if(rtcClockData.bits == 8)
695 {
696 rtcClockData.bits = 0;
697 switch(rtcClockData.command)
698 {
699 case 0x60:
700 // not sure what this command does but it doesn't take parameters
701 // maybe it is a reset or stop
702 rtcClockData.state = IDLE;
703 rtcClockData.bits = 0;
704 break;
705 case 0x62:
706 // this sets the control state but not sure what those values are
707 rtcClockData.state = READDATA;
708 rtcClockData.dataLen = 1;
709 break;
710 case 0x63:
711 rtcClockData.dataLen = 1;
712 rtcClockData.data[0] = 0x40;
713 rtcClockData.state = DATA;
714 break;
715 case 0x64:
716 break;
717 case 0x65:
718 {
719 struct tm *newtime;
720 time_t long_time;
721
722 time( &long_time ); /* Get time as long integer. */
723 newtime = localtime( &long_time ); /* Convert to local time. */
724
725 rtcClockData.dataLen = 7;
726 rtcClockData.data[0] = toBCD(newtime->tm_year);
727 rtcClockData.data[1] = toBCD(newtime->tm_mon+1);
728 rtcClockData.data[2] = toBCD(newtime->tm_mday);
729 rtcClockData.data[3] = toBCD(newtime->tm_wday);
730 rtcClockData.data[4] = toBCD(newtime->tm_hour);
731 rtcClockData.data[5] = toBCD(newtime->tm_min);
732 rtcClockData.data[6] = toBCD(newtime->tm_sec);
733 rtcClockData.state = DATA;
734 }
735 break;
736 case 0x67:
737 {
738 struct tm *newtime;
739 time_t long_time;
740
741 time( &long_time ); /* Get time as long integer. */
742 newtime = localtime( &long_time ); /* Convert to local time. */
743
744 rtcClockData.dataLen = 3;
745 rtcClockData.data[0] = toBCD(newtime->tm_hour);
746 rtcClockData.data[1] = toBCD(newtime->tm_min);
747 rtcClockData.data[2] = toBCD(newtime->tm_sec);
748 rtcClockData.state = DATA;
749 }
750 break;
751 default:
752 systemMessage(0, "Unknown RTC command %02x", rtcClockData.command);
753 rtcClockData.state = IDLE;
754 break;
755 }
756 }
757 break;
758 case DATA:
759 if(rtcClockData.byte1 & 2)
760 {
761 }
762 else
763 {
764 rtcClockData.byte0 = (rtcClockData.byte0 & ~2) |
765 ((rtcClockData.data[rtcClockData.bits >> 3] >>
766 (rtcClockData.bits & 7)) & 1)*2;
767 rtcClockData.bits++;
768 if(rtcClockData.bits == 8*rtcClockData.dataLen)
769 {
770 rtcClockData.bits = 0;
771 rtcClockData.state = IDLE;
772 }
773 }
774 break;
775 case READDATA:
776 if(!(rtcClockData.byte1 & 2)) {
777 } else {
778 rtcClockData.data[rtcClockData.bits >> 3] =
779 (rtcClockData.data[rtcClockData.bits >> 3] >> 1) |
780 ((value << 6) & 128);
781 rtcClockData.bits++;
782 if(rtcClockData.bits == 8*rtcClockData.dataLen) {
783 rtcClockData.bits = 0;
784 rtcClockData.state = IDLE;
785 }
786 }
787 break;
788 default:
789 break;
790 }
791 } else
792 rtcClockData.byte0 = (u8)value;
793 }
794 }
795 return true;
796 }
797
rtcReset(void)798 void rtcReset (void)
799 {
800 memset(&rtcClockData, 0, sizeof(rtcClockData));
801
802 rtcClockData.byte0 = 0;
803 rtcClockData.byte1 = 0;
804 rtcClockData.byte2 = 0;
805 rtcClockData.command = 0;
806 rtcClockData.dataLen = 0;
807 rtcClockData.bits = 0;
808 rtcClockData.state = IDLE;
809 }
810
rtcSaveGameMem(uint8_t * & data)811 void rtcSaveGameMem(uint8_t *& data)
812 {
813 utilWriteMem(data, &rtcClockData, sizeof(rtcClockData));
814 }
815
rtcReadGameMem(const uint8_t * & data)816 void rtcReadGameMem(const uint8_t *& data)
817 {
818 utilReadMem(&rtcClockData, data, sizeof(rtcClockData));
819 }
820
821