Statistics
| Branch: | Revision:

root / hw / mips_timer.c @ 1ffc346f

History | View | Annotate | Download (2.6 kB)

1
#include "hw.h"
2
#include "mips.h"
3
#include "qemu-timer.h"
4

    
5
#define TIMER_FREQ        100 * 1000 * 1000
6

    
7
void cpu_mips_irqctrl_init (void)
8
{
9
}
10

    
11
/* XXX: do not use a global */
12
uint32_t cpu_mips_get_random (CPUState *env)
13
{
14
    static uint32_t seed = 0;
15
    uint32_t idx;
16
    seed = seed * 314159 + 1;
17
    idx = (seed >> 16) % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
18
    return idx;
19
}
20

    
21
/* MIPS R4K timer */
22
uint32_t cpu_mips_get_count (CPUState *env)
23
{
24
    if (env->CP0_Cause & (1 << CP0Ca_DC))
25
        return env->CP0_Count;
26
    else
27
        return env->CP0_Count +
28
            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
29
                               TIMER_FREQ, ticks_per_sec);
30
}
31

    
32
static void cpu_mips_timer_update(CPUState *env)
33
{
34
    uint64_t now, next;
35
    uint32_t wait;
36

    
37
    now = qemu_get_clock(vm_clock);
38
    wait = env->CP0_Compare - env->CP0_Count -
39
            (uint32_t)muldiv64(now, TIMER_FREQ, ticks_per_sec);
40
    next = now + muldiv64(wait, ticks_per_sec, TIMER_FREQ);
41
    qemu_mod_timer(env->timer, next);
42
}
43

    
44
void cpu_mips_store_count (CPUState *env, uint32_t count)
45
{
46
    if (env->CP0_Cause & (1 << CP0Ca_DC))
47
        env->CP0_Count = count;
48
    else {
49
        /* Store new count register */
50
        env->CP0_Count =
51
            count - (uint32_t)muldiv64(qemu_get_clock(vm_clock),
52
                                       TIMER_FREQ, ticks_per_sec);
53
        /* Update timer timer */
54
        cpu_mips_timer_update(env);
55
    }
56
}
57

    
58
void cpu_mips_store_compare (CPUState *env, uint32_t value)
59
{
60
    env->CP0_Compare = value;
61
    if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
62
        cpu_mips_timer_update(env);
63
    if (env->insn_flags & ISA_MIPS32R2)
64
        env->CP0_Cause &= ~(1 << CP0Ca_TI);
65
    qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
66
}
67

    
68
void cpu_mips_start_count(CPUState *env)
69
{
70
    cpu_mips_store_count(env, env->CP0_Count);
71
}
72

    
73
void cpu_mips_stop_count(CPUState *env)
74
{
75
    /* Store the current value */
76
    env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock),
77
                                         TIMER_FREQ, ticks_per_sec);
78
}
79

    
80
static void mips_timer_cb (void *opaque)
81
{
82
    CPUState *env;
83

    
84
    env = opaque;
85
#if 0
86
    if (logfile) {
87
        fprintf(logfile, "%s\n", __func__);
88
    }
89
#endif
90

    
91
    if (env->CP0_Cause & (1 << CP0Ca_DC))
92
        return;
93

    
94
    cpu_mips_timer_update(env);
95
    if (env->insn_flags & ISA_MIPS32R2)
96
        env->CP0_Cause |= 1 << CP0Ca_TI;
97
    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
98
}
99

    
100
void cpu_mips_clock_init (CPUState *env)
101
{
102
    env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
103
    env->CP0_Compare = 0;
104
    cpu_mips_store_count(env, 1);
105
}