From 17ab14acd488289d2f85ad6212b212c21f050b3d Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 17 Feb 2013 16:38:09 +0400 Subject: [PATCH 01/14] target/xtensa: add static vectors selection Xtensa cores may have two distinct addresses for the static vectors group. Provide a function to select one of them. Signed-off-by: Max Filippov --- target/xtensa/cpu.c | 2 +- target/xtensa/cpu.h | 10 +++++++++- target/xtensa/overlay_tool.h | 11 ++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index e8e9f9175b..09b53c76d4 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -60,7 +60,7 @@ static void xtensa_cpu_reset(CPUState *s) xcc->parent_reset(s); env->exception_taken = 0; - env->pc = env->config->exception_vector[EXC_RESET]; + env->pc = env->config->exception_vector[EXC_RESET0 + env->static_vectors]; env->sregs[LITBASE] &= ~1; env->sregs[PS] = xtensa_option_enabled(env->config, XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 7fe82a37af..6b044d32f6 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -209,7 +209,8 @@ enum { enum { /* Static vectors */ - EXC_RESET, + EXC_RESET0, + EXC_RESET1, EXC_MEMORY_ERROR, /* Dynamic vectors */ @@ -373,6 +374,7 @@ typedef struct CPUXtensaState { int64_t halt_clock; int exception_taken; + unsigned static_vectors; /* Watchpoints for DBREAK registers */ struct CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK]; @@ -461,6 +463,12 @@ void reset_mmu(CPUXtensaState *env); void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env); void debug_exception_env(CPUXtensaState *new_env, uint32_t cause); +static inline void xtensa_select_static_vectors(CPUXtensaState *env, + unsigned n) +{ + assert(n < 2); + env->static_vectors = n; +} #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) #define XTENSA_OPTION_ALL (~(uint64_t)0) diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h index e8a7fda3d8..535714243b 100644 --- a/target/xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h @@ -47,6 +47,14 @@ #define XCHAL_VECBASE_RESET_VADDR 0 #endif +#ifndef XCHAL_RESET_VECTOR0_VADDR +#define XCHAL_RESET_VECTOR0_VADDR XCHAL_RESET_VECTOR_VADDR +#endif + +#ifndef XCHAL_RESET_VECTOR1_VADDR +#define XCHAL_RESET_VECTOR1_VADDR XCHAL_RESET_VECTOR_VADDR +#endif + #ifndef XCHAL_HW_MIN_VERSION #define XCHAL_HW_MIN_VERSION 0 #endif @@ -133,7 +141,8 @@ #endif #define EXCEPTION_VECTORS { \ - [EXC_RESET] = XCHAL_RESET_VECTOR_VADDR, \ + [EXC_RESET0] = XCHAL_RESET_VECTOR0_VADDR, \ + [EXC_RESET1] = XCHAL_RESET_VECTOR1_VADDR, \ WINDOW_VECTORS \ [EXC_KERNEL] = XCHAL_KERNEL_VECTOR_VADDR, \ [EXC_USER] = XCHAL_USER_VECTOR_VADDR, \ From bd527a83232ce8b48dac4b8c86607ad8a7e28d98 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 13 Dec 2016 18:52:08 -0800 Subject: [PATCH 02/14] target/xtensa: implement RUNSTALL RUNSTALL signal stalls core execution while it's applied. It is widely used in multicore configurations to control activity of additional cores. Signed-off-by: Max Filippov --- target/xtensa/cpu.c | 3 ++- target/xtensa/cpu.h | 3 ++- target/xtensa/helper.c | 13 +++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 09b53c76d4..1c18892fca 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -47,7 +47,7 @@ static bool xtensa_cpu_has_work(CPUState *cs) { XtensaCPU *cpu = XTENSA_CPU(cs); - return cpu->env.pending_irq_level; + return !cpu->env.runstall && cpu->env.pending_irq_level; } /* CPUClass::reset() */ @@ -74,6 +74,7 @@ static void xtensa_cpu_reset(CPUState *s) env->pending_irq_level = 0; reset_mmu(env); + s->halted = env->runstall; } static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 6b044d32f6..77bd9d2a7f 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -366,7 +366,7 @@ typedef struct CPUXtensaState { xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE]; xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE]; unsigned autorefill_idx; - + bool runstall; int pending_irq_level; /* level of last raised IRQ */ void **irq_inputs; QEMUTimer *ccompare_timer; @@ -469,6 +469,7 @@ static inline void xtensa_select_static_vectors(CPUXtensaState *env, assert(n < 2); env->static_vectors = n; } +void xtensa_runstall(CPUXtensaState *env, bool runstall); #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) #define XTENSA_OPTION_ALL (~(uint64_t)0) diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index 768b32c417..c67d715c4b 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -728,3 +728,16 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env) cpu_fprintf(f, "No TLB for this CPU core\n"); } } + +void xtensa_runstall(CPUXtensaState *env, bool runstall) +{ + CPUState *cpu = CPU(xtensa_env_get_cpu(env)); + + env->runstall = runstall; + cpu->halted = runstall; + if (runstall) { + cpu_interrupt(cpu, CPU_INTERRUPT_HALT); + } else { + cpu_reset_interrupt(cpu, CPU_INTERRUPT_HALT); + } +} From 59a71f75789fb15bac0a67a18325c4ac1acc981c Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 4 Sep 2013 04:57:49 +0400 Subject: [PATCH 03/14] target/xtensa: refactor CCOUNT/CCOMPARE Xtensa cores may have a register (CCOUNT) that counts core clock cycles. It may also have a number of registers (CCOMPAREx); when CCOUNT value passes the value of CCOMPAREx, timer interrupt x is raised. Currently xtensa target counts a number of completed instructions and assumes that for CCOUNT one instruction takes one cycle to complete. It calls helper function to update CCOUNT register at every TB end and raise timer interrupts. This scheme works very predictably and doesn't have noticeable performance impact, but it is hard to use with multiple synchronized processors, especially with coming MTTCG. Derive CCOUNT from the virtual simulation time, QEMU_CLOCK_VIRTUAL. Use native QEMU timers for CCOMPARE timers, one timer for each register. Signed-off-by: Max Filippov --- hw/xtensa/pic_cpu.c | 75 ++++++++------------------------------- target/xtensa/cpu.h | 16 ++++++--- target/xtensa/helper.h | 5 +-- target/xtensa/op_helper.c | 33 ++++++++++++----- target/xtensa/translate.c | 43 +++++++--------------- 5 files changed, 65 insertions(+), 107 deletions(-) diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index 2bed64f15b..0e812d7f06 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -31,22 +31,6 @@ #include "qemu/log.h" #include "qemu/timer.h" -void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d) -{ - uint32_t old_ccount = env->sregs[CCOUNT] + 1; - - env->sregs[CCOUNT] += d; - - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { - int i; - for (i = 0; i < env->config->nccompare; ++i) { - if (env->sregs[CCOMPARE + i] - old_ccount < d) { - xtensa_timer_irq(env, i, 1); - } - } - } -} - void check_interrupts(CPUXtensaState *env) { CPUState *cs = CPU(xtensa_env_get_cpu(env)); @@ -54,17 +38,6 @@ void check_interrupts(CPUXtensaState *env) uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE]; int level; - /* If the CPU is halted advance CCOUNT according to the QEMU_CLOCK_VIRTUAL time - * elapsed since the moment when it was advanced last time. - */ - if (cs->halted) { - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - xtensa_advance_ccount(env, - muldiv64(now - env->halt_clock, - env->config->clock_freq_khz, 1000000)); - env->halt_clock = now; - } for (level = env->config->nlevel; level > minlevel; --level) { if (env->config->level_mask[level] & int_set_enabled) { env->pending_irq_level = level; @@ -109,49 +82,29 @@ void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active) qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active); } -void xtensa_rearm_ccompare_timer(CPUXtensaState *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; - timer_mod(env->ccompare_timer, env->halt_clock + - (uint64_t)(wake_ccount - env->sregs[CCOUNT]) * - 1000000 / env->config->clock_freq_khz); -} - static void xtensa_ccompare_cb(void *opaque) { - XtensaCPU *cpu = opaque; - CPUXtensaState *env = &cpu->env; - CPUState *cs = CPU(cpu); + XtensaCcompareTimer *ccompare = opaque; + CPUXtensaState *env = ccompare->env; + unsigned i = ccompare - env->ccompare; - if (cs->halted) { - env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); - if (!cpu_has_work(cs)) { - env->sregs[CCOUNT] = env->wake_ccount + 1; - xtensa_rearm_ccompare_timer(env); - } - } + xtensa_timer_irq(env, i, 1); } void xtensa_irq_init(CPUXtensaState *env) { - XtensaCPU *cpu = xtensa_env_get_cpu(env); - env->irq_inputs = (void **)qemu_allocate_irqs( xtensa_set_irq, env, env->config->ninterrupt); - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) && - env->config->nccompare > 0) { - env->ccompare_timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, &xtensa_ccompare_cb, cpu); + if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { + unsigned i; + + env->time_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + env->ccount_base = env->sregs[CCOUNT]; + for (i = 0; i < env->config->nccompare; ++i) { + env->ccompare[i].env = env; + env->ccompare[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + xtensa_ccompare_cb, env->ccompare + i); + } } } diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 77bd9d2a7f..744af815aa 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -269,6 +269,8 @@ typedef enum { INTTYPE_MAX } interrupt_type; +struct CPUXtensaState; + typedef struct xtensa_tlb_entry { uint32_t vaddr; uint32_t paddr; @@ -298,6 +300,11 @@ typedef struct XtensaGdbRegmap { XtensaGdbReg reg[1 + 16 + 64 + 256 + 256]; } XtensaGdbRegmap; +typedef struct XtensaCcompareTimer { + struct CPUXtensaState *env; + QEMUTimer *timer; +} XtensaCcompareTimer; + struct XtensaConfig { const char *name; uint64_t options; @@ -369,9 +376,10 @@ typedef struct CPUXtensaState { bool runstall; int pending_irq_level; /* level of last raised IRQ */ void **irq_inputs; - QEMUTimer *ccompare_timer; - uint32_t wake_ccount; - int64_t halt_clock; + XtensaCcompareTimer ccompare[MAX_NCCOMPARE]; + uint64_t time_base; + uint64_t ccount_time; + uint32_t ccount_base; int exception_taken; unsigned static_vectors; @@ -439,9 +447,7 @@ void xtensa_register_core(XtensaConfigList *node); void check_interrupts(CPUXtensaState *s); void xtensa_irq_init(CPUXtensaState *env); void *xtensa_get_extint(CPUXtensaState *env, unsigned extint); -void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d); void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active); -void xtensa_rearm_ccompare_timer(CPUXtensaState *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(CPUXtensaState *env); diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h index 5ea9c5beec..427bdc7a3a 100644 --- a/target/xtensa/helper.h +++ b/target/xtensa/helper.h @@ -18,8 +18,9 @@ DEF_HELPER_1(simcall, void, env) DEF_HELPER_1(dump_state, void, env) DEF_HELPER_3(waiti, void, env, i32, i32) -DEF_HELPER_3(timer_irq, void, env, i32, i32) -DEF_HELPER_2(advance_ccount, void, env, i32) +DEF_HELPER_1(update_ccount, void, env) +DEF_HELPER_2(wsr_ccount, void, env, i32) +DEF_HELPER_2(update_ccompare, void, env, i32) DEF_HELPER_1(check_interrupts, void, env) DEF_HELPER_3(check_atomctl, void, env, i32, i32) diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index 0a4b2147bc..5e5c7da010 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -398,22 +398,39 @@ void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel) } cpu = CPU(xtensa_env_get_cpu(env)); - env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); cpu->halted = 1; - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { - xtensa_rearm_ccompare_timer(env); - } HELPER(exception)(env, EXCP_HLT); } -void HELPER(timer_irq)(CPUXtensaState *env, uint32_t id, uint32_t active) +void HELPER(update_ccount)(CPUXtensaState *env) { - xtensa_timer_irq(env, id, active); + uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + env->ccount_time = now; + env->sregs[CCOUNT] = env->ccount_base + + (uint32_t)((now - env->time_base) * + env->config->clock_freq_khz / 1000000); } -void HELPER(advance_ccount)(CPUXtensaState *env, uint32_t d) +void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v) { - xtensa_advance_ccount(env, d); + int i; + + HELPER(update_ccount)(env); + env->ccount_base += v - env->sregs[CCOUNT]; + for (i = 0; i < env->config->nccompare; ++i) { + HELPER(update_ccompare)(env, i); + } +} + +void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) +{ + uint64_t dcc; + + HELPER(update_ccount)(env); + dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1; + timer_mod(env->ccompare[i].timer, + env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz); } void HELPER(check_interrupts)(CPUXtensaState *env) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 0858c296ea..cb4294514e 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -64,7 +64,6 @@ typedef struct DisasContext { bool sar_m32_allocated; TCGv_i32 sar_m32; - uint32_t ccount_delta; unsigned window; bool debug; @@ -314,20 +313,9 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa) tcg_temp_free(tmp); } -static void gen_advance_ccount(DisasContext *dc) -{ - if (dc->ccount_delta > 0) { - TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta); - gen_helper_advance_ccount(cpu_env, tmp); - tcg_temp_free(tmp); - } - dc->ccount_delta = 0; -} - static void gen_exception(DisasContext *dc, int excp) { TCGv_i32 tmp = tcg_const_i32(excp); - gen_advance_ccount(dc); gen_helper_exception(cpu_env, tmp); tcg_temp_free(tmp); } @@ -336,7 +324,6 @@ static void gen_exception_cause(DisasContext *dc, uint32_t cause) { TCGv_i32 tpc = tcg_const_i32(dc->pc); TCGv_i32 tcause = tcg_const_i32(cause); - gen_advance_ccount(dc); gen_helper_exception_cause(cpu_env, tpc, tcause); tcg_temp_free(tpc); tcg_temp_free(tcause); @@ -351,7 +338,6 @@ static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause, { TCGv_i32 tpc = tcg_const_i32(dc->pc); TCGv_i32 tcause = tcg_const_i32(cause); - gen_advance_ccount(dc); gen_helper_exception_cause_vaddr(cpu_env, tpc, tcause, vaddr); tcg_temp_free(tpc); tcg_temp_free(tcause); @@ -361,7 +347,6 @@ static void gen_debug_exception(DisasContext *dc, uint32_t cause) { TCGv_i32 tpc = tcg_const_i32(dc->pc); TCGv_i32 tcause = tcg_const_i32(cause); - gen_advance_ccount(dc); gen_helper_debug_exception(cpu_env, tpc, tcause); tcg_temp_free(tpc); tcg_temp_free(tcause); @@ -394,7 +379,6 @@ static bool gen_check_cpenable(DisasContext *dc, unsigned cp) static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot) { tcg_gen_mov_i32(cpu_pc, dest); - gen_advance_ccount(dc); if (dc->icount) { tcg_gen_mov_i32(cpu_SR[ICOUNT], dc->next_icount); } @@ -465,7 +449,6 @@ static bool gen_check_loop_end(DisasContext *dc, int slot) dc->next_pc == dc->lend) { TCGLabel *label = gen_new_label(); - gen_advance_ccount(dc); tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label); tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1); gen_jumpi(dc, dc->lbeg, slot); @@ -488,7 +471,6 @@ static void gen_brcond(DisasContext *dc, TCGCond cond, { TCGLabel *label = gen_new_label(); - gen_advance_ccount(dc); tcg_gen_brcond_i32(cond, t0, t1, label); gen_jumpi_check_loop_end(dc, 0); gen_set_label(label); @@ -530,7 +512,7 @@ static bool gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access) static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr) { - gen_advance_ccount(dc); + gen_helper_update_ccount(cpu_env); tcg_gen_mov_i32(d, cpu_SR[sr]); } @@ -546,6 +528,7 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) static void (* const rsr_handler[256])(DisasContext *dc, TCGv_i32 d, uint32_t sr) = { [CCOUNT] = gen_rsr_ccount, + [INTSET] = gen_rsr_ccount, [PTEVADDR] = gen_rsr_ptevaddr, }; @@ -720,6 +703,11 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) gen_jumpi_check_loop_end(dc, -1); } +static void gen_wsr_ccount(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + gen_helper_wsr_ccount(cpu_env, v); +} + static void gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v) { if (dc->icount) { @@ -741,10 +729,12 @@ static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v) uint32_t id = sr - CCOMPARE; if (id < dc->config->nccompare) { uint32_t int_bit = 1 << dc->config->timerint[id]; - gen_advance_ccount(dc); + TCGv_i32 tmp = tcg_const_i32(id); + tcg_gen_mov_i32(cpu_SR[sr], v); tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit); - gen_helper_check_interrupts(cpu_env); + gen_helper_update_ccompare(cpu_env, tmp); + tcg_temp_free(tmp); } } @@ -777,6 +767,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) [INTCLEAR] = gen_wsr_intclear, [INTENABLE] = gen_wsr_intenable, [PS] = gen_wsr_ps, + [CCOUNT] = gen_wsr_ccount, [ICOUNT] = gen_wsr_icount, [ICOUNTLEVEL] = gen_wsr_icountlevel, [CCOMPARE] = gen_wsr_ccompare, @@ -829,7 +820,6 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4) { TCGv_i32 pc = tcg_const_i32(dc->next_pc); TCGv_i32 intlevel = tcg_const_i32(imm4); - gen_advance_ccount(dc); gen_helper_waiti(cpu_env, pc, intlevel); tcg_temp_free(pc); tcg_temp_free(intlevel); @@ -841,7 +831,6 @@ static bool gen_window_check1(DisasContext *dc, unsigned r1) TCGv_i32 pc = tcg_const_i32(dc->pc); TCGv_i32 w = tcg_const_i32(r1 / 4); - gen_advance_ccount(dc); gen_helper_window_check(cpu_env, pc, w); dc->is_jmp = DISAS_UPDATE; return false; @@ -1037,7 +1026,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); { TCGv_i32 tmp = tcg_const_i32(dc->pc); - gen_advance_ccount(dc); gen_helper_retw(tmp, cpu_env, tmp); gen_jump(dc, tmp); tcg_temp_free(tmp); @@ -1086,7 +1074,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); if (gen_window_check2(dc, RRR_T, RRR_S)) { TCGv_i32 pc = tcg_const_i32(dc->pc); - gen_advance_ccount(dc); gen_helper_movsp(cpu_env, pc); tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]); tcg_temp_free(pc); @@ -2517,7 +2504,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); gen_load_store_alignment(dc, 2, addr, true); - gen_advance_ccount(dc); tpc = tcg_const_i32(dc->pc); gen_helper_check_atomctl(cpu_env, tpc, addr); tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring); @@ -2747,7 +2733,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) TCGv_i32 pc = tcg_const_i32(dc->pc); TCGv_i32 s = tcg_const_i32(BRI12_S); TCGv_i32 imm = tcg_const_i32(BRI12_IMM12); - gen_advance_ccount(dc); gen_helper_entry(cpu_env, pc, s, imm); tcg_temp_free(imm); tcg_temp_free(s); @@ -2966,7 +2951,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); { TCGv_i32 tmp = tcg_const_i32(dc->pc); - gen_advance_ccount(dc); gen_helper_retw(tmp, cpu_env, tmp); gen_jump(dc, tmp); tcg_temp_free(tmp); @@ -3063,7 +3047,6 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb) dc.lbeg = env->sregs[LBEG]; dc.lend = env->sregs[LEND]; dc.is_jmp = DISAS_NEXT; - dc.ccount_delta = 0; dc.debug = tb->flags & XTENSA_TBFLAG_DEBUG; dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT; dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >> @@ -3088,8 +3071,6 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb) tcg_gen_insn_start(dc.pc); ++insn_count; - ++dc.ccount_delta; - if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) { tcg_gen_movi_i32(cpu_pc, dc.pc); gen_exception(&dc, EXCP_DEBUG); From d2132510ca88340bed89db5655e65b7cd87d3d8b Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 22 Jul 2013 08:02:43 +0400 Subject: [PATCH 04/14] target/xtensa: support icount Delimit each instruction that may access timers or IRQ state with qemu_io_start/qemu_io_end, so that qemu-system-xtensa could be run with -icount option. Raise EXCP_YIELD after CCOMPARE reprogramming to let tcg_cpu_exec recalculate how long this CPU is allowed to run. RSR now may need to terminate TB, but it can't be done in RSR handler because the same handler is used for XSR together with WSR handler, which may also need to terminate TB. Change RSR and WSR handlers return type to bool indicating whether TB termination is needed (RSR) or has been done (WSR), and add TB termination after RSR/WSR dispatcher call. Signed-off-by: Max Filippov --- target/xtensa/cpu.h | 5 ++ target/xtensa/op_helper.c | 4 + target/xtensa/translate.c | 179 ++++++++++++++++++++++++++++---------- 3 files changed, 143 insertions(+), 45 deletions(-) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 744af815aa..a10f1efd8d 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -382,6 +382,7 @@ typedef struct CPUXtensaState { uint32_t ccount_base; int exception_taken; + int yield_needed; unsigned static_vectors; /* Watchpoints for DBREAK registers */ @@ -554,6 +555,7 @@ static inline int cpu_mmu_index(CPUXtensaState *env, bool ifetch) #define XTENSA_TBFLAG_EXCEPTION 0x4000 #define XTENSA_TBFLAG_WINDOW_MASK 0x18000 #define XTENSA_TBFLAG_WINDOW_SHIFT 15 +#define XTENSA_TBFLAG_YIELD 0x20000 static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) @@ -595,6 +597,9 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, } else { *flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT; } + if (env->yield_needed) { + *flags |= XTENSA_TBFLAG_YIELD; + } } #include "exec/cpu-all.h" diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index 5e5c7da010..864a8f6eba 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -105,6 +105,9 @@ void HELPER(exception)(CPUXtensaState *env, uint32_t excp) CPUState *cs = CPU(xtensa_env_get_cpu(env)); cs->exception_index = excp; + if (excp == EXCP_YIELD) { + env->yield_needed = 0; + } if (excp == EXCP_DEBUG) { env->exception_taken = 0; } @@ -431,6 +434,7 @@ void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1; timer_mod(env->ccompare[i].timer, env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz); + env->yield_needed = 1; } void HELPER(check_interrupts)(CPUXtensaState *env) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index cb4294514e..96c64d6c7f 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -510,22 +510,31 @@ static bool gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access) return true; } -static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr) +static bool gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr) { + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_update_ccount(cpu_env); tcg_gen_mov_i32(d, cpu_SR[sr]); + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_end(); + return true; + } + return false; } -static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr) +static bool gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr) { tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10); tcg_gen_or_i32(d, d, cpu_SR[sr]); tcg_gen_andi_i32(d, d, 0xfffffffc); + return false; } -static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) +static bool gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) { - static void (* const rsr_handler[256])(DisasContext *dc, + static bool (* const rsr_handler[256])(DisasContext *dc, TCGv_i32 d, uint32_t sr) = { [CCOUNT] = gen_rsr_ccount, [INTSET] = gen_rsr_ccount, @@ -533,25 +542,28 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) }; if (rsr_handler[sr]) { - rsr_handler[sr](dc, d, sr); + return rsr_handler[sr](dc, d, sr); } else { tcg_gen_mov_i32(d, cpu_SR[sr]); + return false; } } -static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s) +static bool gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s) { gen_helper_wsr_lbeg(cpu_env, s); gen_jumpi_check_loop_end(dc, 0); + return false; } -static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s) +static bool gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s) { gen_helper_wsr_lend(cpu_env, s); gen_jumpi_check_loop_end(dc, 0); + return false; } -static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s) +static bool gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s) { tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f); if (dc->sar_m32_5bit) { @@ -559,68 +571,79 @@ static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s) } dc->sar_5bit = false; dc->sar_m32_5bit = false; + return false; } -static void gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s) +static bool gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s) { tcg_gen_andi_i32(cpu_SR[sr], s, 0xffff); + return false; } -static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s) +static bool gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s) { tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001); /* This can change tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); + return true; } -static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s) +static bool gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s) { tcg_gen_ext8s_i32(cpu_SR[sr], s); + return false; } -static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v) { gen_helper_wsr_windowbase(cpu_env, v); /* This can change tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); + return true; } -static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1); /* This can change tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); + return true; } -static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000); + return false; } -static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v) { gen_helper_wsr_rasid(cpu_env, v); /* This can change tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); + return true; } -static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000); + return false; } -static void gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) { gen_helper_wsr_ibreakenable(cpu_env, v); gen_jumpi_check_loop_end(dc, 0); + return true; } -static void gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_andi_i32(cpu_SR[sr], v, 0x3f); + return false; } -static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) { unsigned id = sr - IBREAKA; @@ -629,10 +652,12 @@ static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) gen_helper_wsr_ibreaka(cpu_env, tmp, v); tcg_temp_free(tmp); gen_jumpi_check_loop_end(dc, 0); + return true; } + return false; } -static void gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) { unsigned id = sr - DBREAKA; @@ -641,9 +666,10 @@ static void gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) gen_helper_wsr_dbreaka(cpu_env, tmp, v); tcg_temp_free(tmp); } + return false; } -static void gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v) { unsigned id = sr - DBREAKC; @@ -652,24 +678,38 @@ static void gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v) gen_helper_wsr_dbreakc(cpu_env, tmp, v); tcg_temp_free(tmp); } + return false; } -static void gen_wsr_cpenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_cpenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_andi_i32(cpu_SR[sr], v, 0xff); /* This can change tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); + return true; } -static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static void gen_check_interrupts(DisasContext *dc) +{ + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_start(); + } + gen_helper_check_interrupts(cpu_env); + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_end(); + } +} + +static bool gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_andi_i32(cpu_SR[sr], v, dc->config->inttype_mask[INTTYPE_SOFTWARE]); - gen_helper_check_interrupts(cpu_env); + gen_check_interrupts(dc); gen_jumpi_check_loop_end(dc, 0); + return true; } -static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -679,17 +719,20 @@ static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v) dc->config->inttype_mask[INTTYPE_SOFTWARE]); tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp); tcg_temp_free(tmp); - gen_helper_check_interrupts(cpu_env); + gen_check_interrupts(dc); + gen_jumpi_check_loop_end(dc, 0); + return true; } -static void gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_mov_i32(cpu_SR[sr], v); - gen_helper_check_interrupts(cpu_env); + gen_check_interrupts(dc); gen_jumpi_check_loop_end(dc, 0); + return true; } -static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) { uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB | PS_UM | PS_EXCM | PS_INTLEVEL; @@ -698,49 +741,72 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) mask |= PS_RING; } tcg_gen_andi_i32(cpu_SR[sr], v, mask); - gen_helper_check_interrupts(cpu_env); + gen_check_interrupts(dc); /* This can change mmu index and tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); + return true; } -static void gen_wsr_ccount(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_ccount(DisasContext *dc, uint32_t sr, TCGv_i32 v) { + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_wsr_ccount(cpu_env, v); + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_end(); + gen_jumpi_check_loop_end(dc, 0); + return true; + } + return false; } -static void gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v) { if (dc->icount) { tcg_gen_mov_i32(dc->next_icount, v); } else { tcg_gen_mov_i32(cpu_SR[sr], v); } + return false; } -static void gen_wsr_icountlevel(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_icountlevel(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_andi_i32(cpu_SR[sr], v, 0xf); /* This can change tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); + return true; } -static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v) +static bool gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v) { uint32_t id = sr - CCOMPARE; + bool ret = false; + if (id < dc->config->nccompare) { uint32_t int_bit = 1 << dc->config->timerint[id]; TCGv_i32 tmp = tcg_const_i32(id); tcg_gen_mov_i32(cpu_SR[sr], v); tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit); + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_update_ccompare(cpu_env, tmp); + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_end(); + gen_jumpi_check_loop_end(dc, 0); + ret = true; + } tcg_temp_free(tmp); } + return ret; } -static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) +static bool gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) { - static void (* const wsr_handler[256])(DisasContext *dc, + static bool (* const wsr_handler[256])(DisasContext *dc, uint32_t sr, TCGv_i32 v) = { [LBEG] = gen_wsr_lbeg, [LEND] = gen_wsr_lend, @@ -776,9 +842,10 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) }; if (wsr_handler[sr]) { - wsr_handler[sr](dc, sr, s); + return wsr_handler[sr](dc, sr, s); } else { tcg_gen_mov_i32(cpu_SR[sr], s); + return false; } } @@ -820,9 +887,17 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4) { TCGv_i32 pc = tcg_const_i32(dc->next_pc); TCGv_i32 intlevel = tcg_const_i32(imm4); + + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_waiti(cpu_env, pc, intlevel); + if (dc->tb->cflags & CF_USE_ICOUNT) { + gen_io_end(); + } tcg_temp_free(pc); tcg_temp_free(intlevel); + gen_jumpi_check_loop_end(dc, 0); } static bool gen_window_check1(DisasContext *dc, unsigned r1) @@ -1121,7 +1196,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) case 0: /*RFEx*/ if (gen_check_privilege(dc)) { tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); - gen_helper_check_interrupts(cpu_env); + gen_check_interrupts(dc); gen_jump(dc, cpu_SR[EPC1]); } break; @@ -1156,7 +1231,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) } gen_helper_restore_owb(cpu_env); - gen_helper_check_interrupts(cpu_env); + gen_check_interrupts(dc); gen_jump(dc, cpu_SR[EPC1]); tcg_temp_free(tmp); @@ -1175,7 +1250,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) if (gen_check_privilege(dc)) { tcg_gen_mov_i32(cpu_SR[PS], cpu_SR[EPS2 + RRR_S - 2]); - gen_helper_check_interrupts(cpu_env); + gen_check_interrupts(dc); gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]); } } else { @@ -1233,7 +1308,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]); tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL); tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S); - gen_helper_check_interrupts(cpu_env); + gen_check_interrupts(dc); gen_jumpi_check_loop_end(dc, 0); } break; @@ -1521,11 +1596,15 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) (RSR_SR < 64 || gen_check_privilege(dc)) && gen_window_check1(dc, RRR_T)) { TCGv_i32 tmp = tcg_temp_new_i32(); + bool rsr_end, wsr_end; tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); - gen_rsr(dc, cpu_R[RRR_T], RSR_SR); - gen_wsr(dc, RSR_SR, tmp); + rsr_end = gen_rsr(dc, cpu_R[RRR_T], RSR_SR); + wsr_end = gen_wsr(dc, RSR_SR, tmp); tcg_temp_free(tmp); + if (rsr_end && !wsr_end) { + gen_jumpi_check_loop_end(dc, 0); + } } break; @@ -1746,7 +1825,9 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) if (gen_check_sr(dc, RSR_SR, SR_R) && (RSR_SR < 64 || gen_check_privilege(dc)) && gen_window_check1(dc, RRR_T)) { - gen_rsr(dc, cpu_R[RRR_T], RSR_SR); + if (gen_rsr(dc, cpu_R[RRR_T], RSR_SR)) { + gen_jumpi_check_loop_end(dc, 0); + } } break; @@ -3062,6 +3143,14 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb) gen_tb_start(tb); + if ((tb->cflags & CF_USE_ICOUNT) && + (tb->flags & XTENSA_TBFLAG_YIELD)) { + tcg_gen_insn_start(dc.pc); + ++insn_count; + gen_exception(&dc, EXCP_YIELD); + dc.is_jmp = DISAS_UPDATE; + goto done; + } if (tb->flags & XTENSA_TBFLAG_EXCEPTION) { tcg_gen_movi_i32(cpu_pc, dc.pc); gen_exception(&dc, EXCP_DEBUG); @@ -3117,7 +3206,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb) dc.pc < next_page_start && dc.pc + xtensa_insn_len(env, &dc) <= next_page_start && !tcg_op_buf_full()); - +done: reset_litbase(&dc); reset_sar_tracker(&dc); if (dc.icount) { From 787eaa4904c53070fd5ad772b93e3683354a4b04 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sat, 14 Jan 2017 16:38:09 -0800 Subject: [PATCH 05/14] target/xtensa: don't continue translation after exception There's no point in continuing translating guest instructions once an unconditional exception is thrown. There's also no point in updating pc before any instruction is translated, don't do it. Signed-off-by: Max Filippov --- target/xtensa/translate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 96c64d6c7f..7a198fa203 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -3152,8 +3152,11 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb) goto done; } if (tb->flags & XTENSA_TBFLAG_EXCEPTION) { - tcg_gen_movi_i32(cpu_pc, dc.pc); + tcg_gen_insn_start(dc.pc); + ++insn_count; gen_exception(&dc, EXCP_DEBUG); + dc.is_jmp = DISAS_UPDATE; + goto done; } do { From 122d302053062af886c2272f1049017cbfdba7b3 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 27 Dec 2016 02:01:48 -0800 Subject: [PATCH 06/14] target/xtensa: tests: run tests with icount Timer tests expect certain determinism in CCOUNT updates and timer interrupts firing. Run QEMU with -icount to get deterministic results. Signed-off-by: Max Filippov --- tests/tcg/xtensa/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile index 7f9f2d96c3..2882c431e4 100644 --- a/tests/tcg/xtensa/Makefile +++ b/tests/tcg/xtensa/Makefile @@ -5,7 +5,7 @@ CROSS=xtensa-$(CORE)-elf- ifndef XT SIM = ../../../xtensa-softmmu/qemu-system-xtensa -SIMFLAGS = -M sim -cpu $(CORE) -nographic -semihosting $(EXTFLAGS) -kernel +SIMFLAGS = -M sim -cpu $(CORE) -nographic -semihosting -icount 7 $(EXTFLAGS) -kernel SIMDEBUG = -s -S else SIM = xt-run From 72b3b8f24a4ada7f6e97fe5cd83e04f94b1f25e0 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 5 Sep 2016 20:55:13 -0700 Subject: [PATCH 07/14] target/xtensa: tests: fix timer tests Don't expect that CCOUNT increments are equal to the number of executed instructions. Verify that timer interrupt does not fire before the programmed CCOMPARE value and does fire after. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_timer.S | 61 +++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S index f8c6f7423a..9e6012d7fd 100644 --- a/tests/tcg/xtensa/test_timer.S +++ b/tests/tcg/xtensa/test_timer.S @@ -1,12 +1,22 @@ #include "macros.inc" +#define CCOUNT_SHIFT 4 +#define WAIT_LOOPS 20 + +.macro make_ccount_delta target, delta + rsr \delta, ccount + rsr \target, ccount + sub \delta, \target, \delta + slli \delta, \delta, CCOUNT_SHIFT + add \target, \target, \delta +.endm + test_suite timer test ccount rsr a3, ccount rsr a4, ccount - sub a3, a4, a3 - assert eqi, a3, 1 + assert ne, a3, a4 test_end test ccompare @@ -18,18 +28,18 @@ test ccompare wsr a2, ccompare1 wsr a2, ccompare2 - movi a3, 20 - rsr a2, ccount - addi a2, a2, 20 + make_ccount_delta a2, a15 wsr a2, ccompare0 - rsr a2, interrupt - assert eqi, a2, 0 - loop a3, 1f - rsr a3, interrupt - bnez a3, 2f 1: - test_fail + rsr a3, interrupt + rsr a4, ccount + rsr a5, interrupt + sub a4, a4, a2 + bgez a4, 2f + assert eqi, a3, 0 + j 1b 2: + assert nei, a5, 0 test_end test ccompare0_interrupt @@ -42,9 +52,8 @@ test ccompare0_interrupt wsr a2, ccompare1 wsr a2, ccompare2 - movi a3, 20 - rsr a2, ccount - addi a2, a2, 20 + movi a3, WAIT_LOOPS + make_ccount_delta a2, a15 wsr a2, ccompare0 rsync rsr a2, interrupt @@ -72,9 +81,8 @@ test ccompare1_interrupt wsr a2, ccompare0 wsr a2, ccompare2 - movi a3, 20 - rsr a2, ccount - addi a2, a2, 20 + movi a3, WAIT_LOOPS + make_ccount_delta a2, a15 wsr a2, ccompare1 rsync rsr a2, interrupt @@ -99,9 +107,8 @@ test ccompare2_interrupt wsr a2, ccompare0 wsr a2, ccompare1 - movi a3, 20 - rsr a2, ccount - addi a2, a2, 20 + movi a3, WAIT_LOOPS + make_ccount_delta a2, a15 wsr a2, ccompare2 rsync rsr a2, interrupt @@ -125,11 +132,10 @@ test ccompare_interrupt_masked movi a2, 0 wsr a2, ccompare2 - movi a3, 40 - rsr a2, ccount - addi a2, a2, 20 + movi a3, 2 * WAIT_LOOPS + make_ccount_delta a2, a15 wsr a2, ccompare1 - addi a2, a2, 20 + add a2, a2, a15 wsr a2, ccompare0 rsync rsr a2, interrupt @@ -156,11 +162,10 @@ test ccompare_interrupt_masked_waiti movi a2, 0 wsr a2, ccompare2 - movi a3, 40 - rsr a2, ccount - addi a2, a2, 20 + movi a3, 2 * WAIT_LOOPS + make_ccount_delta a2, a15 wsr a2, ccompare1 - addi a2, a2, 20 + add a2, a2, a15 wsr a2, ccompare0 rsync rsr a2, interrupt From 4f89b41c28a17739c4fd40886542e3cb8c7a15a3 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sat, 14 Jan 2017 19:58:55 -0800 Subject: [PATCH 08/14] target/xtensa: tests: replace hardcoded interrupt masks Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_timer.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S index 9e6012d7fd..844c0327aa 100644 --- a/tests/tcg/xtensa/test_timer.S +++ b/tests/tcg/xtensa/test_timer.S @@ -59,7 +59,7 @@ test ccompare0_interrupt rsr a2, interrupt assert eqi, a2, 0 - movi a2, 0x40 + movi a2, 1 << XCHAL_TIMER0_INTERRUPT wsr a2, intenable rsil a2, 0 loop a3, 1f @@ -87,7 +87,7 @@ test ccompare1_interrupt rsync rsr a2, interrupt assert eqi, a2, 0 - movi a2, 0x400 + movi a2, 1 << XCHAL_TIMER1_INTERRUPT wsr a2, intenable rsil a2, 2 loop a3, 1f @@ -113,7 +113,7 @@ test ccompare2_interrupt rsync rsr a2, interrupt assert eqi, a2, 0 - movi a2, 0x2000 + movi a2, 1 << XCHAL_TIMER2_INTERRUPT wsr a2, intenable rsil a2, 4 loop a3, 1f @@ -141,7 +141,7 @@ test ccompare_interrupt_masked rsr a2, interrupt assert eqi, a2, 0 - movi a2, 0x40 + movi a2, 1 << XCHAL_TIMER0_INTERRUPT wsr a2, intenable rsil a2, 0 loop a3, 1f @@ -171,7 +171,7 @@ test ccompare_interrupt_masked_waiti rsr a2, interrupt assert eqi, a2, 0 - movi a2, 0x40 + movi a2, 1 << XCHAL_TIMER0_INTERRUPT wsr a2, intenable waiti 0 test_fail From 0a362d0768c443cf9e5c36c8398c92bfebe9b8a4 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 15 Jan 2017 08:42:31 -0800 Subject: [PATCH 09/14] target/xtensa: tests: add ccount write tests Check that CCOUNT SR is writable and that CCOMPARE timers are updated when CCOUNT is written to. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_timer.S | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S index 844c0327aa..6cda71adbb 100644 --- a/tests/tcg/xtensa/test_timer.S +++ b/tests/tcg/xtensa/test_timer.S @@ -19,6 +19,40 @@ test ccount assert ne, a3, a4 test_end +test ccount_write + rsr a3, ccount + rsr a4, ccount + sub a4, a4, a3 + movi a2, 0x12345678 + wsr a2, ccount + esync + rsr a3, ccount + sub a3, a3, a2 + slli a4, a4, 2 + assert ltu, a3, a4 +test_end + +test ccount_update_deadline + movi a2, 0 + wsr a2, intenable + rsr a2, interrupt + wsr a2, intclear + movi a2, 0 + wsr a2, ccompare1 + wsr a2, ccompare2 + movi a2, 0x12345678 + wsr a2, ccompare0 + rsr a3, interrupt + assert eqi, a3, 0 + movi a2, 0x12345677 + wsr a2, ccount + esync + nop + rsr a2, interrupt + movi a3, 1 << XCHAL_TIMER0_INTERRUPT + assert eq, a2, a3 +test_end + test ccompare movi a2, 0 wsr a2, intenable From 4b37aaa879d508494df14bdc49830cdf8aa77a57 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sat, 12 Nov 2016 01:15:07 -0800 Subject: [PATCH 10/14] target/xtensa: fix ICACHE/DCACHE options detection Configuration overlay does not explicitly say whether there are ICACHE and DCACHE in the core. Current code uses XCHAL_[ID]CACHE_WAYS to detect if corresponding cache option is enabled, but that's not correct: on cores without cache these macros are defined as 1, not as 0. Check XCHAL_[ID]CACHE_SIZE instead. Signed-off-by: Max Filippov --- target/xtensa/overlay_tool.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h index 535714243b..b73fd14dd1 100644 --- a/target/xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h @@ -92,10 +92,10 @@ XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT) | \ XCHAL_OPTION(XCHAL_HAVE_CCOUNT, XTENSA_OPTION_TIMER_INTERRUPT) | \ /* Local memory, TODO */ \ - XCHAL_OPTION(XCHAL_ICACHE_WAYS, XTENSA_OPTION_ICACHE) | \ + XCHAL_OPTION(XCHAL_ICACHE_SIZE, XTENSA_OPTION_ICACHE) | \ XCHAL_OPTION(XCHAL_ICACHE_LINE_LOCKABLE, \ XTENSA_OPTION_ICACHE_INDEX_LOCK) | \ - XCHAL_OPTION(XCHAL_DCACHE_WAYS, XTENSA_OPTION_DCACHE) | \ + XCHAL_OPTION(XCHAL_DCACHE_SIZE, XTENSA_OPTION_DCACHE) | \ XCHAL_OPTION(XCHAL_DCACHE_LINE_LOCKABLE, \ XTENSA_OPTION_DCACHE_INDEX_LOCK) | \ XCHAL_OPTION(XCHAL_UNALIGNED_LOAD_HW, XTENSA_OPTION_HW_ALIGNMENT) | \ From 9e03ade4411c81a7f7d974dcedf0390835ce4096 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 11 Nov 2016 22:40:18 -0800 Subject: [PATCH 11/14] target/xtensa: implement MEMCTL SR MEMCTL SR controls zero overhead loop buffer and number of ways enabled in L1 caches. Signed-off-by: Max Filippov --- target/xtensa/cpu.c | 1 + target/xtensa/cpu.h | 19 +++++++++++++++++++ target/xtensa/helper.h | 1 + target/xtensa/op_helper.c | 24 ++++++++++++++++++++++++ target/xtensa/overlay_tool.h | 15 +++++++++++++++ target/xtensa/translate.c | 8 ++++++++ 6 files changed, 68 insertions(+) diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 1c18892fca..811d8780d6 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -66,6 +66,7 @@ static void xtensa_cpu_reset(CPUState *s) XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; env->sregs[VECBASE] = env->config->vecbase; env->sregs[IBREAKENABLE] = 0; + env->sregs[MEMCTL] = MEMCTL_IL0EN & env->config->memctl_mask; env->sregs[CACHEATTR] = 0x22222222; env->sregs[ATOMCTL] = xtensa_option_enabled(env->config, XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15; diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index a10f1efd8d..9a130bdabf 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -129,6 +129,7 @@ enum { ITLBCFG = 91, DTLBCFG = 92, IBREAKENABLE = 96, + MEMCTL = 97, CACHEATTR = 98, ATOMCTL = 99, IBREAKA = 128, @@ -189,6 +190,20 @@ enum { #define DBREAKC_SB_LB (DBREAKC_SB | DBREAKC_LB) #define DBREAKC_MASK 0x3f +#define MEMCTL_INIT 0x00800000 +#define MEMCTL_IUSEWAYS_SHIFT 18 +#define MEMCTL_IUSEWAYS_LEN 5 +#define MEMCTL_IUSEWAYS_MASK 0x007c0000 +#define MEMCTL_DALLOCWAYS_SHIFT 13 +#define MEMCTL_DALLOCWAYS_LEN 5 +#define MEMCTL_DALLOCWAYS_MASK 0x0003e000 +#define MEMCTL_DUSEWAYS_SHIFT 8 +#define MEMCTL_DUSEWAYS_LEN 5 +#define MEMCTL_DUSEWAYS_MASK 0x00001f00 +#define MEMCTL_ISNP 0x4 +#define MEMCTL_DSNP 0x2 +#define MEMCTL_IL0EN 0x1 + #define MAX_NAREG 64 #define MAX_NINTERRUPT 32 #define MAX_NLEVEL 6 @@ -332,6 +347,10 @@ struct XtensaConfig { unsigned nibreak; unsigned ndbreak; + unsigned icache_ways; + unsigned dcache_ways; + uint32_t memctl_mask; + uint32_t configid[2]; uint32_t clock_freq_khz; diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h index 427bdc7a3a..7e1474147b 100644 --- a/target/xtensa/helper.h +++ b/target/xtensa/helper.h @@ -23,6 +23,7 @@ DEF_HELPER_2(wsr_ccount, void, env, i32) DEF_HELPER_2(update_ccompare, void, env, i32) DEF_HELPER_1(check_interrupts, void, env) DEF_HELPER_3(check_atomctl, void, env, i32, i32) +DEF_HELPER_2(wsr_memctl, void, env, i32) DEF_HELPER_2(itlb_hit_test, void, env, i32) DEF_HELPER_2(wsr_rasid, void, env, i32) diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index 864a8f6eba..989578a811 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -506,6 +506,30 @@ void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr) } } +void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v) +{ + if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) { + if (extract32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN) > + env->config->icache_ways) { + deposit32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN, + env->config->icache_ways); + } + } + if (xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { + if (extract32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN) > + env->config->dcache_ways) { + deposit32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN, + env->config->dcache_ways); + } + if (extract32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN) > + env->config->dcache_ways) { + deposit32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN, + env->config->dcache_ways); + } + } + env->sregs[MEMCTL] = v & env->config->memctl_mask; +} + void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v) { XtensaCPU *cpu = xtensa_env_get_cpu(env); diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h index b73fd14dd1..bf36b5cdf6 100644 --- a/target/xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h @@ -59,6 +59,10 @@ #define XCHAL_HW_MIN_VERSION 0 #endif +#ifndef XCHAL_LOOP_BUFFER_SIZE +#define XCHAL_LOOP_BUFFER_SIZE 0 +#endif + #define XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0) #define XTENSA_OPTIONS ( \ @@ -343,6 +347,16 @@ .nibreak = XCHAL_NUM_IBREAK, \ .ndbreak = XCHAL_NUM_DBREAK +#define CACHE_SECTION \ + .icache_ways = XCHAL_ICACHE_WAYS, \ + .dcache_ways = XCHAL_DCACHE_WAYS, \ + .memctl_mask = \ + (XCHAL_ICACHE_SIZE ? MEMCTL_IUSEWAYS_MASK : 0) | \ + (XCHAL_DCACHE_SIZE ? \ + MEMCTL_DALLOCWAYS_MASK | MEMCTL_DUSEWAYS_MASK : 0) | \ + MEMCTL_ISNP | MEMCTL_DSNP | \ + (XCHAL_HAVE_LOOPS && XCHAL_LOOP_BUFFER_SIZE ? MEMCTL_IL0EN : 0) + #define CONFIG_SECTION \ .configid = { \ XCHAL_HW_CONFIGID0, \ @@ -357,6 +371,7 @@ INTERRUPTS_SECTION, \ TLB_SECTION, \ DEBUG_SECTION, \ + CACHE_SECTION, \ CONFIG_SECTION diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 7a198fa203..c541b59747 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -133,6 +133,7 @@ static const XtensaReg sregnames[256] = { [ITLBCFG] = XTENSA_REG("ITLBCFG", XTENSA_OPTION_MMU), [DTLBCFG] = XTENSA_REG("DTLBCFG", XTENSA_OPTION_MMU), [IBREAKENABLE] = XTENSA_REG("IBREAKENABLE", XTENSA_OPTION_DEBUG), + [MEMCTL] = XTENSA_REG_BITS("MEMCTL", XTENSA_OPTION_ALL), [CACHEATTR] = XTENSA_REG("CACHEATTR", XTENSA_OPTION_CACHEATTR), [ATOMCTL] = XTENSA_REG("ATOMCTL", XTENSA_OPTION_ATOMCTL), [IBREAKA] = XTENSA_REG("IBREAKA0", XTENSA_OPTION_DEBUG), @@ -637,6 +638,12 @@ static bool gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) return true; } +static bool gen_wsr_memctl(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + gen_helper_wsr_memctl(cpu_env, v); + return false; +} + static bool gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v) { tcg_gen_andi_i32(cpu_SR[sr], v, 0x3f); @@ -821,6 +828,7 @@ static bool gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) [ITLBCFG] = gen_wsr_tlbcfg, [DTLBCFG] = gen_wsr_tlbcfg, [IBREAKENABLE] = gen_wsr_ibreakenable, + [MEMCTL] = gen_wsr_memctl, [ATOMCTL] = gen_wsr_atomctl, [IBREAKA] = gen_wsr_ibreaka, [IBREAKA + 1] = gen_wsr_ibreaka, From 255d254382aab90a52654ddef4296c806d6d6aad Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 15 Jan 2017 12:54:52 -0800 Subject: [PATCH 12/14] target/xtensa: tests: add memctl test Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_sr.S | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tcg/xtensa/test_sr.S b/tests/tcg/xtensa/test_sr.S index 4fac46e80f..42e3e5e386 100644 --- a/tests/tcg/xtensa/test_sr.S +++ b/tests/tcg/xtensa/test_sr.S @@ -44,6 +44,7 @@ test_end test_sr acchi, 1 test_sr acclo, 1 +test_sr /*memctl*/97, 0 test_sr_mask /*atomctl*/99, 0, 0 test_sr_mask /*br*/4, 0, 0 test_sr_mask /*cacheattr*/98, 0, 0 From 8b912ff033cbc2e58476dfdc00fa2b8529c9eb96 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 5 Sep 2016 22:49:38 -0700 Subject: [PATCH 13/14] target/xtensa: tests: clean up interrupt tests Don't use hardcoded software interrupt masks, use XCHAL macros. Mask off timer interrupt bits that are not checked for. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_interrupt.S | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tests/tcg/xtensa/test_interrupt.S b/tests/tcg/xtensa/test_interrupt.S index 334ddab287..876683518e 100644 --- a/tests/tcg/xtensa/test_interrupt.S +++ b/tests/tcg/xtensa/test_interrupt.S @@ -1,5 +1,7 @@ #include "macros.inc" +#define LSBIT(v) ((v) ^ ((v) & ((v) - 1))) + test_suite interrupt .macro clear_interrupts @@ -46,14 +48,17 @@ test soft_disabled set_vector kernel, 1f clear_interrupts - movi a2, 0x80 + movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) wsr a2, intset esync rsr a3, interrupt + movi a4, ~XCHAL_INTTYPE_MASK_TIMER + and a3, a3, a4 assert eq, a2, a3 wsr a2, intclear esync rsr a3, interrupt + and a3, a3, a4 assert eqi, a3, 0 j 2f 1: @@ -65,10 +70,12 @@ test soft_intenable set_vector kernel, 1f clear_interrupts - movi a2, 0x80 + movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) wsr a2, intset esync rsr a3, interrupt + movi a4, ~XCHAL_INTTYPE_MASK_TIMER + and a3, a3, a4 assert eq, a2, a3 rsil a3, 0 wsr a2, intenable @@ -82,10 +89,12 @@ test soft_rsil set_vector kernel, 1f clear_interrupts - movi a2, 0x80 + movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) wsr a2, intset esync rsr a3, interrupt + movi a4, ~XCHAL_INTTYPE_MASK_TIMER + and a3, a3, a4 assert eq, a2, a3 wsr a2, intenable rsil a3, 0 @@ -99,10 +108,12 @@ test soft_waiti set_vector kernel, 1f clear_interrupts - movi a2, 0x80 + movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) wsr a2, intset esync rsr a3, interrupt + movi a4, ~XCHAL_INTTYPE_MASK_TIMER + and a3, a3, a4 assert eq, a2, a3 wsr a2, intenable waiti 0 @@ -116,10 +127,12 @@ test soft_user set_vector user, 2f clear_interrupts - movi a2, 0x80 + movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) wsr a2, intset esync rsr a3, interrupt + movi a4, ~XCHAL_INTTYPE_MASK_TIMER + and a3, a3, a4 assert eq, a2, a3 wsr a2, intenable @@ -139,7 +152,7 @@ test soft_priority set_vector level3, 2f clear_interrupts - movi a2, 0x880 + movi a2, XCHAL_INTTYPE_MASK_SOFTWARE wsr a2, intenable rsil a3, 0 esync @@ -161,7 +174,7 @@ test eps_epc_rfi clear_interrupts reset_ps - movi a2, 0x880 + movi a2, XCHAL_INTTYPE_MASK_SOFTWARE wsr a2, intenable rsil a3, 0 rsr a3, ps From 3a3c9dc4ca2eaa612cbd5d4c85d674b15eadfb02 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sat, 26 Nov 2011 15:48:41 +0400 Subject: [PATCH 14/14] target-xtensa: implement RER/WER instructions RER and WER are privileged instructions for accessing external registers. External register address space is local to processor core. There's no alignment requirements, addressable units are 32-bit wide registers. Signed-off-by: Max Filippov --- target/xtensa/cpu.c | 6 ++++++ target/xtensa/cpu.h | 7 +++++++ target/xtensa/helper.h | 3 +++ target/xtensa/op_helper.c | 12 ++++++++++++ target/xtensa/overlay_tool.h | 7 ++++++- target/xtensa/translate.c | 12 ++++++++++-- 6 files changed, 44 insertions(+), 3 deletions(-) diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 811d8780d6..cd7f95823f 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -127,6 +127,12 @@ static void xtensa_cpu_initfn(Object *obj) cs->env_ptr = env; env->config = xcc->config; + env->address_space_er = g_malloc(sizeof(*env->address_space_er)); + env->system_er = g_malloc(sizeof(*env->system_er)); + memory_region_init_io(env->system_er, NULL, NULL, env, "er", + UINT64_C(0x100000000)); + address_space_init(env->address_space_er, env->system_er, "ER"); + if (tcg_enabled() && !tcg_inited) { tcg_inited = true; xtensa_translate_init(); diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 9a130bdabf..7e7131a596 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -103,6 +103,7 @@ enum { XTENSA_OPTION_PROCESSOR_ID, XTENSA_OPTION_DEBUG, XTENSA_OPTION_TRACE_PORT, + XTENSA_OPTION_EXTERN_REGS, }; enum { @@ -393,6 +394,8 @@ typedef struct CPUXtensaState { xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE]; unsigned autorefill_idx; bool runstall; + AddressSpace *address_space_er; + MemoryRegion *system_er; int pending_irq_level; /* level of last raised IRQ */ void **irq_inputs; XtensaCcompareTimer ccompare[MAX_NCCOMPARE]; @@ -488,6 +491,10 @@ int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, void reset_mmu(CPUXtensaState *env); void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env); void debug_exception_env(CPUXtensaState *new_env, uint32_t cause); +static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env) +{ + return env->system_er; +} static inline void xtensa_select_static_vectors(CPUXtensaState *env, unsigned n) diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h index 7e1474147b..db3c9c5f21 100644 --- a/target/xtensa/helper.h +++ b/target/xtensa/helper.h @@ -58,3 +58,6 @@ DEF_HELPER_4(olt_s, void, env, i32, f32, f32) DEF_HELPER_4(ult_s, void, env, i32, f32, f32) DEF_HELPER_4(ole_s, void, env, i32, f32, f32) DEF_HELPER_4(ule_s, void, env, i32, f32, f32) + +DEF_HELPER_2(rer, i32, env, i32) +DEF_HELPER_3(wer, void, env, i32, i32) diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index 989578a811..b456c2ec3f 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -1027,3 +1027,15 @@ void HELPER(ule_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) int v = float32_compare_quiet(a, b, &env->fp_status); set_br(env, v != float_relation_greater, br); } + +uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr) +{ + return address_space_ldl(env->address_space_er, addr, + (MemTxAttrs){0}, NULL); +} + +void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr) +{ + address_space_stl(env->address_space_er, addr, data, + (MemTxAttrs){0}, NULL); +} diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h index bf36b5cdf6..38e9be9ff5 100644 --- a/target/xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h @@ -63,6 +63,10 @@ #define XCHAL_LOOP_BUFFER_SIZE 0 #endif +#ifndef XCHAL_HAVE_EXTERN_REGS +#define XCHAL_HAVE_EXTERN_REGS 0 +#endif + #define XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0) #define XTENSA_OPTIONS ( \ @@ -115,7 +119,8 @@ XCHAL_OPTION(XCHAL_HAVE_DEBUG, XTENSA_OPTION_DEBUG) |\ XCHAL_OPTION(XCHAL_NUM_MISC_REGS > 0, XTENSA_OPTION_MISC_SR) | \ XCHAL_OPTION(XCHAL_HAVE_THREADPTR, XTENSA_OPTION_THREAD_POINTER) | \ - XCHAL_OPTION(XCHAL_HAVE_PRID, XTENSA_OPTION_PROCESSOR_ID)) + XCHAL_OPTION(XCHAL_HAVE_PRID, XTENSA_OPTION_PROCESSOR_ID) | \ + XCHAL_OPTION(XCHAL_HAVE_EXTERN_REGS, XTENSA_OPTION_EXTERN_REGS)) #ifndef XCHAL_WINDOW_OF4_VECOFS #define XCHAL_WINDOW_OF4_VECOFS 0x00000000 diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index c541b59747..c0408a01c7 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1420,11 +1420,19 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) break; case 6: /*RER*/ - TBD(); + HAS_OPTION(XTENSA_OPTION_EXTERN_REGS); + if (gen_check_privilege(dc) && + gen_window_check2(dc, RRR_S, RRR_T)) { + gen_helper_rer(cpu_R[RRR_T], cpu_env, cpu_R[RRR_S]); + } break; case 7: /*WER*/ - TBD(); + HAS_OPTION(XTENSA_OPTION_EXTERN_REGS); + if (gen_check_privilege(dc) && + gen_window_check2(dc, RRR_S, RRR_T)) { + gen_helper_wer(cpu_env, cpu_R[RRR_T], cpu_R[RRR_S]); + } break; case 8: /*ROTWw*/