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