1 // Based on MAME sources by Aaron Giles,smf
2
3 #include "burnint.h"
4 #include "time.h"
5 #include "timekpr.h"
6
7 typedef struct
8 {
9 UINT8 control;
10 UINT8 seconds;
11 UINT8 minutes;
12 UINT8 hours;
13 UINT8 day;
14 UINT8 date;
15 UINT8 month;
16 UINT8 year;
17 UINT8 century;
18 UINT8 *data;
19 INT32 type;
20 INT32 size;
21 INT32 offset_control;
22 INT32 offset_seconds;
23 INT32 offset_minutes;
24 INT32 offset_hours;
25 INT32 offset_day;
26 INT32 offset_date;
27 INT32 offset_month;
28 INT32 offset_year;
29 INT32 offset_century;
30 INT32 offset_flags;
31 } timekeeper_chip;
32
33 static timekeeper_chip Chip;
34
35 static INT32 AllocatedOwnDataArea = 0;
36
37 #define MASK_SECONDS ( 0x7f )
38 #define MASK_MINUTES ( 0x7f )
39 #define MASK_HOURS ( 0x3f )
40 #define MASK_DAY ( 0x07 )
41 #define MASK_DATE ( 0x3f )
42 #define MASK_MONTH ( 0x1f )
43 #define MASK_YEAR ( 0xff )
44 #define MASK_CENTURY ( 0xff )
45
46 #define CONTROL_W ( 0x80 )
47 #define CONTROL_R ( 0x40 )
48 #define CONTROL_S ( 0x20 ) /* not emulated */
49 #define CONTROL_CALIBRATION ( 0x1f ) /* not emulated */
50
51 #define SECONDS_ST ( 0x80 )
52
53 #define DAY_FT ( 0x40 ) /* M48T37 - not emulated */
54 #define DAY_CEB ( 0x20 ) /* M48T35/M48T58 */
55 #define DAY_CB ( 0x10 ) /* M48T35/M48T58 */
56
57 #define DATE_BLE ( 0x80 ) /* M48T58: not emulated */
58 #define DATE_BL ( 0x40 ) /* M48T58: not emulated */
59
60 #define FLAGS_BL ( 0x10 ) /* MK48T08/M48T37: not emulated */
61 #define FLAGS_AF ( 0x40 ) /* M48T37: not emulated */
62 #define FLAGS_WDF ( 0x80 ) /* M48T37: not emulated */
63
make_bcd(UINT8 data)64 static inline UINT8 make_bcd(UINT8 data)
65 {
66 return ( ( ( data / 10 ) % 10 ) << 4 ) + ( data % 10 );
67 }
68
from_bcd(UINT8 data)69 static inline UINT8 from_bcd(UINT8 data)
70 {
71 return ( ( ( data >> 4 ) & 15 ) * 10 ) + ( data & 15 );
72 }
73
inc_bcd(UINT8 * data,INT32 mask,INT32 min,INT32 max)74 static INT32 inc_bcd( UINT8 *data, INT32 mask, INT32 min, INT32 max )
75 {
76 INT32 bcd;
77 INT32 carry;
78
79 bcd = ( *( data ) + 1 ) & mask;
80 carry = 0;
81
82 if( ( bcd & 0x0f ) > 9 )
83 {
84 bcd &= 0xf0;
85 bcd += 0x10;
86 if( bcd > max )
87 {
88 bcd = min;
89 carry = 1;
90 }
91 }
92
93 *( data ) = ( *( data ) & ~mask ) | ( bcd & mask );
94 return carry;
95 }
96
counter_to_ram(UINT8 * data,INT32 offset,INT32 counter)97 static void counter_to_ram(UINT8 *data, INT32 offset, INT32 counter)
98 {
99 if( offset >= 0 )
100 {
101 data[ offset ] = counter;
102 }
103 }
104
counters_to_ram()105 static void counters_to_ram()
106 {
107 counter_to_ram( Chip.data, Chip.offset_control, Chip.control );
108 counter_to_ram( Chip.data, Chip.offset_seconds, Chip.seconds );
109 counter_to_ram( Chip.data, Chip.offset_minutes, Chip.minutes );
110 counter_to_ram( Chip.data, Chip.offset_hours, Chip.hours );
111 counter_to_ram( Chip.data, Chip.offset_day, Chip.day );
112 counter_to_ram( Chip.data, Chip.offset_date, Chip.date );
113 counter_to_ram( Chip.data, Chip.offset_month, Chip.month );
114 counter_to_ram( Chip.data, Chip.offset_year, Chip.year );
115 counter_to_ram( Chip.data, Chip.offset_century, Chip.century );
116 }
117
counter_from_ram(UINT8 * data,INT32 offset)118 static INT32 counter_from_ram(UINT8 *data, INT32 offset)
119 {
120 if( offset >= 0 )
121 {
122 return data[ offset ];
123 }
124 return 0;
125 }
126
counters_from_ram()127 static void counters_from_ram()
128 {
129 Chip.control = counter_from_ram( Chip.data, Chip.offset_control );
130 Chip.seconds = counter_from_ram( Chip.data, Chip.offset_seconds );
131 Chip.minutes = counter_from_ram( Chip.data, Chip.offset_minutes );
132 Chip.hours = counter_from_ram( Chip.data, Chip.offset_hours );
133 Chip.day = counter_from_ram( Chip.data, Chip.offset_day );
134 Chip.date = counter_from_ram( Chip.data, Chip.offset_date );
135 Chip.month = counter_from_ram( Chip.data, Chip.offset_month );
136 Chip.year = counter_from_ram( Chip.data, Chip.offset_year );
137 Chip.century = counter_from_ram( Chip.data, Chip.offset_century );
138 }
139
TimeKeeperRead(UINT32 offset)140 UINT8 TimeKeeperRead(UINT32 offset)
141 {
142 #if defined FBNEO_DEBUG
143 if (!DebugDev_TimeKprInitted) bprintf(PRINT_ERROR, _T("TimeKeeperRead called without init\n"));
144 #endif
145
146 return Chip.data[offset];
147 }
148
TimeKeeperIsEmpty()149 INT32 TimeKeeperIsEmpty()
150 {
151 #if defined FBNEO_DEBUG
152 if (!DebugDev_TimeKprInitted) bprintf(PRINT_ERROR, _T("TimeKeeperIsEmpty called without init\n"));
153 #endif
154
155 INT32 found = 0;
156
157 for (INT32 i = 0; i < Chip.size; i++) {
158 if (Chip.data[i] != 0xff)
159 found = 1;
160 }
161
162 return !found;
163 }
164
TimeKeeperGetRaw()165 UINT8* TimeKeeperGetRaw()
166 {
167 #if defined FBNEO_DEBUG
168 if (!DebugDev_TimeKprInitted) bprintf(PRINT_ERROR, _T("TimeKeeperGetRaw called without init\n"));
169 #endif
170
171 return Chip.data;
172 }
173
TimeKeeperWrite(INT32 offset,UINT8 data)174 void TimeKeeperWrite(INT32 offset, UINT8 data)
175 {
176 #if defined FBNEO_DEBUG
177 if (!DebugDev_TimeKprInitted) bprintf(PRINT_ERROR, _T("TimeKeeperWrite called without init\n"));
178 #endif
179
180 if( offset == Chip.offset_control )
181 {
182 if( ( Chip.control & CONTROL_W ) != 0 &&
183 ( data & CONTROL_W ) == 0 )
184 {
185 counters_from_ram();
186 }
187 Chip.control = data;
188 }
189 else if( (Chip.type == TIMEKEEPER_M48T58 || Chip.type == TIMEKEEPER_M48T35) && offset == Chip.offset_day )
190 {
191 Chip.day = ( Chip.day & ~DAY_CEB ) | ( data & DAY_CEB );
192 }
193
194 Chip.data[ offset ] = data;
195 }
196
TimeKeeperTick()197 void TimeKeeperTick()
198 {
199 #if defined FBNEO_DEBUG
200 if (!DebugDev_TimeKprInitted) bprintf(PRINT_ERROR, _T("TimeKeeperTick called without init\n"));
201 #endif
202
203 INT32 carry;
204
205 if( ( Chip.seconds & SECONDS_ST ) != 0 ||
206 ( Chip.control & CONTROL_W ) != 0 )
207 {
208 return;
209 }
210
211 carry = inc_bcd( &Chip.seconds, MASK_SECONDS, 0x00, 0x59 );
212 if( carry )
213 {
214 carry = inc_bcd( &Chip.minutes, MASK_MINUTES, 0x00, 0x59 );
215 }
216 if( carry )
217 {
218 carry = inc_bcd( &Chip.hours, MASK_HOURS, 0x00, 0x23 );
219 }
220
221 if( carry )
222 {
223 UINT8 month;
224 UINT8 year;
225 UINT8 maxdays;
226 static const UINT8 daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 };
227
228 inc_bcd( &Chip.day, MASK_DAY, 0x01, 0x07 );
229
230 month = from_bcd( Chip.month );
231 year = from_bcd( Chip.year );
232
233 if( month == 2 && ( year % 4 ) == 0 )
234 {
235 maxdays = 0x29;
236 }
237 else if( month >= 1 && month <= 12 )
238 {
239 maxdays = daysinmonth[ month - 1 ];
240 }
241 else
242 {
243 maxdays = 0x31;
244 }
245
246 carry = inc_bcd( &Chip.date, MASK_DATE, 0x01, maxdays );
247 }
248 if( carry )
249 {
250 carry = inc_bcd( &Chip.month, MASK_MONTH, 0x01, 0x12 );
251 }
252 if( carry )
253 {
254 carry = inc_bcd( &Chip.year, MASK_YEAR, 0x00, 0x99 );
255 }
256 if( carry )
257 {
258 carry = inc_bcd( &Chip.century, MASK_CENTURY, 0x00, 0x99 );
259 if( (Chip.type == TIMEKEEPER_M48T58 || Chip.type == TIMEKEEPER_M48T35) && ( Chip.day & DAY_CEB ) != 0 )
260 {
261 Chip.day ^= DAY_CB;
262 }
263 }
264
265 if( ( Chip.control & CONTROL_R ) == 0 )
266 {
267 counters_to_ram();
268 }
269 }
270
TimeKeeperInit(INT32 type,UINT8 * data)271 void TimeKeeperInit(INT32 type, UINT8 *data)
272 {
273 DebugDev_TimeKprInitted = 1;
274
275 struct tm timeinfo;
276
277 Chip.type = type;
278
279 switch( Chip.type )
280 {
281 case TIMEKEEPER_M48T02:
282 Chip.offset_control = 0x7f8;
283 Chip.offset_seconds = 0x7f9;
284 Chip.offset_minutes = 0x7fa;
285 Chip.offset_hours = 0x7fb;
286 Chip.offset_day = 0x7fc;
287 Chip.offset_date = 0x7fd;
288 Chip.offset_month = 0x7fe;
289 Chip.offset_year = 0x7ff;
290 Chip.offset_century = -1;
291 Chip.offset_flags = -1;
292 Chip.size = 0x800;
293 break;
294 case TIMEKEEPER_M48T35:
295 Chip.offset_control = 0x7ff8;
296 Chip.offset_seconds = 0x7ff9;
297 Chip.offset_minutes = 0x7ffa;
298 Chip.offset_hours = 0x7ffb;
299 Chip.offset_day = 0x7ffc;
300 Chip.offset_date = 0x7ffd;
301 Chip.offset_month = 0x7ffe;
302 Chip.offset_year = 0x7fff;
303 Chip.offset_century = -1;
304 Chip.offset_flags = -1;
305 Chip.size = 0x8000;
306 break;
307 case TIMEKEEPER_M48T37:
308 Chip.offset_control = 0x7ff8;
309 Chip.offset_seconds = 0x7ff9;
310 Chip.offset_minutes = 0x7ffa;
311 Chip.offset_hours = 0x7ffb;
312 Chip.offset_day = 0x7ffc;
313 Chip.offset_date = 0x7ffd;
314 Chip.offset_month = 0x7ffe;
315 Chip.offset_year = 0x7fff;
316 Chip.offset_century = 0x7ff1;
317 Chip.offset_flags = 0x7ff0;
318 Chip.size = 0x8000;
319 break;
320 case TIMEKEEPER_M48T58:
321 Chip.offset_control = 0x1ff8;
322 Chip.offset_seconds = 0x1ff9;
323 Chip.offset_minutes = 0x1ffa;
324 Chip.offset_hours = 0x1ffb;
325 Chip.offset_day = 0x1ffc;
326 Chip.offset_date = 0x1ffd;
327 Chip.offset_month = 0x1ffe;
328 Chip.offset_year = 0x1fff;
329 Chip.offset_century = -1;
330 Chip.offset_flags = -1;
331 Chip.size = 0x2000;
332 break;
333 case TIMEKEEPER_MK48T08:
334 Chip.offset_control = 0x1ff8;
335 Chip.offset_seconds = 0x1ff9;
336 Chip.offset_minutes = 0x1ffa;
337 Chip.offset_hours = 0x1ffb;
338 Chip.offset_day = 0x1ffc;
339 Chip.offset_date = 0x1ffd;
340 Chip.offset_month = 0x1ffe;
341 Chip.offset_year = 0x1fff;
342 Chip.offset_century = 0x1ff1;
343 Chip.offset_flags = 0x1ff0;
344 Chip.size = 0x2000;
345 break;
346 }
347
348 if( data == NULL )
349 {
350 data = (UINT8*)BurnMalloc(Chip.size);
351 memset(data, 0xff, Chip.size );
352 AllocatedOwnDataArea = 1;
353 }
354 Chip.data = data;
355
356 BurnGetLocalTime(&timeinfo);
357
358 Chip.control = 0;
359 Chip.seconds = make_bcd(timeinfo.tm_sec);
360 Chip.minutes = make_bcd(timeinfo.tm_min);
361 Chip.hours = make_bcd(timeinfo.tm_hour);
362 Chip.day = make_bcd(timeinfo.tm_wday + 1 );
363 Chip.date = make_bcd(timeinfo.tm_mday );
364 Chip.month = make_bcd(timeinfo.tm_mon + 1 );
365 Chip.year = make_bcd(timeinfo.tm_year % 100 );
366 Chip.century = make_bcd(timeinfo.tm_year / 100 );
367 }
368
TimeKeeperExit()369 void TimeKeeperExit()
370 {
371 #if defined FBNEO_DEBUG
372 if (!DebugDev_TimeKprInitted) bprintf(PRINT_ERROR, _T("TimeKeeperExit called without init\n"));
373 #endif
374
375 if (AllocatedOwnDataArea) {
376 BurnFree (Chip.data);
377 }
378 AllocatedOwnDataArea = 0;
379 memset(&Chip, 0, sizeof(Chip));
380
381 DebugDev_TimeKprInitted = 0;
382 }
383
TimeKeeperScan(INT32 nAction)384 void TimeKeeperScan(INT32 nAction)
385 {
386 #if defined FBNEO_DEBUG
387 if (!DebugDev_TimeKprInitted) bprintf(PRINT_ERROR, _T("TimeKeeperScan called without init\n"));
388 #endif
389
390 struct BurnArea ba;
391
392 if (nAction & ACB_NVRAM) {
393 memset(&ba, 0, sizeof(ba));
394 ba.Data = Chip.data;
395 ba.nLen = Chip.size;
396 ba.szName = "Time Keeper RAM";
397 BurnAcb(&ba);
398 }
399 }
400