Commit 42532189dfba7a5675225b7b3d6da3d80f8c2447
1 parent
b51eaa82
Timer start/stop implementation, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3237 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
46 additions
and
8 deletions
hw/mips_timer.c
| ... | ... | @@ -17,9 +17,12 @@ uint32_t cpu_mips_get_random (CPUState *env) |
| 17 | 17 | /* MIPS R4K timer */ |
| 18 | 18 | uint32_t cpu_mips_get_count (CPUState *env) |
| 19 | 19 | { |
| 20 | - return env->CP0_Count + | |
| 21 | - (uint32_t)muldiv64(qemu_get_clock(vm_clock), | |
| 22 | - 100 * 1000 * 1000, ticks_per_sec); | |
| 20 | + if (env->CP0_Cause & (1 << CP0Ca_DC)) | |
| 21 | + return env->CP0_Count; | |
| 22 | + else | |
| 23 | + return env->CP0_Count + | |
| 24 | + (uint32_t)muldiv64(qemu_get_clock(vm_clock), | |
| 25 | + 100 * 1000 * 1000, ticks_per_sec); | |
| 23 | 26 | } |
| 24 | 27 | |
| 25 | 28 | void cpu_mips_store_count (CPUState *env, uint32_t count) |
| ... | ... | @@ -63,7 +66,19 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value) |
| 63 | 66 | cpu_mips_update_count(env, cpu_mips_get_count(env)); |
| 64 | 67 | if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) |
| 65 | 68 | env->CP0_Cause &= ~(1 << CP0Ca_TI); |
| 66 | - qemu_irq_lower(env->irq[7]); | |
| 69 | + qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); | |
| 70 | +} | |
| 71 | + | |
| 72 | +void cpu_mips_start_count(CPUState *env) | |
| 73 | +{ | |
| 74 | + cpu_mips_store_count(env, env->CP0_Count); | |
| 75 | +} | |
| 76 | + | |
| 77 | +void cpu_mips_stop_count(CPUState *env) | |
| 78 | +{ | |
| 79 | + /* Store the current value */ | |
| 80 | + env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock), | |
| 81 | + 100 * 1000 * 1000, ticks_per_sec); | |
| 67 | 82 | } |
| 68 | 83 | |
| 69 | 84 | static void mips_timer_cb (void *opaque) |
| ... | ... | @@ -76,10 +91,14 @@ static void mips_timer_cb (void *opaque) |
| 76 | 91 | fprintf(logfile, "%s\n", __func__); |
| 77 | 92 | } |
| 78 | 93 | #endif |
| 94 | + | |
| 95 | + if (env->CP0_Cause & (1 << CP0Ca_DC)) | |
| 96 | + return; | |
| 97 | + | |
| 79 | 98 | cpu_mips_update_count(env, cpu_mips_get_count(env)); |
| 80 | 99 | if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) |
| 81 | 100 | env->CP0_Cause |= 1 << CP0Ca_TI; |
| 82 | - qemu_irq_raise(env->irq[7]); | |
| 101 | + qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); | |
| 83 | 102 | } |
| 84 | 103 | |
| 85 | 104 | void cpu_mips_clock_init (CPUState *env) | ... | ... |
target-mips/exec.h
| ... | ... | @@ -153,6 +153,8 @@ uint32_t cpu_mips_get_random (CPUState *env); |
| 153 | 153 | uint32_t cpu_mips_get_count (CPUState *env); |
| 154 | 154 | void cpu_mips_store_count (CPUState *env, uint32_t value); |
| 155 | 155 | void cpu_mips_store_compare (CPUState *env, uint32_t value); |
| 156 | +void cpu_mips_start_count(CPUState *env); | |
| 157 | +void cpu_mips_stop_count(CPUState *env); | |
| 156 | 158 | void cpu_mips_update_irq (CPUState *env); |
| 157 | 159 | void cpu_mips_clock_init (CPUState *env); |
| 158 | 160 | void cpu_mips_tlb_flush (CPUState *env, int flush_global); | ... | ... |
target-mips/op.c
| ... | ... | @@ -1886,9 +1886,8 @@ void op_mttc0_status(void) |
| 1886 | 1886 | |
| 1887 | 1887 | void op_mtc0_intctl (void) |
| 1888 | 1888 | { |
| 1889 | - /* vectored interrupts not implemented, timer on int 7, | |
| 1890 | - no performance counters. */ | |
| 1891 | - env->CP0_IntCtl |= T0 & 0x000002e0; | |
| 1889 | + /* vectored interrupts not implemented, no performance counters. */ | |
| 1890 | + env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (T0 & 0x000002e0); | |
| 1892 | 1891 | RETURN(); |
| 1893 | 1892 | } |
| 1894 | 1893 | |
| ... | ... | @@ -1908,12 +1907,20 @@ void op_mtc0_srsmap (void) |
| 1908 | 1907 | void op_mtc0_cause (void) |
| 1909 | 1908 | { |
| 1910 | 1909 | uint32_t mask = 0x00C00300; |
| 1910 | + uint32_t old = env->CP0_Cause; | |
| 1911 | 1911 | |
| 1912 | 1912 | if (env->insn_flags & ISA_MIPS32R2) |
| 1913 | 1913 | mask |= 1 << CP0Ca_DC; |
| 1914 | 1914 | |
| 1915 | 1915 | env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask); |
| 1916 | 1916 | |
| 1917 | + if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { | |
| 1918 | + if (env->CP0_Cause & (1 << CP0Ca_DC)) | |
| 1919 | + CALL_FROM_TB1(cpu_mips_stop_count, env); | |
| 1920 | + else | |
| 1921 | + CALL_FROM_TB1(cpu_mips_start_count, env); | |
| 1922 | + } | |
| 1923 | + | |
| 1917 | 1924 | /* Handle the software interrupt as an hardware one, as they |
| 1918 | 1925 | are very similar */ |
| 1919 | 1926 | if (T0 & CP0Ca_IP_mask) { | ... | ... |
target-mips/op_helper.c
| ... | ... | @@ -265,6 +265,16 @@ void cpu_mips_store_compare(CPUState *env, uint32_t value) |
| 265 | 265 | cpu_abort(env, "mtc0 compare\n"); |
| 266 | 266 | } |
| 267 | 267 | |
| 268 | +void cpu_mips_start_count(CPUState *env) | |
| 269 | +{ | |
| 270 | + cpu_abort(env, "start count\n"); | |
| 271 | +} | |
| 272 | + | |
| 273 | +void cpu_mips_stop_count(CPUState *env) | |
| 274 | +{ | |
| 275 | + cpu_abort(env, "stop count\n"); | |
| 276 | +} | |
| 277 | + | |
| 268 | 278 | void cpu_mips_update_irq(CPUState *env) |
| 269 | 279 | { |
| 270 | 280 | cpu_abort(env, "mtc0 status / mtc0 cause\n"); | ... | ... |