view src/gba/RTC.cpp @ 536:c2ee7222a3c4

investigating a problem with bad sound when writing RAM with bootstrapping program
author Robert McIntyre <rlm@mit.edu>
date Mon, 25 Jun 2012 14:23:16 -0500
parents f9f4f1b99eed
children
line wrap: on
line source
1 #include <cstring>
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"
10 enum RTCSTATE { IDLE, COMMAND, DATA, READDATA };
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;
28 static RTCCLOCKDATA rtcClockData;
29 static bool rtcEnabled = false;
31 void rtcEnable(bool enable)
32 {
33 rtcEnabled = enable;
34 }
36 bool rtcIsEnabled()
37 {
38 return rtcEnabled;
39 }
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 }
55 return READ16LE((&rom[address & 0x1FFFFFE]));
56 }
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 }
66 bool rtcWrite(u32 address, u16 value)
67 {
68 if (!rtcEnabled)
69 return false;
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;
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 }
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;
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 }
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 }
218 void rtcReset()
219 {
220 memset(&rtcClockData, 0, sizeof(rtcClockData));
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 }
231 void rtcSaveGame(gzFile gzFile)
232 {
233 utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData));
234 }
236 void rtcReadGame(gzFile gzFile)
237 {
238 utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData));
239 }