pbrook | 87ecb68 | 2007-11-17 17:14:51 +0000 | [diff] [blame] | 1 | #include "hw.h" |
| 2 | #include "mips.h" |
| 3 | #include "qemu-timer.h" |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 4 | |
aurel32 | ea86e4e | 2008-04-11 04:55:31 +0000 | [diff] [blame^] | 5 | #define TIMER_FREQ 100 * 1000 * 1000 |
| 6 | |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 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; |
ths | ead9360 | 2007-09-06 00:18:15 +0000 | [diff] [blame] | 17 | idx = (seed >> 16) % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired; |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 18 | return idx; |
| 19 | } |
| 20 | |
| 21 | /* MIPS R4K timer */ |
| 22 | uint32_t cpu_mips_get_count (CPUState *env) |
| 23 | { |
ths | 4253218 | 2007-09-25 16:53:15 +0000 | [diff] [blame] | 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), |
aurel32 | ea86e4e | 2008-04-11 04:55:31 +0000 | [diff] [blame^] | 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); |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 42 | } |
| 43 | |
ths | 3529b53 | 2007-04-05 23:17:40 +0000 | [diff] [blame] | 44 | void cpu_mips_store_count (CPUState *env, uint32_t count) |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 45 | { |
ths | 3529b53 | 2007-04-05 23:17:40 +0000 | [diff] [blame] | 46 | if (env->CP0_Cause & (1 << CP0Ca_DC)) |
aurel32 | ea86e4e | 2008-04-11 04:55:31 +0000 | [diff] [blame^] | 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 | } |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | void cpu_mips_store_compare (CPUState *env, uint32_t value) |
| 59 | { |
ths | 3529b53 | 2007-04-05 23:17:40 +0000 | [diff] [blame] | 60 | env->CP0_Compare = value; |
aurel32 | ea86e4e | 2008-04-11 04:55:31 +0000 | [diff] [blame^] | 61 | if (!(env->CP0_Cause & (1 << CP0Ca_DC))) |
| 62 | cpu_mips_timer_update(env); |
| 63 | if (env->insn_flags & ISA_MIPS32R2) |
ths | 39d51eb | 2007-03-18 12:43:40 +0000 | [diff] [blame] | 64 | env->CP0_Cause &= ~(1 << CP0Ca_TI); |
ths | 4253218 | 2007-09-25 16:53:15 +0000 | [diff] [blame] | 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), |
aurel32 | ea86e4e | 2008-04-11 04:55:31 +0000 | [diff] [blame^] | 77 | TIMER_FREQ, ticks_per_sec); |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 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 |
ths | 4253218 | 2007-09-25 16:53:15 +0000 | [diff] [blame] | 90 | |
| 91 | if (env->CP0_Cause & (1 << CP0Ca_DC)) |
| 92 | return; |
| 93 | |
aurel32 | ea86e4e | 2008-04-11 04:55:31 +0000 | [diff] [blame^] | 94 | cpu_mips_timer_update(env); |
| 95 | if (env->insn_flags & ISA_MIPS32R2) |
ths | 39d51eb | 2007-03-18 12:43:40 +0000 | [diff] [blame] | 96 | env->CP0_Cause |= 1 << CP0Ca_TI; |
ths | 4253218 | 2007-09-25 16:53:15 +0000 | [diff] [blame] | 97 | qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 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; |
aurel32 | ea86e4e | 2008-04-11 04:55:31 +0000 | [diff] [blame^] | 104 | cpu_mips_store_count(env, 1); |
ths | e16fe40 | 2006-12-06 21:38:37 +0000 | [diff] [blame] | 105 | } |