blob: d341e5165729e58cacd95d8592336aaee9fdb0f8 [file] [log] [blame]
pbrook87ecb682007-11-17 17:14:51 +00001#include "hw.h"
2#include "mips.h"
3#include "qemu-timer.h"
thse16fe402006-12-06 21:38:37 +00004
aurel32ea86e4e2008-04-11 04:55:31 +00005#define TIMER_FREQ 100 * 1000 * 1000
6
thse16fe402006-12-06 21:38:37 +00007/* XXX: do not use a global */
8uint32_t cpu_mips_get_random (CPUState *env)
9{
aurel3259d94132009-01-08 18:48:12 +000010 static uint32_t lfsr = 1;
11 static uint32_t prev_idx = 0;
thse16fe402006-12-06 21:38:37 +000012 uint32_t idx;
aurel3259d94132009-01-08 18:48:12 +000013 /* Don't return same value twice, so get another value */
14 do {
15 lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
16 idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
17 } while (idx == prev_idx);
18 prev_idx = idx;
thse16fe402006-12-06 21:38:37 +000019 return idx;
20}
21
22/* MIPS R4K timer */
23uint32_t cpu_mips_get_count (CPUState *env)
24{
ths42532182007-09-25 16:53:15 +000025 if (env->CP0_Cause & (1 << CP0Ca_DC))
26 return env->CP0_Count;
27 else
28 return env->CP0_Count +
29 (uint32_t)muldiv64(qemu_get_clock(vm_clock),
aurel32ea86e4e2008-04-11 04:55:31 +000030 TIMER_FREQ, ticks_per_sec);
31}
32
33static void cpu_mips_timer_update(CPUState *env)
34{
35 uint64_t now, next;
36 uint32_t wait;
37
38 now = qemu_get_clock(vm_clock);
39 wait = env->CP0_Compare - env->CP0_Count -
40 (uint32_t)muldiv64(now, TIMER_FREQ, ticks_per_sec);
41 next = now + muldiv64(wait, ticks_per_sec, TIMER_FREQ);
42 qemu_mod_timer(env->timer, next);
thse16fe402006-12-06 21:38:37 +000043}
44
ths3529b532007-04-05 23:17:40 +000045void cpu_mips_store_count (CPUState *env, uint32_t count)
thse16fe402006-12-06 21:38:37 +000046{
ths3529b532007-04-05 23:17:40 +000047 if (env->CP0_Cause & (1 << CP0Ca_DC))
aurel32ea86e4e2008-04-11 04:55:31 +000048 env->CP0_Count = count;
49 else {
50 /* Store new count register */
51 env->CP0_Count =
52 count - (uint32_t)muldiv64(qemu_get_clock(vm_clock),
53 TIMER_FREQ, ticks_per_sec);
54 /* Update timer timer */
55 cpu_mips_timer_update(env);
56 }
thse16fe402006-12-06 21:38:37 +000057}
58
59void cpu_mips_store_compare (CPUState *env, uint32_t value)
60{
ths3529b532007-04-05 23:17:40 +000061 env->CP0_Compare = value;
aurel32ea86e4e2008-04-11 04:55:31 +000062 if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
63 cpu_mips_timer_update(env);
64 if (env->insn_flags & ISA_MIPS32R2)
ths39d51eb2007-03-18 12:43:40 +000065 env->CP0_Cause &= ~(1 << CP0Ca_TI);
ths42532182007-09-25 16:53:15 +000066 qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
67}
68
69void cpu_mips_start_count(CPUState *env)
70{
71 cpu_mips_store_count(env, env->CP0_Count);
72}
73
74void cpu_mips_stop_count(CPUState *env)
75{
76 /* Store the current value */
77 env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock),
aurel32ea86e4e2008-04-11 04:55:31 +000078 TIMER_FREQ, ticks_per_sec);
thse16fe402006-12-06 21:38:37 +000079}
80
81static void mips_timer_cb (void *opaque)
82{
83 CPUState *env;
84
85 env = opaque;
86#if 0
aliguori93fcfe32009-01-15 22:34:14 +000087 qemu_log("%s\n", __func__);
thse16fe402006-12-06 21:38:37 +000088#endif
ths42532182007-09-25 16:53:15 +000089
90 if (env->CP0_Cause & (1 << CP0Ca_DC))
91 return;
92
pbrook2e70f6e2008-06-29 01:03:05 +000093 /* ??? This callback should occur when the counter is exactly equal to
94 the comparator value. Offset the count by one to avoid immediately
95 retriggering the callback before any virtual time has passed. */
96 env->CP0_Count++;
aurel32ea86e4e2008-04-11 04:55:31 +000097 cpu_mips_timer_update(env);
pbrook2e70f6e2008-06-29 01:03:05 +000098 env->CP0_Count--;
aurel32ea86e4e2008-04-11 04:55:31 +000099 if (env->insn_flags & ISA_MIPS32R2)
ths39d51eb2007-03-18 12:43:40 +0000100 env->CP0_Cause |= 1 << CP0Ca_TI;
ths42532182007-09-25 16:53:15 +0000101 qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
thse16fe402006-12-06 21:38:37 +0000102}
103
104void cpu_mips_clock_init (CPUState *env)
105{
106 env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
107 env->CP0_Compare = 0;
aurel32ea86e4e2008-04-11 04:55:31 +0000108 cpu_mips_store_count(env, 1);
thse16fe402006-12-06 21:38:37 +0000109}