Mercurial > vba-linux
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 +