diff options
Diffstat (limited to 'hw/mc146818rtc.c')
-rw-r--r-- | hw/mc146818rtc.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index f57a9a6783..cd57bf3760 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -67,6 +67,10 @@ struct RTCState { int64_t next_periodic_time; /* second update */ int64_t next_second_time; +#ifdef TARGET_I386 + uint32_t irq_coalesced; + uint32_t period; +#endif QEMUTimer *second_timer; QEMUTimer *second_timer2; }; @@ -104,12 +108,20 @@ static void rtc_timer_update(RTCState *s, int64_t current_time) period_code += 7; /* period in 32 Khz cycles */ period = 1 << (period_code - 1); +#ifdef TARGET_I386 + if(period != s->period) + s->irq_coalesced = (s->irq_coalesced * s->period) / period; + s->period = period; +#endif /* compute 32 khz clock */ cur_clock = muldiv64(current_time, 32768, ticks_per_sec); next_irq_clock = (cur_clock & ~(period - 1)) + period; s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1; qemu_mod_timer(s->periodic_timer, s->next_periodic_time); } else { +#ifdef TARGET_I386 + s->irq_coalesced = 0; +#endif qemu_del_timer(s->periodic_timer); } } @@ -119,6 +131,12 @@ static void rtc_periodic_timer(void *opaque) RTCState *s = opaque; rtc_timer_update(s, s->next_periodic_time); +#ifdef TARGET_I386 + if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) { + s->irq_coalesced++; + return; + } +#endif s->cmos_data[RTC_REG_C] |= 0xc0; rtc_irq_raise(s->irq); } @@ -379,6 +397,15 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; qemu_irq_lower(s->irq); +#ifdef TARGET_I386 + if(s->irq_coalesced) { + apic_reset_irq_delivered(); + qemu_irq_raise(s->irq); + if (apic_get_irq_delivered()) + s->irq_coalesced--; + break; + } +#endif s->cmos_data[RTC_REG_C] = 0x00; break; default: @@ -473,6 +500,28 @@ static int rtc_load(QEMUFile *f, void *opaque, int version_id) return 0; } +#ifdef TARGET_I386 +static void rtc_save_td(QEMUFile *f, void *opaque) +{ + RTCState *s = opaque; + + qemu_put_be32(f, s->irq_coalesced); + qemu_put_be32(f, s->period); +} + +static int rtc_load_td(QEMUFile *f, void *opaque, int version_id) +{ + RTCState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + s->irq_coalesced = qemu_get_be32(f); + s->period = qemu_get_be32(f); + return 0; +} +#endif + RTCState *rtc_init(int base, qemu_irq irq) { RTCState *s; @@ -503,6 +552,10 @@ RTCState *rtc_init(int base, qemu_irq irq) register_ioport_read(base, 2, 1, cmos_ioport_read, s); register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); +#ifdef TARGET_I386 + if (rtc_td_hack) + register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s); +#endif return s; } @@ -609,5 +662,9 @@ RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq) cpu_register_physical_memory(base, 2 << it_shift, io_memory); register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); +#ifdef TARGET_I386 + if (rtc_td_hack) + register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s); +#endif return s; } |