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"); | ... | ... |