Mercurial > vba-clojure
comparison 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 |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 #include <cstring> | |
2 | |
3 #include "../Port.h" | |
4 #include "../NLS.h" | |
5 #include "../common/System.h" // systemMessage | |
6 #include "../common/Util.h" | |
7 #include "../common/movie.h" | |
8 #include "GBAGlobals.h" | |
9 | |
10 enum RTCSTATE { IDLE, COMMAND, DATA, READDATA }; | |
11 | |
12 typedef struct | |
13 { | |
14 u8 byte0; | |
15 u8 byte1; | |
16 u8 byte2; | |
17 u8 command; | |
18 int dataLen; | |
19 int bits; | |
20 RTCSTATE state; | |
21 u8 data[12]; | |
22 // reserved variables for future | |
23 u8 reserved[12]; | |
24 bool reserved2; | |
25 u32 reserved3; | |
26 } RTCCLOCKDATA; | |
27 | |
28 static RTCCLOCKDATA rtcClockData; | |
29 static bool rtcEnabled = false; | |
30 | |
31 void rtcEnable(bool enable) | |
32 { | |
33 rtcEnabled = enable; | |
34 } | |
35 | |
36 bool rtcIsEnabled() | |
37 { | |
38 return rtcEnabled; | |
39 } | |
40 | |
41 u16 rtcRead(u32 address) | |
42 { | |
43 if (rtcEnabled) | |
44 { | |
45 if (address == 0x80000c8) | |
46 return rtcClockData.byte2; | |
47 else if (address == 0x80000c6) | |
48 return rtcClockData.byte1; | |
49 else if (address == 0x80000c4) | |
50 { | |
51 return rtcClockData.byte0; | |
52 } | |
53 } | |
54 | |
55 return READ16LE((&rom[address & 0x1FFFFFE])); | |
56 } | |
57 | |
58 static u8 toBCD(u8 value) | |
59 { | |
60 value = value % 100; | |
61 int l = value % 10; | |
62 int h = value / 10; | |
63 return h * 16 + l; | |
64 } | |
65 | |
66 bool rtcWrite(u32 address, u16 value) | |
67 { | |
68 if (!rtcEnabled) | |
69 return false; | |
70 | |
71 if (address == 0x80000c8) | |
72 { | |
73 rtcClockData.byte2 = (u8)value; // enable ? | |
74 } | |
75 else if (address == 0x80000c6) | |
76 { | |
77 rtcClockData.byte1 = (u8)value; // read/write | |
78 } | |
79 else if (address == 0x80000c4) | |
80 { | |
81 if (rtcClockData.byte2 & 1) | |
82 { | |
83 if (rtcClockData.state == IDLE && rtcClockData.byte0 == 1 && value == 5) | |
84 { | |
85 rtcClockData.state = COMMAND; | |
86 rtcClockData.bits = 0; | |
87 rtcClockData.command = 0; | |
88 } | |
89 else if (!(rtcClockData.byte0 & 1) && (value & 1)) // bit transfer | |
90 { | |
91 rtcClockData.byte0 = (u8)value; | |
92 switch (rtcClockData.state) | |
93 { | |
94 case COMMAND: | |
95 rtcClockData.command |= ((value & 2) >> 1) << (7-rtcClockData.bits); | |
96 rtcClockData.bits++; | |
97 if (rtcClockData.bits == 8) | |
98 { | |
99 rtcClockData.bits = 0; | |
100 switch (rtcClockData.command) | |
101 { | |
102 case 0x60: | |
103 // not sure what this command does but it doesn't take parameters | |
104 // maybe it is a reset or stop | |
105 rtcClockData.state = IDLE; | |
106 rtcClockData.bits = 0; | |
107 break; | |
108 case 0x62: | |
109 // this sets the control state but not sure what those values are | |
110 rtcClockData.state = READDATA; | |
111 rtcClockData.dataLen = 1; | |
112 break; | |
113 case 0x63: | |
114 rtcClockData.dataLen = 1; | |
115 rtcClockData.data[0] = 0x40; | |
116 rtcClockData.state = DATA; | |
117 break; | |
118 case 0x65: | |
119 { | |
120 struct tm *newtime; | |
121 time_t long_time; | |
122 | |
123 if (VBAMovieActive() || VBAMovieLoading()) | |
124 { | |
125 long_time = VBAMovieGetId() + VBAMovieGetFrameCounter()/60; | |
126 newtime = gmtime(&long_time); | |
127 } | |
128 else | |
129 { | |
130 time(&long_time); /* Get time as long integer. */ | |
131 newtime = localtime(&long_time); /* Convert to local time. */ | |
132 } | |
133 | |
134 rtcClockData.dataLen = 7; | |
135 rtcClockData.data[0] = toBCD(newtime->tm_year); | |
136 rtcClockData.data[1] = toBCD(newtime->tm_mon+1); | |
137 rtcClockData.data[2] = toBCD(newtime->tm_mday); | |
138 rtcClockData.data[3] = 0; | |
139 rtcClockData.data[4] = toBCD(newtime->tm_hour); | |
140 rtcClockData.data[5] = toBCD(newtime->tm_min); | |
141 rtcClockData.data[6] = toBCD(newtime->tm_sec); | |
142 rtcClockData.state = DATA; | |
143 break; | |
144 } | |
145 case 0x67: | |
146 { | |
147 struct tm *newtime; | |
148 time_t long_time; | |
149 | |
150 if (VBAMovieActive() || VBAMovieLoading()) | |
151 { | |
152 long_time = VBAMovieGetId() + VBAMovieGetFrameCounter()/60; | |
153 newtime = gmtime(&long_time); | |
154 } | |
155 else | |
156 { | |
157 time(&long_time); /* Get time as long integer. */ | |
158 newtime = localtime(&long_time); /* Convert to local time. */ | |
159 } | |
160 | |
161 rtcClockData.dataLen = 3; | |
162 rtcClockData.data[0] = toBCD(newtime->tm_hour); | |
163 rtcClockData.data[1] = toBCD(newtime->tm_min); | |
164 rtcClockData.data[2] = toBCD(newtime->tm_sec); | |
165 rtcClockData.state = DATA; | |
166 break; | |
167 } | |
168 default: | |
169 systemMessage(0, N_("Unknown RTC command %02x"), rtcClockData.command); | |
170 rtcClockData.state = IDLE; | |
171 break; | |
172 } | |
173 } | |
174 break; | |
175 case DATA: | |
176 if (rtcClockData.byte1 & 2) | |
177 {} | |
178 else | |
179 { | |
180 rtcClockData.byte0 = (rtcClockData.byte0 & ~2) | | |
181 ((rtcClockData.data[rtcClockData.bits >> 3] >> | |
182 (rtcClockData.bits & 7)) & 1)*2; | |
183 rtcClockData.bits++; | |
184 if (rtcClockData.bits == 8*rtcClockData.dataLen) | |
185 { | |
186 rtcClockData.bits = 0; | |
187 rtcClockData.state = IDLE; | |
188 } | |
189 } | |
190 break; | |
191 case READDATA: | |
192 if (!(rtcClockData.byte1 & 2)) | |
193 {} | |
194 else | |
195 { | |
196 rtcClockData.data[rtcClockData.bits >> 3] = | |
197 (rtcClockData.data[rtcClockData.bits >> 3] >> 1) | | |
198 ((value << 6) & 128); | |
199 rtcClockData.bits++; | |
200 if (rtcClockData.bits == 8*rtcClockData.dataLen) | |
201 { | |
202 rtcClockData.bits = 0; | |
203 rtcClockData.state = IDLE; | |
204 } | |
205 } | |
206 break; | |
207 default: | |
208 break; | |
209 } | |
210 } | |
211 else | |
212 rtcClockData.byte0 = (u8)value; | |
213 } | |
214 } | |
215 return true; | |
216 } | |
217 | |
218 void rtcReset() | |
219 { | |
220 memset(&rtcClockData, 0, sizeof(rtcClockData)); | |
221 | |
222 rtcClockData.byte0 = 0; | |
223 rtcClockData.byte1 = 0; | |
224 rtcClockData.byte2 = 0; | |
225 rtcClockData.command = 0; | |
226 rtcClockData.dataLen = 0; | |
227 rtcClockData.bits = 0; | |
228 rtcClockData.state = IDLE; | |
229 } | |
230 | |
231 void rtcSaveGame(gzFile gzFile) | |
232 { | |
233 utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData)); | |
234 } | |
235 | |
236 void rtcReadGame(gzFile gzFile) | |
237 { | |
238 utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData)); | |
239 } | |
240 |