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