1409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli#include "hw.h"
2409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli#include "mips.h"
3409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli#include "qemu-timer.h"
4409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
5409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli#define TIMER_FREQ	100 * 1000 * 1000
6409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
7409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli/* XXX: do not use a global */
8409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalliuint32_t cpu_mips_get_random (CPUState *env)
9409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
10409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    static uint32_t lfsr = 1;
11409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    static uint32_t prev_idx = 0;
12409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    uint32_t idx;
13409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    /* Don't return same value twice, so get another value */
14409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    do {
15409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
16409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
17409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    } while (idx == prev_idx);
18409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    prev_idx = idx;
19409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    return idx;
20409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
21409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
22409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli/* MIPS R4K timer */
23409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalliuint32_t cpu_mips_get_count (CPUState *env)
24409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
25409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    if (env->CP0_Cause & (1 << CP0Ca_DC))
26409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        return env->CP0_Count;
27409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    else
28409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        return env->CP0_Count +
29409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
30409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli                               TIMER_FREQ, get_ticks_per_sec());
31409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
32409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
33409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapallistatic void cpu_mips_timer_update(CPUState *env)
34409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
35409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    uint64_t now, next;
36409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    uint32_t wait;
37409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
38409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    now = qemu_get_clock(vm_clock);
39409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    wait = env->CP0_Compare - env->CP0_Count -
40409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli	    (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
41409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
42409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    qemu_mod_timer(env->timer, next);
43409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
44409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
45409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapallivoid cpu_mips_store_count (CPUState *env, uint32_t count)
46409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
47409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    if (env->CP0_Cause & (1 << CP0Ca_DC))
48409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        env->CP0_Count = count;
49409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    else {
50409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        /* Store new count register */
51409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        env->CP0_Count =
52409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli            count - (uint32_t)muldiv64(qemu_get_clock(vm_clock),
53409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli                                       TIMER_FREQ, get_ticks_per_sec());
54409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        /* Update timer timer */
55409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        cpu_mips_timer_update(env);
56409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    }
57409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
58409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
59409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapallivoid cpu_mips_store_compare (CPUState *env, uint32_t value)
60409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
61409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    env->CP0_Compare = value;
62409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
63409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        cpu_mips_timer_update(env);
64409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    if (env->insn_flags & ISA_MIPS32R2)
65409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        env->CP0_Cause &= ~(1 << CP0Ca_TI);
66409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
67409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
68409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
69409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapallivoid cpu_mips_start_count(CPUState *env)
70409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
71409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    cpu_mips_store_count(env, env->CP0_Count);
72409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
73409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
74409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapallivoid cpu_mips_stop_count(CPUState *env)
75409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
76409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    /* Store the current value */
77409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock),
78409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli                                         TIMER_FREQ, get_ticks_per_sec());
79409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
80409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
81409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapallistatic void mips_timer_cb (void *opaque)
82409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
83409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    CPUState *env;
84409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
85409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    env = opaque;
86409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli#if 0
87409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    qemu_log("%s\n", __func__);
88409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli#endif
89409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
90409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    if (env->CP0_Cause & (1 << CP0Ca_DC))
91409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        return;
92409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
93409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    /* ??? This callback should occur when the counter is exactly equal to
94409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli       the comparator value.  Offset the count by one to avoid immediately
95409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli       retriggering the callback before any virtual time has passed.  */
96409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    env->CP0_Count++;
97409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    cpu_mips_timer_update(env);
98409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    env->CP0_Count--;
99409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    if (env->insn_flags & ISA_MIPS32R2)
100409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli        env->CP0_Cause |= 1 << CP0Ca_TI;
101409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
102409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
103409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli
104409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapallivoid cpu_mips_clock_init (CPUState *env)
105409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli{
106325e19d19ff9e1fc9c6acb12eeb754563fc2e251Bhanu Chetlapalli    env->timer = qemu_new_timer_ns(vm_clock, &mips_timer_cb, env);
107409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    env->CP0_Compare = 0;
108409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli    cpu_mips_store_count(env, 1);
109409c7b66435cf5947cab6bf0710f92507317f22eBhanu Chetlapalli}
110