diff src/gba/RTC.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/gba/RTC.cpp	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,240 @@
     1.4 +#include <cstring>
     1.5 +
     1.6 +#include "../Port.h"
     1.7 +#include "../NLS.h"
     1.8 +#include "../common/System.h" // systemMessage
     1.9 +#include "../common/Util.h"
    1.10 +#include "../common/movie.h"
    1.11 +#include "GBAGlobals.h"
    1.12 +
    1.13 +enum RTCSTATE { IDLE, COMMAND, DATA, READDATA };
    1.14 +
    1.15 +typedef struct
    1.16 +{
    1.17 +	u8       byte0;
    1.18 +	u8       byte1;
    1.19 +	u8       byte2;
    1.20 +	u8       command;
    1.21 +	int      dataLen;
    1.22 +	int      bits;
    1.23 +	RTCSTATE state;
    1.24 +	u8       data[12];
    1.25 +	// reserved variables for future
    1.26 +	u8   reserved[12];
    1.27 +	bool reserved2;
    1.28 +	u32  reserved3;
    1.29 +} RTCCLOCKDATA;
    1.30 +
    1.31 +static RTCCLOCKDATA rtcClockData;
    1.32 +static bool         rtcEnabled = false;
    1.33 +
    1.34 +void rtcEnable(bool enable)
    1.35 +{
    1.36 +	rtcEnabled = enable;
    1.37 +}
    1.38 +
    1.39 +bool rtcIsEnabled()
    1.40 +{
    1.41 +	return rtcEnabled;
    1.42 +}
    1.43 +
    1.44 +u16 rtcRead(u32 address)
    1.45 +{
    1.46 +	if (rtcEnabled)
    1.47 +	{
    1.48 +		if (address == 0x80000c8)
    1.49 +			return rtcClockData.byte2;
    1.50 +		else if (address == 0x80000c6)
    1.51 +			return rtcClockData.byte1;
    1.52 +		else if (address == 0x80000c4)
    1.53 +		{
    1.54 +			return rtcClockData.byte0;
    1.55 +		}
    1.56 +	}
    1.57 +
    1.58 +	return READ16LE((&rom[address & 0x1FFFFFE]));
    1.59 +}
    1.60 +
    1.61 +static u8 toBCD(u8 value)
    1.62 +{
    1.63 +	value = value % 100;
    1.64 +	int l = value % 10;
    1.65 +	int h = value / 10;
    1.66 +	return h * 16 + l;
    1.67 +}
    1.68 +
    1.69 +bool rtcWrite(u32 address, u16 value)
    1.70 +{
    1.71 +	if (!rtcEnabled)
    1.72 +		return false;
    1.73 +
    1.74 +	if (address == 0x80000c8)
    1.75 +	{
    1.76 +		rtcClockData.byte2 = (u8)value; // enable ?
    1.77 +	}
    1.78 +	else if (address == 0x80000c6)
    1.79 +	{
    1.80 +		rtcClockData.byte1 = (u8)value; // read/write
    1.81 +	}
    1.82 +	else if (address == 0x80000c4)
    1.83 +	{
    1.84 +		if (rtcClockData.byte2 & 1)
    1.85 +		{
    1.86 +			if (rtcClockData.state == IDLE && rtcClockData.byte0 == 1 && value == 5)
    1.87 +			{
    1.88 +				rtcClockData.state   = COMMAND;
    1.89 +				rtcClockData.bits    = 0;
    1.90 +				rtcClockData.command = 0;
    1.91 +			}
    1.92 +			else if (!(rtcClockData.byte0 & 1) && (value & 1)) // bit transfer
    1.93 +			{
    1.94 +				rtcClockData.byte0 = (u8)value;
    1.95 +				switch (rtcClockData.state)
    1.96 +				{
    1.97 +				case COMMAND:
    1.98 +					rtcClockData.command |= ((value & 2) >> 1) << (7-rtcClockData.bits);
    1.99 +					rtcClockData.bits++;
   1.100 +					if (rtcClockData.bits == 8)
   1.101 +					{
   1.102 +						rtcClockData.bits = 0;
   1.103 +						switch (rtcClockData.command)
   1.104 +						{
   1.105 +						case 0x60:
   1.106 +							// not sure what this command does but it doesn't take parameters
   1.107 +							// maybe it is a reset or stop
   1.108 +							rtcClockData.state = IDLE;
   1.109 +							rtcClockData.bits  = 0;
   1.110 +							break;
   1.111 +						case 0x62:
   1.112 +							// this sets the control state but not sure what those values are
   1.113 +							rtcClockData.state   = READDATA;
   1.114 +							rtcClockData.dataLen = 1;
   1.115 +							break;
   1.116 +						case 0x63:
   1.117 +							rtcClockData.dataLen = 1;
   1.118 +							rtcClockData.data[0] = 0x40;
   1.119 +							rtcClockData.state   = DATA;
   1.120 +							break;
   1.121 +						case 0x65:
   1.122 +						{
   1.123 +							struct tm *newtime;
   1.124 +							time_t     long_time;
   1.125 +
   1.126 +							if (VBAMovieActive() || VBAMovieLoading())
   1.127 +							{
   1.128 +								long_time = VBAMovieGetId() + VBAMovieGetFrameCounter()/60;
   1.129 +								newtime   = gmtime(&long_time);
   1.130 +							}
   1.131 +							else
   1.132 +							{
   1.133 +								time(&long_time);      /* Get time as long integer. */
   1.134 +								newtime = localtime(&long_time); /* Convert to local time. */
   1.135 +							}
   1.136 +
   1.137 +							rtcClockData.dataLen = 7;
   1.138 +							rtcClockData.data[0] = toBCD(newtime->tm_year);
   1.139 +							rtcClockData.data[1] = toBCD(newtime->tm_mon+1);
   1.140 +							rtcClockData.data[2] = toBCD(newtime->tm_mday);
   1.141 +							rtcClockData.data[3] = 0;
   1.142 +							rtcClockData.data[4] = toBCD(newtime->tm_hour);
   1.143 +							rtcClockData.data[5] = toBCD(newtime->tm_min);
   1.144 +							rtcClockData.data[6] = toBCD(newtime->tm_sec);
   1.145 +							rtcClockData.state   = DATA;
   1.146 +							break;
   1.147 +						}
   1.148 +						case 0x67:
   1.149 +						{
   1.150 +							struct tm *newtime;
   1.151 +							time_t     long_time;
   1.152 +
   1.153 +							if (VBAMovieActive() || VBAMovieLoading())
   1.154 +							{
   1.155 +								long_time = VBAMovieGetId() + VBAMovieGetFrameCounter()/60;
   1.156 +								newtime   = gmtime(&long_time);
   1.157 +							}
   1.158 +							else
   1.159 +							{
   1.160 +								time(&long_time);      /* Get time as long integer. */
   1.161 +								newtime = localtime(&long_time); /* Convert to local time. */
   1.162 +							}
   1.163 +
   1.164 +							rtcClockData.dataLen = 3;
   1.165 +							rtcClockData.data[0] = toBCD(newtime->tm_hour);
   1.166 +							rtcClockData.data[1] = toBCD(newtime->tm_min);
   1.167 +							rtcClockData.data[2] = toBCD(newtime->tm_sec);
   1.168 +							rtcClockData.state   = DATA;
   1.169 +							break;
   1.170 +						}
   1.171 +						default:
   1.172 +							systemMessage(0, N_("Unknown RTC command %02x"), rtcClockData.command);
   1.173 +							rtcClockData.state = IDLE;
   1.174 +							break;
   1.175 +						}
   1.176 +					}
   1.177 +					break;
   1.178 +				case DATA:
   1.179 +					if (rtcClockData.byte1 & 2)
   1.180 +					{}
   1.181 +					else
   1.182 +					{
   1.183 +						rtcClockData.byte0 = (rtcClockData.byte0 & ~2) |
   1.184 +						                     ((rtcClockData.data[rtcClockData.bits >> 3] >>
   1.185 +						                       (rtcClockData.bits & 7)) & 1)*2;
   1.186 +						rtcClockData.bits++;
   1.187 +						if (rtcClockData.bits == 8*rtcClockData.dataLen)
   1.188 +						{
   1.189 +							rtcClockData.bits  = 0;
   1.190 +							rtcClockData.state = IDLE;
   1.191 +						}
   1.192 +					}
   1.193 +					break;
   1.194 +				case READDATA:
   1.195 +					if (!(rtcClockData.byte1 & 2))
   1.196 +					{}
   1.197 +					else
   1.198 +					{
   1.199 +						rtcClockData.data[rtcClockData.bits >> 3] =
   1.200 +						    (rtcClockData.data[rtcClockData.bits >> 3] >> 1) |
   1.201 +						    ((value << 6) & 128);
   1.202 +						rtcClockData.bits++;
   1.203 +						if (rtcClockData.bits == 8*rtcClockData.dataLen)
   1.204 +						{
   1.205 +							rtcClockData.bits  = 0;
   1.206 +							rtcClockData.state = IDLE;
   1.207 +						}
   1.208 +					}
   1.209 +					break;
   1.210 +				default:
   1.211 +					break;
   1.212 +				}
   1.213 +			}
   1.214 +			else
   1.215 +				rtcClockData.byte0 = (u8)value;
   1.216 +		}
   1.217 +	}
   1.218 +	return true;
   1.219 +}
   1.220 +
   1.221 +void rtcReset()
   1.222 +{
   1.223 +	memset(&rtcClockData, 0, sizeof(rtcClockData));
   1.224 +
   1.225 +	rtcClockData.byte0   = 0;
   1.226 +	rtcClockData.byte1   = 0;
   1.227 +	rtcClockData.byte2   = 0;
   1.228 +	rtcClockData.command = 0;
   1.229 +	rtcClockData.dataLen = 0;
   1.230 +	rtcClockData.bits    = 0;
   1.231 +	rtcClockData.state   = IDLE;
   1.232 +}
   1.233 +
   1.234 +void rtcSaveGame(gzFile gzFile)
   1.235 +{
   1.236 +	utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData));
   1.237 +}
   1.238 +
   1.239 +void rtcReadGame(gzFile gzFile)
   1.240 +{
   1.241 +	utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData));
   1.242 +}
   1.243 +