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