]> Git Repo - qemu.git/blob - hw/mc146818rtc.c
mc146818: add square wave output support
[qemu.git] / hw / mc146818rtc.c
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 "hw.h"
25 #include "qemu-timer.h"
26 #include "sysemu.h"
27 #include "pc.h"
28 #include "isa.h"
29 #include "hpet_emul.h"
30
31 //#define DEBUG_CMOS
32
33 #define RTC_SECONDS             0
34 #define RTC_SECONDS_ALARM       1
35 #define RTC_MINUTES             2
36 #define RTC_MINUTES_ALARM       3
37 #define RTC_HOURS               4
38 #define RTC_HOURS_ALARM         5
39 #define RTC_ALARM_DONT_CARE    0xC0
40
41 #define RTC_DAY_OF_WEEK         6
42 #define RTC_DAY_OF_MONTH        7
43 #define RTC_MONTH               8
44 #define RTC_YEAR                9
45
46 #define RTC_REG_A               10
47 #define RTC_REG_B               11
48 #define RTC_REG_C               12
49 #define RTC_REG_D               13
50
51 #define REG_A_UIP 0x80
52
53 #define REG_B_SET  0x80
54 #define REG_B_PIE  0x40
55 #define REG_B_AIE  0x20
56 #define REG_B_UIE  0x10
57 #define REG_B_SQWE 0x08
58 #define REG_B_DM   0x04
59
60 struct RTCState {
61     uint8_t cmos_data[128];
62     uint8_t cmos_index;
63     struct tm current_tm;
64     int base_year;
65     qemu_irq irq;
66     qemu_irq sqw_irq;
67     int it_shift;
68     /* periodic timer */
69     QEMUTimer *periodic_timer;
70     int64_t next_periodic_time;
71     /* second update */
72     int64_t next_second_time;
73 #ifdef TARGET_I386
74     uint32_t irq_coalesced;
75     uint32_t period;
76 #endif
77     QEMUTimer *second_timer;
78     QEMUTimer *second_timer2;
79 };
80
81 static void rtc_irq_raise(qemu_irq irq) {
82     /* When HPET is operating in legacy mode, RTC interrupts are disabled
83      * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
84      * mode is established while interrupt is raised. We want it to
85      * be lowered in any case
86      */
87 #if defined TARGET_I386 || defined TARGET_X86_64
88     if (!hpet_in_legacy_mode())
89 #endif
90         qemu_irq_raise(irq);
91 }
92
93 static void rtc_set_time(RTCState *s);
94 static void rtc_copy_date(RTCState *s);
95
96 static void rtc_timer_update(RTCState *s, int64_t current_time)
97 {
98     int period_code, period;
99     int64_t cur_clock, next_irq_clock;
100     int enable_pie;
101
102     period_code = s->cmos_data[RTC_REG_A] & 0x0f;
103 #if defined TARGET_I386 || defined TARGET_X86_64
104     /* disable periodic timer if hpet is in legacy mode, since interrupts are
105      * disabled anyway.
106      */
107     enable_pie = hpet_in_legacy_mode();
108 #else
109     enable_pie = 1;
110 #endif
111     if (period_code != 0
112         && (((s->cmos_data[RTC_REG_B] & REG_B_PIE) && enable_pie)
113             || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
114         if (period_code <= 2)
115             period_code += 7;
116         /* period in 32 Khz cycles */
117         period = 1 << (period_code - 1);
118 #ifdef TARGET_I386
119         if(period != s->period)
120             s->irq_coalesced = (s->irq_coalesced * s->period) / period;
121         s->period = period;
122 #endif
123         /* compute 32 khz clock */
124         cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
125         next_irq_clock = (cur_clock & ~(period - 1)) + period;
126         s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
127         qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
128     } else {
129 #ifdef TARGET_I386
130         s->irq_coalesced = 0;
131 #endif
132         qemu_del_timer(s->periodic_timer);
133     }
134 }
135
136 static void rtc_periodic_timer(void *opaque)
137 {
138     RTCState *s = opaque;
139
140     rtc_timer_update(s, s->next_periodic_time);
141 #ifdef TARGET_I386
142     if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) {
143         s->irq_coalesced++;
144         return;
145     }
146 #endif
147     if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
148         s->cmos_data[RTC_REG_C] |= 0xc0;
149         rtc_irq_raise(s->irq);
150     }
151     if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
152         /* Not square wave at all but we don't want 2048Hz interrupts!
153            Must be seen as a pulse.  */
154         qemu_irq_raise(s->sqw_irq);
155     }
156 }
157
158 static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
159 {
160     RTCState *s = opaque;
161
162     if ((addr & 1) == 0) {
163         s->cmos_index = data & 0x7f;
164     } else {
165 #ifdef DEBUG_CMOS
166         printf("cmos: write index=0x%02x val=0x%02x\n",
167                s->cmos_index, data);
168 #endif
169         switch(s->cmos_index) {
170         case RTC_SECONDS_ALARM:
171         case RTC_MINUTES_ALARM:
172         case RTC_HOURS_ALARM:
173             /* XXX: not supported */
174             s->cmos_data[s->cmos_index] = data;
175             break;
176         case RTC_SECONDS:
177         case RTC_MINUTES:
178         case RTC_HOURS:
179         case RTC_DAY_OF_WEEK:
180         case RTC_DAY_OF_MONTH:
181         case RTC_MONTH:
182         case RTC_YEAR:
183             s->cmos_data[s->cmos_index] = data;
184             /* if in set mode, do not update the time */
185             if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
186                 rtc_set_time(s);
187             }
188             break;
189         case RTC_REG_A:
190             /* UIP bit is read only */
191             s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
192                 (s->cmos_data[RTC_REG_A] & REG_A_UIP);
193             rtc_timer_update(s, qemu_get_clock(vm_clock));
194             break;
195         case RTC_REG_B:
196             if (data & REG_B_SET) {
197                 /* set mode: reset UIP mode */
198                 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
199                 data &= ~REG_B_UIE;
200             } else {
201                 /* if disabling set mode, update the time */
202                 if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
203                     rtc_set_time(s);
204                 }
205             }
206             s->cmos_data[RTC_REG_B] = data;
207             rtc_timer_update(s, qemu_get_clock(vm_clock));
208             break;
209         case RTC_REG_C:
210         case RTC_REG_D:
211             /* cannot write to them */
212             break;
213         default:
214             s->cmos_data[s->cmos_index] = data;
215             break;
216         }
217     }
218 }
219
220 static inline int to_bcd(RTCState *s, int a)
221 {
222     if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
223         return a;
224     } else {
225         return ((a / 10) << 4) | (a % 10);
226     }
227 }
228
229 static inline int from_bcd(RTCState *s, int a)
230 {
231     if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
232         return a;
233     } else {
234         return ((a >> 4) * 10) + (a & 0x0f);
235     }
236 }
237
238 static void rtc_set_time(RTCState *s)
239 {
240     struct tm *tm = &s->current_tm;
241
242     tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
243     tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
244     tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
245     if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
246         (s->cmos_data[RTC_HOURS] & 0x80)) {
247         tm->tm_hour += 12;
248     }
249     tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
250     tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
251     tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
252     tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
253 }
254
255 static void rtc_copy_date(RTCState *s)
256 {
257     const struct tm *tm = &s->current_tm;
258     int year;
259
260     s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
261     s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
262     if (s->cmos_data[RTC_REG_B] & 0x02) {
263         /* 24 hour format */
264         s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
265     } else {
266         /* 12 hour format */
267         s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
268         if (tm->tm_hour >= 12)
269             s->cmos_data[RTC_HOURS] |= 0x80;
270     }
271     s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday + 1);
272     s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
273     s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
274     year = (tm->tm_year - s->base_year) % 100;
275     if (year < 0)
276         year += 100;
277     s->cmos_data[RTC_YEAR] = to_bcd(s, year);
278 }
279
280 /* month is between 0 and 11. */
281 static int get_days_in_month(int month, int year)
282 {
283     static const int days_tab[12] = {
284         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
285     };
286     int d;
287     if ((unsigned )month >= 12)
288         return 31;
289     d = days_tab[month];
290     if (month == 1) {
291         if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
292             d++;
293     }
294     return d;
295 }
296
297 /* update 'tm' to the next second */
298 static void rtc_next_second(struct tm *tm)
299 {
300     int days_in_month;
301
302     tm->tm_sec++;
303     if ((unsigned)tm->tm_sec >= 60) {
304         tm->tm_sec = 0;
305         tm->tm_min++;
306         if ((unsigned)tm->tm_min >= 60) {
307             tm->tm_min = 0;
308             tm->tm_hour++;
309             if ((unsigned)tm->tm_hour >= 24) {
310                 tm->tm_hour = 0;
311                 /* next day */
312                 tm->tm_wday++;
313                 if ((unsigned)tm->tm_wday >= 7)
314                     tm->tm_wday = 0;
315                 days_in_month = get_days_in_month(tm->tm_mon,
316                                                   tm->tm_year + 1900);
317                 tm->tm_mday++;
318                 if (tm->tm_mday < 1) {
319                     tm->tm_mday = 1;
320                 } else if (tm->tm_mday > days_in_month) {
321                     tm->tm_mday = 1;
322                     tm->tm_mon++;
323                     if (tm->tm_mon >= 12) {
324                         tm->tm_mon = 0;
325                         tm->tm_year++;
326                     }
327                 }
328             }
329         }
330     }
331 }
332
333
334 static void rtc_update_second(void *opaque)
335 {
336     RTCState *s = opaque;
337     int64_t delay;
338
339     /* if the oscillator is not in normal operation, we do not update */
340     if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
341         s->next_second_time += ticks_per_sec;
342         qemu_mod_timer(s->second_timer, s->next_second_time);
343     } else {
344         rtc_next_second(&s->current_tm);
345
346         if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
347             /* update in progress bit */
348             s->cmos_data[RTC_REG_A] |= REG_A_UIP;
349         }
350         /* should be 244 us = 8 / 32768 seconds, but currently the
351            timers do not have the necessary resolution. */
352         delay = (ticks_per_sec * 1) / 100;
353         if (delay < 1)
354             delay = 1;
355         qemu_mod_timer(s->second_timer2,
356                        s->next_second_time + delay);
357     }
358 }
359
360 static void rtc_update_second2(void *opaque)
361 {
362     RTCState *s = opaque;
363
364     if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
365         rtc_copy_date(s);
366     }
367
368     /* check alarm */
369     if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
370         if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
371              s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
372             ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
373              s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
374             ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
375              s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
376
377             s->cmos_data[RTC_REG_C] |= 0xa0;
378             rtc_irq_raise(s->irq);
379         }
380     }
381
382     /* update ended interrupt */
383     if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
384         s->cmos_data[RTC_REG_C] |= 0x90;
385         rtc_irq_raise(s->irq);
386     }
387
388     /* clear update in progress bit */
389     s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
390
391     s->next_second_time += ticks_per_sec;
392     qemu_mod_timer(s->second_timer, s->next_second_time);
393 }
394
395 static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
396 {
397     RTCState *s = opaque;
398     int ret;
399     if ((addr & 1) == 0) {
400         return 0xff;
401     } else {
402         switch(s->cmos_index) {
403         case RTC_SECONDS:
404         case RTC_MINUTES:
405         case RTC_HOURS:
406         case RTC_DAY_OF_WEEK:
407         case RTC_DAY_OF_MONTH:
408         case RTC_MONTH:
409         case RTC_YEAR:
410             ret = s->cmos_data[s->cmos_index];
411             break;
412         case RTC_REG_A:
413             ret = s->cmos_data[s->cmos_index];
414             break;
415         case RTC_REG_C:
416             ret = s->cmos_data[s->cmos_index];
417             qemu_irq_lower(s->irq);
418 #ifdef TARGET_I386
419             if(s->irq_coalesced) {
420                 apic_reset_irq_delivered();
421                 qemu_irq_raise(s->irq);
422                 if (apic_get_irq_delivered())
423                     s->irq_coalesced--;
424                 break;
425             }
426 #endif
427             s->cmos_data[RTC_REG_C] = 0x00;
428             break;
429         default:
430             ret = s->cmos_data[s->cmos_index];
431             break;
432         }
433 #ifdef DEBUG_CMOS
434         printf("cmos: read index=0x%02x val=0x%02x\n",
435                s->cmos_index, ret);
436 #endif
437         return ret;
438     }
439 }
440
441 void rtc_set_memory(RTCState *s, int addr, int val)
442 {
443     if (addr >= 0 && addr <= 127)
444         s->cmos_data[addr] = val;
445 }
446
447 void rtc_set_date(RTCState *s, const struct tm *tm)
448 {
449     s->current_tm = *tm;
450     rtc_copy_date(s);
451 }
452
453 /* PC cmos mappings */
454 #define REG_IBM_CENTURY_BYTE        0x32
455 #define REG_IBM_PS2_CENTURY_BYTE    0x37
456
457 static void rtc_set_date_from_host(RTCState *s)
458 {
459     struct tm tm;
460     int val;
461
462     /* set the CMOS date */
463     qemu_get_timedate(&tm, 0);
464     rtc_set_date(s, &tm);
465
466     val = to_bcd(s, (tm.tm_year / 100) + 19);
467     rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
468     rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
469 }
470
471 static void rtc_save(QEMUFile *f, void *opaque)
472 {
473     RTCState *s = opaque;
474
475     qemu_put_buffer(f, s->cmos_data, 128);
476     qemu_put_8s(f, &s->cmos_index);
477
478     qemu_put_be32(f, s->current_tm.tm_sec);
479     qemu_put_be32(f, s->current_tm.tm_min);
480     qemu_put_be32(f, s->current_tm.tm_hour);
481     qemu_put_be32(f, s->current_tm.tm_wday);
482     qemu_put_be32(f, s->current_tm.tm_mday);
483     qemu_put_be32(f, s->current_tm.tm_mon);
484     qemu_put_be32(f, s->current_tm.tm_year);
485
486     qemu_put_timer(f, s->periodic_timer);
487     qemu_put_be64(f, s->next_periodic_time);
488
489     qemu_put_be64(f, s->next_second_time);
490     qemu_put_timer(f, s->second_timer);
491     qemu_put_timer(f, s->second_timer2);
492 }
493
494 static int rtc_load(QEMUFile *f, void *opaque, int version_id)
495 {
496     RTCState *s = opaque;
497
498     if (version_id != 1)
499         return -EINVAL;
500
501     qemu_get_buffer(f, s->cmos_data, 128);
502     qemu_get_8s(f, &s->cmos_index);
503
504     s->current_tm.tm_sec=qemu_get_be32(f);
505     s->current_tm.tm_min=qemu_get_be32(f);
506     s->current_tm.tm_hour=qemu_get_be32(f);
507     s->current_tm.tm_wday=qemu_get_be32(f);
508     s->current_tm.tm_mday=qemu_get_be32(f);
509     s->current_tm.tm_mon=qemu_get_be32(f);
510     s->current_tm.tm_year=qemu_get_be32(f);
511
512     qemu_get_timer(f, s->periodic_timer);
513     s->next_periodic_time=qemu_get_be64(f);
514
515     s->next_second_time=qemu_get_be64(f);
516     qemu_get_timer(f, s->second_timer);
517     qemu_get_timer(f, s->second_timer2);
518     return 0;
519 }
520
521 #ifdef TARGET_I386
522 static void rtc_save_td(QEMUFile *f, void *opaque)
523 {
524     RTCState *s = opaque;
525
526     qemu_put_be32(f, s->irq_coalesced);
527     qemu_put_be32(f, s->period);
528 }
529
530 static int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
531 {
532     RTCState *s = opaque;
533
534     if (version_id != 1)
535         return -EINVAL;
536
537     s->irq_coalesced = qemu_get_be32(f);
538     s->period = qemu_get_be32(f);
539     return 0;
540 }
541 #endif
542
543 RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year)
544 {
545     RTCState *s;
546
547     s = qemu_mallocz(sizeof(RTCState));
548
549     s->irq = irq;
550     s->sqw_irq = sqw_irq;
551     s->cmos_data[RTC_REG_A] = 0x26;
552     s->cmos_data[RTC_REG_B] = 0x02;
553     s->cmos_data[RTC_REG_C] = 0x00;
554     s->cmos_data[RTC_REG_D] = 0x80;
555
556     s->base_year = base_year;
557     rtc_set_date_from_host(s);
558
559     s->periodic_timer = qemu_new_timer(vm_clock,
560                                        rtc_periodic_timer, s);
561     s->second_timer = qemu_new_timer(vm_clock,
562                                      rtc_update_second, s);
563     s->second_timer2 = qemu_new_timer(vm_clock,
564                                       rtc_update_second2, s);
565
566     s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
567     qemu_mod_timer(s->second_timer2, s->next_second_time);
568
569     register_ioport_write(base, 2, 1, cmos_ioport_write, s);
570     register_ioport_read(base, 2, 1, cmos_ioport_read, s);
571
572     register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
573 #ifdef TARGET_I386
574     if (rtc_td_hack)
575         register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
576 #endif
577     return s;
578 }
579
580 RTCState *rtc_init(int base, qemu_irq irq, int base_year)
581 {
582     return rtc_init_sqw(base, irq, NULL, base_year);
583 }
584
585 /* Memory mapped interface */
586 static uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
587 {
588     RTCState *s = opaque;
589
590     return cmos_ioport_read(s, addr >> s->it_shift) & 0xFF;
591 }
592
593 static void cmos_mm_writeb (void *opaque,
594                             target_phys_addr_t addr, uint32_t value)
595 {
596     RTCState *s = opaque;
597
598     cmos_ioport_write(s, addr >> s->it_shift, value & 0xFF);
599 }
600
601 static uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
602 {
603     RTCState *s = opaque;
604     uint32_t val;
605
606     val = cmos_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
607 #ifdef TARGET_WORDS_BIGENDIAN
608     val = bswap16(val);
609 #endif
610     return val;
611 }
612
613 static void cmos_mm_writew (void *opaque,
614                             target_phys_addr_t addr, uint32_t value)
615 {
616     RTCState *s = opaque;
617 #ifdef TARGET_WORDS_BIGENDIAN
618     value = bswap16(value);
619 #endif
620     cmos_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
621 }
622
623 static uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
624 {
625     RTCState *s = opaque;
626     uint32_t val;
627
628     val = cmos_ioport_read(s, addr >> s->it_shift);
629 #ifdef TARGET_WORDS_BIGENDIAN
630     val = bswap32(val);
631 #endif
632     return val;
633 }
634
635 static void cmos_mm_writel (void *opaque,
636                             target_phys_addr_t addr, uint32_t value)
637 {
638     RTCState *s = opaque;
639 #ifdef TARGET_WORDS_BIGENDIAN
640     value = bswap32(value);
641 #endif
642     cmos_ioport_write(s, addr >> s->it_shift, value);
643 }
644
645 static CPUReadMemoryFunc *rtc_mm_read[] = {
646     &cmos_mm_readb,
647     &cmos_mm_readw,
648     &cmos_mm_readl,
649 };
650
651 static CPUWriteMemoryFunc *rtc_mm_write[] = {
652     &cmos_mm_writeb,
653     &cmos_mm_writew,
654     &cmos_mm_writel,
655 };
656
657 RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
658                       int base_year)
659 {
660     RTCState *s;
661     int io_memory;
662
663     s = qemu_mallocz(sizeof(RTCState));
664
665     s->irq = irq;
666     s->cmos_data[RTC_REG_A] = 0x26;
667     s->cmos_data[RTC_REG_B] = 0x02;
668     s->cmos_data[RTC_REG_C] = 0x00;
669     s->cmos_data[RTC_REG_D] = 0x80;
670
671     s->base_year = base_year;
672     rtc_set_date_from_host(s);
673
674     s->periodic_timer = qemu_new_timer(vm_clock,
675                                        rtc_periodic_timer, s);
676     s->second_timer = qemu_new_timer(vm_clock,
677                                      rtc_update_second, s);
678     s->second_timer2 = qemu_new_timer(vm_clock,
679                                       rtc_update_second2, s);
680
681     s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
682     qemu_mod_timer(s->second_timer2, s->next_second_time);
683
684     io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s);
685     cpu_register_physical_memory(base, 2 << it_shift, io_memory);
686
687     register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
688 #ifdef TARGET_I386
689     if (rtc_td_hack)
690         register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
691 #endif
692     return s;
693 }
This page took 0.062659 seconds and 4 git commands to generate.