]> git.proxmox.com Git - qemu.git/blame - hw/mips_timer.c
list MST as pci layer maintainer
[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),
6ee093c9 30 TIMER_FREQ, get_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 39 wait = env->CP0_Compare - env->CP0_Count -
6ee093c9
JQ
40 (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
41 next = now + muldiv64(wait, get_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),
6ee093c9 53 TIMER_FREQ, get_ticks_per_sec());
ea86e4e6
AJ
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),
6ee093c9 78 TIMER_FREQ, get_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
93fcfe39 87 qemu_log("%s\n", __func__);
e16fe40c 88#endif
42532189
TS
89
90 if (env->CP0_Cause & (1 << CP0Ca_DC))
91 return;
92
2e70f6ef
PB
93 /* ??? This callback should occur when the counter is exactly equal to
94 the comparator value. Offset the count by one to avoid immediately
95 retriggering the callback before any virtual time has passed. */
96 env->CP0_Count++;
ea86e4e6 97 cpu_mips_timer_update(env);
2e70f6ef 98 env->CP0_Count--;
ea86e4e6 99 if (env->insn_flags & ISA_MIPS32R2)
39d51eb8 100 env->CP0_Cause |= 1 << CP0Ca_TI;
42532189 101 qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
e16fe40c
TS
102}
103
104void cpu_mips_clock_init (CPUState *env)
105{
106 env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
107 env->CP0_Compare = 0;
ea86e4e6 108 cpu_mips_store_count(env, 1);
e16fe40c 109}