|
|
1.1.1.5 ! root 1: /* ! 2: * QEMU MIPS timer support ! 3: * ! 4: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 5: * of this software and associated documentation files (the "Software"), to deal ! 6: * in the Software without restriction, including without limitation the rights ! 7: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 8: * copies of the Software, and to permit persons to whom the Software is ! 9: * furnished to do so, subject to the following conditions: ! 10: * ! 11: * The above copyright notice and this permission notice shall be included in ! 12: * all copies or substantial portions of the Software. ! 13: * ! 14: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 15: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 17: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 18: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 19: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 20: * THE SOFTWARE. ! 21: */ ! 22: 1.1.1.2 root 23: #include "hw.h" 1.1.1.5 ! root 24: #include "mips_cpudevs.h" 1.1.1.2 root 25: #include "qemu-timer.h" 1.1 root 26: 1.1.1.3 root 27: #define TIMER_FREQ 100 * 1000 * 1000 1.1 root 28: 29: /* XXX: do not use a global */ 30: uint32_t cpu_mips_get_random (CPUState *env) 31: { 1.1.1.3 root 32: static uint32_t lfsr = 1; 33: static uint32_t prev_idx = 0; 1.1 root 34: uint32_t idx; 1.1.1.3 root 35: /* Don't return same value twice, so get another value */ 36: do { 37: lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u); 38: idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired; 39: } while (idx == prev_idx); 40: prev_idx = idx; 1.1 root 41: return idx; 42: } 43: 44: /* MIPS R4K timer */ 45: uint32_t cpu_mips_get_count (CPUState *env) 46: { 1.1.1.2 root 47: if (env->CP0_Cause & (1 << CP0Ca_DC)) 48: return env->CP0_Count; 49: else 50: return env->CP0_Count + 51: (uint32_t)muldiv64(qemu_get_clock(vm_clock), 1.1.1.4 root 52: TIMER_FREQ, get_ticks_per_sec()); 1.1 root 53: } 54: 1.1.1.3 root 55: static void cpu_mips_timer_update(CPUState *env) 1.1 root 56: { 57: uint64_t now, next; 1.1.1.3 root 58: uint32_t wait; 1.1 root 59: 60: now = qemu_get_clock(vm_clock); 1.1.1.3 root 61: wait = env->CP0_Compare - env->CP0_Count - 1.1.1.4 root 62: (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec()); 63: next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); 1.1 root 64: qemu_mod_timer(env->timer, next); 65: } 66: 1.1.1.3 root 67: void cpu_mips_store_count (CPUState *env, uint32_t count) 1.1 root 68: { 1.1.1.2 root 69: if (env->CP0_Cause & (1 << CP0Ca_DC)) 1.1.1.3 root 70: env->CP0_Count = count; 71: else { 72: /* Store new count register */ 73: env->CP0_Count = 74: count - (uint32_t)muldiv64(qemu_get_clock(vm_clock), 1.1.1.4 root 75: TIMER_FREQ, get_ticks_per_sec()); 1.1.1.3 root 76: /* Update timer timer */ 77: cpu_mips_timer_update(env); 78: } 1.1 root 79: } 80: 81: void cpu_mips_store_compare (CPUState *env, uint32_t value) 82: { 1.1.1.2 root 83: env->CP0_Compare = value; 1.1.1.3 root 84: if (!(env->CP0_Cause & (1 << CP0Ca_DC))) 85: cpu_mips_timer_update(env); 86: if (env->insn_flags & ISA_MIPS32R2) 1.1.1.2 root 87: env->CP0_Cause &= ~(1 << CP0Ca_TI); 88: qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); 89: } 90: 91: void cpu_mips_start_count(CPUState *env) 92: { 93: cpu_mips_store_count(env, env->CP0_Count); 94: } 95: 96: void cpu_mips_stop_count(CPUState *env) 97: { 98: /* Store the current value */ 99: env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock), 1.1.1.4 root 100: TIMER_FREQ, get_ticks_per_sec()); 1.1 root 101: } 102: 103: static void mips_timer_cb (void *opaque) 104: { 105: CPUState *env; 106: 107: env = opaque; 108: #if 0 1.1.1.3 root 109: qemu_log("%s\n", __func__); 1.1 root 110: #endif 1.1.1.2 root 111: 112: if (env->CP0_Cause & (1 << CP0Ca_DC)) 113: return; 114: 1.1.1.3 root 115: /* ??? This callback should occur when the counter is exactly equal to 116: the comparator value. Offset the count by one to avoid immediately 117: retriggering the callback before any virtual time has passed. */ 118: env->CP0_Count++; 119: cpu_mips_timer_update(env); 120: env->CP0_Count--; 121: if (env->insn_flags & ISA_MIPS32R2) 1.1.1.2 root 122: env->CP0_Cause |= 1 << CP0Ca_TI; 123: qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); 1.1 root 124: } 125: 126: void cpu_mips_clock_init (CPUState *env) 127: { 128: env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); 129: env->CP0_Compare = 0; 1.1.1.3 root 130: cpu_mips_store_count(env, 1); 1.1 root 131: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.