]> git.proxmox.com Git - qemu.git/blame - hw/mips_timer.c
virtio-blk: Avoid zeroing every request structure
[qemu.git] / hw / mips_timer.c
CommitLineData
7b9cbadb
AJ
1/*
2 * QEMU MIPS timer support
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
87ecb68b 23#include "hw.h"
b970ea8f 24#include "mips_cpudevs.h"
87ecb68b 25#include "qemu-timer.h"
e16fe40c 26
ea86e4e6
AJ
27#define TIMER_FREQ 100 * 1000 * 1000
28
e16fe40c
TS
29/* XXX: do not use a global */
30uint32_t cpu_mips_get_random (CPUState *env)
31{
59d94130
AJ
32 static uint32_t lfsr = 1;
33 static uint32_t prev_idx = 0;
e16fe40c 34 uint32_t idx;
59d94130
AJ
35 /* Don't return same value twice, so get another value */
36 do {
37 lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
38 idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
39 } while (idx == prev_idx);
40 prev_idx = idx;
e16fe40c
TS
41 return idx;
42}
43
44/* MIPS R4K timer */
45uint32_t cpu_mips_get_count (CPUState *env)
46{
42532189
TS
47 if (env->CP0_Cause & (1 << CP0Ca_DC))
48 return env->CP0_Count;
49 else
50 return env->CP0_Count +
51 (uint32_t)muldiv64(qemu_get_clock(vm_clock),
6ee093c9 52 TIMER_FREQ, get_ticks_per_sec());
e16fe40c
TS
53}
54
ea86e4e6 55static void cpu_mips_timer_update(CPUState *env)
e16fe40c
TS
56{
57 uint64_t now, next;
ea86e4e6 58 uint32_t wait;
39d51eb8 59
e16fe40c 60 now = qemu_get_clock(vm_clock);
ea86e4e6 61 wait = env->CP0_Compare - env->CP0_Count -
6ee093c9
JQ
62 (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
63 next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
e16fe40c
TS
64 qemu_mod_timer(env->timer, next);
65}
66
ea86e4e6 67void cpu_mips_store_count (CPUState *env, uint32_t count)
e16fe40c 68{
3529b538 69 if (env->CP0_Cause & (1 << CP0Ca_DC))
ea86e4e6
AJ
70 env->CP0_Count = count;
71 else {
72 /* Store new count register */
73 env->CP0_Count =
74 count - (uint32_t)muldiv64(qemu_get_clock(vm_clock),
6ee093c9 75 TIMER_FREQ, get_ticks_per_sec());
ea86e4e6
AJ
76 /* Update timer timer */
77 cpu_mips_timer_update(env);
78 }
e16fe40c
TS
79}
80
81void cpu_mips_store_compare (CPUState *env, uint32_t value)
82{
3529b538 83 env->CP0_Compare = value;
ea86e4e6
AJ
84 if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
85 cpu_mips_timer_update(env);
86 if (env->insn_flags & ISA_MIPS32R2)
39d51eb8 87 env->CP0_Cause &= ~(1 << CP0Ca_TI);
42532189
TS
88 qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
89}
90
91void cpu_mips_start_count(CPUState *env)
92{
93 cpu_mips_store_count(env, env->CP0_Count);
94}
95
96void cpu_mips_stop_count(CPUState *env)
97{
98 /* Store the current value */
99 env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock),
6ee093c9 100 TIMER_FREQ, get_ticks_per_sec());
e16fe40c
TS
101}
102
103static void mips_timer_cb (void *opaque)
104{
105 CPUState *env;
106
107 env = opaque;
108#if 0
93fcfe39 109 qemu_log("%s\n", __func__);
e16fe40c 110#endif
42532189
TS
111
112 if (env->CP0_Cause & (1 << CP0Ca_DC))
113 return;
114
2e70f6ef
PB
115 /* ??? This callback should occur when the counter is exactly equal to
116 the comparator value. Offset the count by one to avoid immediately
117 retriggering the callback before any virtual time has passed. */
118 env->CP0_Count++;
ea86e4e6 119 cpu_mips_timer_update(env);
2e70f6ef 120 env->CP0_Count--;
ea86e4e6 121 if (env->insn_flags & ISA_MIPS32R2)
39d51eb8 122 env->CP0_Cause |= 1 << CP0Ca_TI;
42532189 123 qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
e16fe40c
TS
124}
125
126void cpu_mips_clock_init (CPUState *env)
127{
128 env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
129 env->CP0_Compare = 0;
ea86e4e6 130 cpu_mips_store_count(env, 1);
e16fe40c 131}