Statistics
| Branch: | Revision:

root / hw / mips_timer.c @ 21cafd08

History | View | Annotate | Download (2.8 kB)

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