ia64/xen-unstable

view tools/ioemu/hw/mc146818rtc.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 8e5fc5fe636c
children 345464c2fd47
line source
1 /*
2 * QEMU MC146818 RTC emulation
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "vl.h"
26 //#define DEBUG_CMOS
28 #define RTC_SECONDS 0
29 #define RTC_SECONDS_ALARM 1
30 #define RTC_MINUTES 2
31 #define RTC_MINUTES_ALARM 3
32 #define RTC_HOURS 4
33 #define RTC_HOURS_ALARM 5
34 #define RTC_ALARM_DONT_CARE 0xC0
36 #define RTC_DAY_OF_WEEK 6
37 #define RTC_DAY_OF_MONTH 7
38 #define RTC_MONTH 8
39 #define RTC_YEAR 9
41 #define RTC_REG_A 10
42 #define RTC_REG_B 11
43 #define RTC_REG_C 12
44 #define RTC_REG_D 13
46 #define REG_A_UIP 0x80
48 #define REG_B_SET 0x80
49 #define REG_B_PIE 0x40
50 #define REG_B_AIE 0x20
51 #define REG_B_UIE 0x10
53 struct RTCState {
54 uint8_t cmos_data[128];
55 uint8_t cmos_index;
56 struct tm current_tm;
57 int irq;
58 /* periodic timer */
59 QEMUTimer *periodic_timer;
60 int64_t next_periodic_time;
61 /* second update */
62 int64_t next_second_time;
63 QEMUTimer *second_timer;
64 QEMUTimer *second_timer2;
65 };
67 static void rtc_set_time(RTCState *s);
68 static void rtc_copy_date(RTCState *s);
70 static void rtc_timer_update(RTCState *s, int64_t current_time)
71 {
72 int period_code, period;
73 int64_t cur_clock, next_irq_clock;
75 period_code = s->cmos_data[RTC_REG_A] & 0x0f;
76 if (period_code != 0 &&
77 (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
78 if (period_code <= 2)
79 period_code += 7;
80 /* period in 32 Khz cycles */
81 period = 1 << (period_code - 1);
82 /* compute 32 khz clock */
83 cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
84 next_irq_clock = (cur_clock & ~(period - 1)) + period;
85 s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
86 qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
87 } else {
88 qemu_del_timer(s->periodic_timer);
89 }
90 }
92 static void rtc_periodic_timer(void *opaque)
93 {
94 RTCState *s = opaque;
96 rtc_timer_update(s, s->next_periodic_time);
97 s->cmos_data[RTC_REG_C] |= 0xc0;
98 pic_set_irq(s->irq, 1);
99 }
101 static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
102 {
103 RTCState *s = opaque;
105 if ((addr & 1) == 0) {
106 s->cmos_index = data & 0x7f;
107 } else {
108 #ifdef DEBUG_CMOS
109 printf("cmos: write index=0x%02x val=0x%02x\n",
110 s->cmos_index, data);
111 #endif
112 switch(s->cmos_index) {
113 case RTC_SECONDS_ALARM:
114 case RTC_MINUTES_ALARM:
115 case RTC_HOURS_ALARM:
116 /* XXX: not supported */
117 s->cmos_data[s->cmos_index] = data;
118 break;
119 case RTC_SECONDS:
120 case RTC_MINUTES:
121 case RTC_HOURS:
122 case RTC_DAY_OF_WEEK:
123 case RTC_DAY_OF_MONTH:
124 case RTC_MONTH:
125 case RTC_YEAR:
126 s->cmos_data[s->cmos_index] = data;
127 /* if in set mode, do not update the time */
128 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
129 rtc_set_time(s);
130 }
131 break;
132 case RTC_REG_A:
133 /* UIP bit is read only */
134 s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
135 (s->cmos_data[RTC_REG_A] & REG_A_UIP);
136 rtc_timer_update(s, qemu_get_clock(vm_clock));
137 break;
138 case RTC_REG_B:
139 if (data & REG_B_SET) {
140 /* set mode: reset UIP mode */
141 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
142 data &= ~REG_B_UIE;
143 } else {
144 /* if disabling set mode, update the time */
145 if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
146 rtc_set_time(s);
147 }
148 }
149 s->cmos_data[RTC_REG_B] = data;
150 rtc_timer_update(s, qemu_get_clock(vm_clock));
151 break;
152 case RTC_REG_C:
153 case RTC_REG_D:
154 /* cannot write to them */
155 break;
156 default:
157 s->cmos_data[s->cmos_index] = data;
158 break;
159 }
160 }
161 }
163 static inline int to_bcd(RTCState *s, int a)
164 {
165 if (s->cmos_data[RTC_REG_B] & 0x04) {
166 return a;
167 } else {
168 return ((a / 10) << 4) | (a % 10);
169 }
170 }
172 static inline int from_bcd(RTCState *s, int a)
173 {
174 if (s->cmos_data[RTC_REG_B] & 0x04) {
175 return a;
176 } else {
177 return ((a >> 4) * 10) + (a & 0x0f);
178 }
179 }
181 static void rtc_set_time(RTCState *s)
182 {
183 struct tm *tm = &s->current_tm;
185 tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
186 tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
187 tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
188 if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
189 (s->cmos_data[RTC_HOURS] & 0x80)) {
190 tm->tm_hour += 12;
191 }
192 tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
193 tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
194 tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
195 tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
196 }
198 static void rtc_copy_date(RTCState *s)
199 {
200 const struct tm *tm = &s->current_tm;
202 s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
203 s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
204 if (s->cmos_data[RTC_REG_B] & 0x02) {
205 /* 24 hour format */
206 s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
207 } else {
208 /* 12 hour format */
209 s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
210 if (tm->tm_hour >= 12)
211 s->cmos_data[RTC_HOURS] |= 0x80;
212 }
213 s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
214 s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
215 s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
216 s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
217 }
219 /* month is between 0 and 11. */
220 static int get_days_in_month(int month, int year)
221 {
222 static const int days_tab[12] = {
223 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
224 };
225 int d;
226 if ((unsigned )month >= 12)
227 return 31;
228 d = days_tab[month];
229 if (month == 1) {
230 if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
231 d++;
232 }
233 return d;
234 }
236 /* update 'tm' to the next second */
237 static void rtc_next_second(struct tm *tm)
238 {
239 int days_in_month;
241 tm->tm_sec++;
242 if ((unsigned)tm->tm_sec >= 60) {
243 tm->tm_sec = 0;
244 tm->tm_min++;
245 if ((unsigned)tm->tm_min >= 60) {
246 tm->tm_min = 0;
247 tm->tm_hour++;
248 if ((unsigned)tm->tm_hour >= 24) {
249 tm->tm_hour = 0;
250 /* next day */
251 tm->tm_wday++;
252 if ((unsigned)tm->tm_wday >= 7)
253 tm->tm_wday = 0;
254 days_in_month = get_days_in_month(tm->tm_mon,
255 tm->tm_year + 1900);
256 tm->tm_mday++;
257 if (tm->tm_mday < 1) {
258 tm->tm_mday = 1;
259 } else if (tm->tm_mday > days_in_month) {
260 tm->tm_mday = 1;
261 tm->tm_mon++;
262 if (tm->tm_mon >= 12) {
263 tm->tm_mon = 0;
264 tm->tm_year++;
265 }
266 }
267 }
268 }
269 }
270 }
273 static void rtc_update_second(void *opaque)
274 {
275 RTCState *s = opaque;
276 int64_t delay;
278 /* if the oscillator is not in normal operation, we do not update */
279 if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
280 s->next_second_time += ticks_per_sec;
281 qemu_mod_timer(s->second_timer, s->next_second_time);
282 } else {
283 rtc_next_second(&s->current_tm);
285 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
286 /* update in progress bit */
287 s->cmos_data[RTC_REG_A] |= REG_A_UIP;
288 }
289 /* should be 244 us = 8 / 32768 seconds, but currently the
290 timers do not have the necessary resolution. */
291 delay = (ticks_per_sec * 1) / 100;
292 if (delay < 1)
293 delay = 1;
294 qemu_mod_timer(s->second_timer2,
295 s->next_second_time + delay);
296 }
297 }
299 static void rtc_update_second2(void *opaque)
300 {
301 RTCState *s = opaque;
303 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
304 rtc_copy_date(s);
305 }
307 /* check alarm */
308 if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
309 if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
310 s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
311 ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
312 s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
313 ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
314 s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
316 s->cmos_data[RTC_REG_C] |= 0xa0;
317 pic_set_irq(s->irq, 1);
318 }
319 }
321 /* update ended interrupt */
322 if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
323 s->cmos_data[RTC_REG_C] |= 0x90;
324 pic_set_irq(s->irq, 1);
325 }
327 /* clear update in progress bit */
328 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
330 s->next_second_time += ticks_per_sec;
331 qemu_mod_timer(s->second_timer, s->next_second_time);
332 }
334 static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
335 {
336 RTCState *s = opaque;
337 int ret;
338 if ((addr & 1) == 0) {
339 return 0xff;
340 } else {
341 switch(s->cmos_index) {
342 case RTC_SECONDS:
343 case RTC_MINUTES:
344 case RTC_HOURS:
345 case RTC_DAY_OF_WEEK:
346 case RTC_DAY_OF_MONTH:
347 case RTC_MONTH:
348 case RTC_YEAR:
349 ret = s->cmos_data[s->cmos_index];
350 break;
351 case RTC_REG_A:
352 ret = s->cmos_data[s->cmos_index];
353 break;
354 case RTC_REG_C:
355 ret = s->cmos_data[s->cmos_index];
356 pic_set_irq(s->irq, 0);
357 s->cmos_data[RTC_REG_C] = 0x00;
358 break;
359 default:
360 ret = s->cmos_data[s->cmos_index];
361 break;
362 }
363 #ifdef DEBUG_CMOS
364 printf("cmos: read index=0x%02x val=0x%02x\n",
365 s->cmos_index, ret);
366 #endif
367 return ret;
368 }
369 }
371 void rtc_set_memory(RTCState *s, int addr, int val)
372 {
373 if (addr >= 0 && addr <= 127)
374 s->cmos_data[addr] = val;
375 }
377 void rtc_set_date(RTCState *s, const struct tm *tm)
378 {
379 s->current_tm = *tm;
380 rtc_copy_date(s);
381 }
383 static void rtc_save(QEMUFile *f, void *opaque)
384 {
385 RTCState *s = opaque;
387 qemu_put_buffer(f, s->cmos_data, 128);
388 qemu_put_8s(f, &s->cmos_index);
390 qemu_put_be32s(f, &s->current_tm.tm_sec);
391 qemu_put_be32s(f, &s->current_tm.tm_min);
392 qemu_put_be32s(f, &s->current_tm.tm_hour);
393 qemu_put_be32s(f, &s->current_tm.tm_wday);
394 qemu_put_be32s(f, &s->current_tm.tm_mday);
395 qemu_put_be32s(f, &s->current_tm.tm_mon);
396 qemu_put_be32s(f, &s->current_tm.tm_year);
398 qemu_put_timer(f, s->periodic_timer);
399 qemu_put_be64s(f, &s->next_periodic_time);
401 qemu_put_be64s(f, &s->next_second_time);
402 qemu_put_timer(f, s->second_timer);
403 qemu_put_timer(f, s->second_timer2);
404 }
406 static int rtc_load(QEMUFile *f, void *opaque, int version_id)
407 {
408 RTCState *s = opaque;
410 if (version_id != 1)
411 return -EINVAL;
413 qemu_get_buffer(f, s->cmos_data, 128);
414 qemu_get_8s(f, &s->cmos_index);
416 qemu_get_be32s(f, &s->current_tm.tm_sec);
417 qemu_get_be32s(f, &s->current_tm.tm_min);
418 qemu_get_be32s(f, &s->current_tm.tm_hour);
419 qemu_get_be32s(f, &s->current_tm.tm_wday);
420 qemu_get_be32s(f, &s->current_tm.tm_mday);
421 qemu_get_be32s(f, &s->current_tm.tm_mon);
422 qemu_get_be32s(f, &s->current_tm.tm_year);
424 qemu_get_timer(f, s->periodic_timer);
425 qemu_get_be64s(f, &s->next_periodic_time);
427 qemu_get_be64s(f, &s->next_second_time);
428 qemu_get_timer(f, s->second_timer);
429 qemu_get_timer(f, s->second_timer2);
430 return 0;
431 }
433 RTCState *rtc_init(int base, int irq)
434 {
435 RTCState *s;
437 s = qemu_mallocz(sizeof(RTCState));
438 if (!s)
439 return NULL;
441 s->irq = irq;
442 s->cmos_data[RTC_REG_A] = 0x26;
443 s->cmos_data[RTC_REG_B] = 0x02;
444 s->cmos_data[RTC_REG_C] = 0x00;
445 s->cmos_data[RTC_REG_D] = 0x80;
447 s->periodic_timer = qemu_new_timer(vm_clock,
448 rtc_periodic_timer, s);
449 s->second_timer = qemu_new_timer(vm_clock,
450 rtc_update_second, s);
451 s->second_timer2 = qemu_new_timer(vm_clock,
452 rtc_update_second2, s);
454 s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
455 qemu_mod_timer(s->second_timer2, s->next_second_time);
457 register_ioport_write(base, 2, 1, cmos_ioport_write, s);
458 register_ioport_read(base, 2, 1, cmos_ioport_read, s);
460 register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
461 return s;
462 }