Statistics
| Branch: | Revision:

root / hw / mips_timer.c @ 7b9cbadb

History | View | Annotate | Download (4.1 kB)

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