Thanks, applied.
On Mon, Oct 10, 2011 at 2:25 AM, Max Filippov <jcmvb...@gmail.com> wrote:
> QEMU timer is used to post CCOMPARE interrupt when the core is halted.
> If that CCOMPARE interrupt is masked off then the timer must be rearmed
> in the callback, otherwise it will be rearmed next time the core goes to
> halt by the waiti instruction.
>
> Add test case into timer testsuite.
>
> Signed-off-by: Max Filippov <jcmvb...@gmail.com>
> ---
> hw/xtensa_pic.c | 27 ++++++++++++++++++-
> target-xtensa/cpu.h | 1 +
> target-xtensa/op_helper.c | 18 ++----------
> tests/xtensa/test_timer.S | 63
> +++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 93 insertions(+), 16 deletions(-)
>
> diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c
> index 3033ae2..e5085ea 100644
> --- a/hw/xtensa_pic.c
> +++ b/hw/xtensa_pic.c
> @@ -116,10 +116,35 @@ void xtensa_timer_irq(CPUState *env, uint32_t id,
> uint32_t active)
> qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
> }
>
> +void xtensa_rearm_ccompare_timer(CPUState *env)
> +{
> + int i;
> + uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
> +
> + for (i = 0; i < env->config->nccompare; ++i) {
> + if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
> + wake_ccount - env->sregs[CCOUNT]) {
> + wake_ccount = env->sregs[CCOMPARE + i];
> + }
> + }
> + env->wake_ccount = wake_ccount;
> + qemu_mod_timer(env->ccompare_timer, env->halt_clock +
> + muldiv64(wake_ccount - env->sregs[CCOUNT],
> + 1000000, env->config->clock_freq_khz));
> +}
> +
> static void xtensa_ccompare_cb(void *opaque)
> {
> CPUState *env = opaque;
> - xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
> +
> + if (env->halted) {
> + env->halt_clock = qemu_get_clock_ns(vm_clock);
> + xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
> + if (!cpu_has_work(env)) {
> + env->sregs[CCOUNT] = env->wake_ccount + 1;
> + xtensa_rearm_ccompare_timer(env);
> + }
> + }
> }
>
> void xtensa_irq_init(CPUState *env)
> diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
> index 339075d..966f515 100644
> --- a/target-xtensa/cpu.h
> +++ b/target-xtensa/cpu.h
> @@ -313,6 +313,7 @@ void check_interrupts(CPUXtensaState *s);
> void xtensa_irq_init(CPUState *env);
> void xtensa_advance_ccount(CPUState *env, uint32_t d);
> void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active);
> +void xtensa_rearm_ccompare_timer(CPUState *env);
> int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
> void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
> void xtensa_sync_window_from_phys(CPUState *env);
> diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
> index 64847fc..0605611 100644
> --- a/target-xtensa/op_helper.c
> +++ b/target-xtensa/op_helper.c
> @@ -370,23 +370,11 @@ void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
> return;
> }
>
> - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
> - int i;
> - uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
> -
> - for (i = 0; i < env->config->nccompare; ++i) {
> - if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
> - wake_ccount - env->sregs[CCOUNT]) {
> - wake_ccount = env->sregs[CCOMPARE + i];
> - }
> - }
> - env->wake_ccount = wake_ccount;
> - qemu_mod_timer(env->ccompare_timer, qemu_get_clock_ns(vm_clock) +
> - muldiv64(wake_ccount - env->sregs[CCOUNT],
> - 1000000, env->config->clock_freq_khz));
> - }
> env->halt_clock = qemu_get_clock_ns(vm_clock);
> env->halted = 1;
> + if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
> + xtensa_rearm_ccompare_timer(env);
> + }
> HELPER(exception)(EXCP_HLT);
> }
>
> diff --git a/tests/xtensa/test_timer.S b/tests/xtensa/test_timer.S
> index ede6395..1041cc6 100644
> --- a/tests/xtensa/test_timer.S
> +++ b/tests/xtensa/test_timer.S
> @@ -14,6 +14,7 @@ test ccompare
> wsr a2, intenable
> rsr a2, interrupt
> wsr a2, intclear
> + movi a2, 0
> wsr a2, ccompare1
> wsr a2, ccompare2
>
> @@ -37,6 +38,7 @@ test ccompare0_interrupt
> wsr a2, intenable
> rsr a2, interrupt
> wsr a2, intclear
> + movi a2, 0
> wsr a2, ccompare1
> wsr a2, ccompare2
>
> @@ -66,6 +68,7 @@ test ccompare1_interrupt
> wsr a2, intenable
> rsr a2, interrupt
> wsr a2, intclear
> + movi a2, 0
> wsr a2, ccompare0
> wsr a2, ccompare2
>
> @@ -92,6 +95,7 @@ test ccompare2_interrupt
> wsr a2, intenable
> rsr a2, interrupt
> wsr a2, intclear
> + movi a2, 0
> wsr a2, ccompare0
> wsr a2, ccompare1
>
> @@ -112,4 +116,63 @@ test ccompare2_interrupt
> 2:
> test_end
>
> +test ccompare_interrupt_masked
> + set_vector kernel, 2f
> + movi a2, 0
> + wsr a2, intenable
> + rsr a2, interrupt
> + wsr a2, intclear
> + movi a2, 0
> + wsr a2, ccompare2
> +
> + movi a3, 40
> + rsr a2, ccount
> + addi a2, a2, 20
> + wsr a2, ccompare1
> + addi a2, a2, 20
> + wsr a2, ccompare0
> + rsync
> + rsr a2, interrupt
> + assert eqi, a2, 0
> +
> + movi a2, 0x40
> + wsr a2, intenable
> + rsil a2, 0
> + loop a3, 1f
> + nop
> +1:
> + test_fail
> +2:
> + rsr a2, exccause
> + assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */
> +test_end
> +
> +test ccompare_interrupt_masked_waiti
> + set_vector kernel, 2f
> + movi a2, 0
> + wsr a2, intenable
> + rsr a2, interrupt
> + wsr a2, intclear
> + movi a2, 0
> + wsr a2, ccompare2
> +
> + movi a3, 40
> + rsr a2, ccount
> + addi a2, a2, 20
> + wsr a2, ccompare1
> + addi a2, a2, 20
> + wsr a2, ccompare0
> + rsync
> + rsr a2, interrupt
> + assert eqi, a2, 0
> +
> + movi a2, 0x40
> + wsr a2, intenable
> + waiti 0
> + test_fail
> +2:
> + rsr a2, exccause
> + assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */
> +test_end
> +
> test_suite_end
> --
> 1.7.6.4
>
>
>