diff options
-rw-r--r-- | hw/mips_timer.c | 56 |
1 files changed, 25 insertions, 31 deletions
diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 3e7d5e3..5b172ea 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -2,6 +2,8 @@ #include "mips.h" #include "qemu-timer.h" +#define TIMER_FREQ 100 * 1000 * 1000 + void cpu_mips_irqctrl_init (void) { } @@ -24,49 +26,41 @@ uint32_t cpu_mips_get_count (CPUState *env) else return env->CP0_Count + (uint32_t)muldiv64(qemu_get_clock(vm_clock), - 100 * 1000 * 1000, ticks_per_sec); + TIMER_FREQ, ticks_per_sec); } -void cpu_mips_store_count (CPUState *env, uint32_t count) +static void cpu_mips_timer_update(CPUState *env) { uint64_t now, next; - uint32_t tmp; - uint32_t compare = env->CP0_Compare; + uint32_t wait; - tmp = count; - if (count == compare) - tmp++; now = qemu_get_clock(vm_clock); - next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); - if (next == now) - next++; -#if 0 - if (logfile) { - fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", - __func__, now, count, compare, next - now); - } -#endif - /* Store new count and compare registers */ - env->CP0_Compare = compare; - env->CP0_Count = - count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec); - /* Adjust timer */ + wait = env->CP0_Compare - env->CP0_Count - + (uint32_t)muldiv64(now, TIMER_FREQ, ticks_per_sec); + next = now + muldiv64(wait, ticks_per_sec, TIMER_FREQ); qemu_mod_timer(env->timer, next); } -static void cpu_mips_update_count (CPUState *env, uint32_t count) +void cpu_mips_store_count (CPUState *env, uint32_t count) { if (env->CP0_Cause & (1 << CP0Ca_DC)) - return; - - cpu_mips_store_count(env, count); + env->CP0_Count = count; + else { + /* Store new count register */ + env->CP0_Count = + count - (uint32_t)muldiv64(qemu_get_clock(vm_clock), + TIMER_FREQ, ticks_per_sec); + /* Update timer timer */ + cpu_mips_timer_update(env); + } } void cpu_mips_store_compare (CPUState *env, uint32_t value) { env->CP0_Compare = value; - cpu_mips_update_count(env, cpu_mips_get_count(env)); - if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) + if (!(env->CP0_Cause & (1 << CP0Ca_DC))) + cpu_mips_timer_update(env); + if (env->insn_flags & ISA_MIPS32R2) env->CP0_Cause &= ~(1 << CP0Ca_TI); qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); } @@ -80,7 +74,7 @@ void cpu_mips_stop_count(CPUState *env) { /* Store the current value */ env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock), - 100 * 1000 * 1000, ticks_per_sec); + TIMER_FREQ, ticks_per_sec); } static void mips_timer_cb (void *opaque) @@ -97,8 +91,8 @@ static void mips_timer_cb (void *opaque) if (env->CP0_Cause & (1 << CP0Ca_DC)) return; - cpu_mips_update_count(env, cpu_mips_get_count(env)); - if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) + cpu_mips_timer_update(env); + if (env->insn_flags & ISA_MIPS32R2) env->CP0_Cause |= 1 << CP0Ca_TI; qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); } @@ -107,5 +101,5 @@ void cpu_mips_clock_init (CPUState *env) { env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); env->CP0_Compare = 0; - cpu_mips_update_count(env, 1); + cpu_mips_store_count(env, 1); } |