hvf: use yacc & re2c to generate a system config parser
[hvf.git] / lib / clock.c
blobc83b94b6a703b3b7574d643422d01e494206aa67
1 /*
2 * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
5 * details.
6 */
8 #include <clock.h>
10 #define LS_NONE 0x00 /* non-leap second entry */
11 #define LS_LS 0x10 /* previous second was leap */
13 #define LS_MASK (LS_LS)
15 #define LS_YM2DATE(y, m, f) ((y) << 8 | (f) | (m))
16 #define LS_DATE2Y(d) ((d) >> 8)
17 #define LS_DATE2M(d) ((d) & 0xf)
18 #define LS_DATE2F(d) ((d) & LS_MASK)
20 struct leap_sec_info {
21 u64 tod;
22 u32 date;
26 * List of TOD clocks for each of the leap seconds
28 static struct leap_sec_info leap_secs[] = {
29 { 0xC3870CB9BB600000ULL, LS_YM2DATE(2009, 1, LS_LS ), },
30 { 0xBE251097973C0000ULL, LS_YM2DATE(2006, 1, LS_LS ), },
31 { 0xB1962F9305180000ULL, LS_YM2DATE(1999, 1, LS_LS ), },
32 { 0xAEE3EFA402F40000ULL, LS_YM2DATE(1997, 7, LS_LS ), },
33 { 0xAC34336FECD00000ULL, LS_YM2DATE(1996, 1, LS_LS ), },
34 { 0xA981F380EAAC0000ULL, LS_YM2DATE(1994, 7, LS_LS ), },
35 { 0xA7B70ABEB8880000ULL, LS_YM2DATE(1993, 7, LS_LS ), },
36 { 0xA5EC21FC86640000ULL, LS_YM2DATE(1992, 7, LS_LS ), },
37 { 0xA33C65C870400000ULL, LS_YM2DATE(1991, 1, LS_LS ), },
38 { 0xA1717D063E1C0000ULL, LS_YM2DATE(1990, 1, LS_LS ), },
39 { 0x9DDA69A557F80000ULL, LS_YM2DATE(1988, 1, LS_LS ), },
40 { 0x995D40F517D40000ULL, LS_YM2DATE(1985, 7, LS_LS ), },
41 { 0x95C62D9431B00000ULL, LS_YM2DATE(1983, 7, LS_LS ), },
42 { 0x93FB44D1FF8C0000ULL, LS_YM2DATE(1982, 7, LS_LS ), },
43 { 0x92305C0FCD680000ULL, LS_YM2DATE(1981, 7, LS_LS ), },
44 { 0x8F809FDBB7440000ULL, LS_YM2DATE(1980, 1, LS_LS ), },
45 { 0x8DB5B71985200000ULL, LS_YM2DATE(1979, 1, LS_LS ), },
46 { 0x8BEACE5752FC0000ULL, LS_YM2DATE(1978, 1, LS_LS ), },
47 { 0x8A1FE59520D80000ULL, LS_YM2DATE(1977, 1, LS_LS ), },
48 { 0x8853BAF578B40000ULL, LS_YM2DATE(1976, 1, LS_LS ), },
49 { 0x8688D23346900000ULL, LS_YM2DATE(1975, 1, LS_LS ), },
50 { 0x84BDE971146C0000ULL, LS_YM2DATE(1974, 1, LS_LS ), },
51 { 0x82F300AEE2480000ULL, LS_YM2DATE(1973, 1, LS_LS ), },
52 { 0x820BA9811E240000ULL, LS_YM2DATE(1972, 7, LS_LS ), },
53 { 0x8126D60E46000000ULL, LS_YM2DATE(1972, 1, LS_NONE), }, /* UTC begins */
54 { 0x0000000000000000ULL, LS_YM2DATE(1900, 1, LS_NONE), }, /* TOD begins */
58 * Number of days passed since the beginning of the year
60 static const short int month_offsets[2][12] = {
61 /* J F M A M J J A S O N D */
62 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
63 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
66 struct datetime *parse_tod(struct datetime *dt, u64 tod)
68 int add_sec;
69 int leap;
70 int done;
71 int i,j;
74 * find the most recent info for this tod (i), as well as for one
75 * that's one second ahead (j)
77 for (i=0; leap_secs[i].tod > tod; i++)
79 for (j=0; leap_secs[j].tod > (tod + CLK_SEC); j++)
82 tod -= leap_secs[i].tod;
84 dt->dy = LS_DATE2Y(leap_secs[i].date);
85 dt->dm = LS_DATE2M(leap_secs[i].date);
88 * If we're in the leap second, let's pretend we're a second
89 * earlier, and then add it back in at the end of the function
91 add_sec = 0;
93 if ((i != j) && (LS_DATE2F(leap_secs[j].date) == LS_LS)) {
94 tod -= CLK_SEC;
95 add_sec = 1;
98 /* The month should be 1 or 7! */
99 if ((dt->dm != 1) && (dt->dm != 7))
100 return NULL;
103 * At this point, we have a TOD value to add to a struct datetime.
104 * We don't have to worry about leap seconds. Life is good.
107 for(;;) {
108 if (leap_year((dt->dm == 1) ? dt->dy : (dt->dy+1)))
109 done = tod < (CLK_YEAR + CLK_DAY);
110 else
111 done = tod < CLK_YEAR;
113 if (done)
114 break;
116 if ((dt->dm == 1 && leap_year(dt->dy)) ||
117 (dt->dm == 7 && leap_year(dt->dy+1)))
118 tod -= (CLK_YEAR + CLK_DAY);
119 else
120 tod -= CLK_YEAR;
122 dt->dy++;
126 * At this point, we have the year and we know the month is either Jan
127 * or Jul; let's get an actual month
130 dt->dd = tod / CLK_DAY;
131 tod -= dt->dd * CLK_DAY;
133 do {
134 leap = leap_year(dt->dy);
135 i = month_offsets[leap][dt->dm - 1];
137 while((dt->dm < 12) &&
138 ((i + dt->dd) >= month_offsets[leap][dt->dm]))
139 dt->dm++;
141 dt->dd = dt->dd + i - month_offsets[leap][dt->dm-1];
143 if ((dt->dm < 12) || (dt->dd < 31))
144 break;
146 dt->dy++;
147 dt->dm = 1;
148 dt->dd -= 31;
149 } while(1);
151 dt->dd++;
154 * At this point, we have the year, the month, and even the day;
155 * let's get the hours, minutes and seconds
158 dt->th = tod / CLK_HOUR;
159 tod -= dt->th * CLK_HOUR;
161 dt->tm = tod / CLK_MIN;
162 tod -= dt->tm * CLK_MIN;
164 dt->ts = tod / CLK_SEC;
165 tod -= dt->ts * CLK_SEC;
168 * If we borrowed a second before, then add it back! (We borrow only
169 * for leap seconds in progress.)
171 dt->ts += add_sec;
173 dt->tmicro = (u32) (tod >> 12);
175 return dt;