]> git.proxmox.com Git - mirror_qemu.git/blame - hw/mips_timer.c
Add instruction counter.
[mirror_qemu.git] / hw / mips_timer.c
CommitLineData
87ecb68b
PB
1#include "hw.h"
2#include "mips.h"
3#include "qemu-timer.h"
e16fe40c 4
ea86e4e6
AJ
5#define TIMER_FREQ 100 * 1000 * 1000
6
e16fe40c
TS
7void cpu_mips_irqctrl_init (void)
8{
9}
10
11/* XXX: do not use a global */
12uint32_t cpu_mips_get_random (CPUState *env)
13{
14 static uint32_t seed = 0;
15 uint32_t idx;
16 seed = seed * 314159 + 1;
ead9360e 17 idx = (seed >> 16) % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
e16fe40c
TS
18 return idx;
19}
20
21/* MIPS R4K timer */
22uint32_t cpu_mips_get_count (CPUState *env)
23{
42532189
TS
24 if (env->CP0_Cause & (1 << CP0Ca_DC))
25 return env->CP0_Count;
26 else
27 return env->CP0_Count +
28 (uint32_t)muldiv64(qemu_get_clock(vm_clock),
ea86e4e6 29 TIMER_FREQ, ticks_per_sec);
e16fe40c
TS
30}
31
ea86e4e6 32static void cpu_mips_timer_update(CPUState *env)
e16fe40c
TS
33{
34 uint64_t now, next;
ea86e4e6 35 uint32_t wait;
39d51eb8 36
e16fe40c 37 now = qemu_get_clock(vm_clock);
ea86e4e6
AJ
38 wait = env->CP0_Compare - env->CP0_Count -
39 (uint32_t)muldiv64(now, TIMER_FREQ, ticks_per_sec);
40 next = now + muldiv64(wait, ticks_per_sec, TIMER_FREQ);
e16fe40c
TS
41 qemu_mod_timer(env->timer, next);
42}
43
ea86e4e6 44void cpu_mips_store_count (CPUState *env, uint32_t count)
e16fe40c 45{
3529b538 46 if (env->CP0_Cause & (1 << CP0Ca_DC))
ea86e4e6
AJ
47 env->CP0_Count = count;
48 else {
49 /* Store new count register */
50 env->CP0_Count =
51 count - (uint32_t)muldiv64(qemu_get_clock(vm_clock),
52 TIMER_FREQ, ticks_per_sec);
53 /* Update timer timer */
54 cpu_mips_timer_update(env);
55 }
e16fe40c
TS
56}
57
58void cpu_mips_store_compare (CPUState *env, uint32_t value)
59{
3529b538 60 env->CP0_Compare = value;
ea86e4e6
AJ
61 if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
62 cpu_mips_timer_update(env);
63 if (env->insn_flags & ISA_MIPS32R2)
39d51eb8 64 env->CP0_Cause &= ~(1 << CP0Ca_TI);
42532189
TS
65 qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
66}
67
68void cpu_mips_start_count(CPUState *env)
69{
70 cpu_mips_store_count(env, env->CP0_Count);
71}
72
73void cpu_mips_stop_count(CPUState *env)
74{
75 /* Store the current value */
76 env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock),
ea86e4e6 77 TIMER_FREQ, ticks_per_sec);
e16fe40c
TS
78}
79
80static void mips_timer_cb (void *opaque)
81{
82 CPUState *env;
83
84 env = opaque;
85#if 0
86 if (logfile) {
87 fprintf(logfile, "%s\n", __func__);
88 }
89#endif
42532189
TS
90
91 if (env->CP0_Cause & (1 << CP0Ca_DC))
92 return;
93
2e70f6ef
PB
94 /* ??? This callback should occur when the counter is exactly equal to
95 the comparator value. Offset the count by one to avoid immediately
96 retriggering the callback before any virtual time has passed. */
97 env->CP0_Count++;
ea86e4e6 98 cpu_mips_timer_update(env);
2e70f6ef 99 env->CP0_Count--;
ea86e4e6 100 if (env->insn_flags & ISA_MIPS32R2)
39d51eb8 101 env->CP0_Cause |= 1 << CP0Ca_TI;
42532189 102 qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
e16fe40c
TS
103}
104
105void cpu_mips_clock_init (CPUState *env)
106{
107 env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
108 env->CP0_Compare = 0;
ea86e4e6 109 cpu_mips_store_count(env, 1);
e16fe40c 110}