]>
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 | { | |
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 */ | |
23 | uint32_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 | 33 | static 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 | 45 | void 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 | ||
59 | void 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 | ||
69 | void cpu_mips_start_count(CPUState *env) | |
70 | { | |
71 | cpu_mips_store_count(env, env->CP0_Count); | |
72 | } | |
73 | ||
74 | void 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 | ||
81 | static 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 | ||
104 | void 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 | } |