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