1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#include "vl.h"
void cpu_mips_irqctrl_init (void)
{
}
/* XXX: do not use a global */
uint32_t cpu_mips_get_random (CPUState *env)
{
static uint32_t seed = 0;
uint32_t idx;
seed = seed * 314159 + 1;
idx = (seed >> 16) % (env->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
return idx;
}
/* MIPS R4K timer */
uint32_t cpu_mips_get_count (CPUState *env)
{
return env->CP0_Count +
(uint32_t)muldiv64(qemu_get_clock(vm_clock),
100 * 1000 * 1000, ticks_per_sec);
}
void cpu_mips_store_count (CPUState *env, uint32_t count)
{
uint64_t now, next;
uint32_t tmp;
uint32_t compare = env->CP0_Compare;
tmp = count;
if (count == compare)
tmp++;
now = qemu_get_clock(vm_clock);
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
if (next == now)
next++;
#if 0
if (logfile) {
fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n",
__func__, now, count, compare, next - now);
}
#endif
/* Store new count and compare registers */
env->CP0_Compare = compare;
env->CP0_Count =
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
/* Adjust timer */
qemu_mod_timer(env->timer, next);
}
static void cpu_mips_update_count (CPUState *env, uint32_t count)
{
if (env->CP0_Cause & (1 << CP0Ca_DC))
return;
cpu_mips_store_count(env, count);
}
void cpu_mips_store_compare (CPUState *env, uint32_t value)
{
env->CP0_Compare = value;
cpu_mips_update_count(env, cpu_mips_get_count(env));
if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
env->CP0_Cause &= ~(1 << CP0Ca_TI);
qemu_irq_lower(env->irq[7]);
}
static void mips_timer_cb (void *opaque)
{
CPUState *env;
env = opaque;
#if 0
if (logfile) {
fprintf(logfile, "%s\n", __func__);
}
#endif
cpu_mips_update_count(env, cpu_mips_get_count(env));
if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
env->CP0_Cause |= 1 << CP0Ca_TI;
qemu_irq_raise(env->irq[7]);
}
void cpu_mips_clock_init (CPUState *env)
{
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
env->CP0_Compare = 0;
cpu_mips_update_count(env, 1);
}
|