diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-01-25 16:36:57 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-01-25 16:36:57 +0000 |
commit | e32c41e4f65f4d16508fe759a800538a73608839 (patch) | |
tree | 288ad9c192a4d6b58d3490eb088450de7153922c /target | |
parent | ae5045ae5b2bbd8ce1335d1b05f9ecacca83a6cf (diff) | |
parent | 3a3c9dc4ca2eaa612cbd5d4c85d674b15eadfb02 (diff) | |
download | qemu-e32c41e4f65f4d16508fe759a800538a73608839.zip |
Merge remote-tracking branch 'remotes/xtensa/tags/20170124-xtensa' into staging
target/xtensa updates:
- refactor CCOUNT/CCOMPARE (use QEMU timers instead of instruction counting);
- support icount; run target/xtensa TCG tests with icount;
- implement SMP prerequisites: static vector selection, RUNSTALL and RER/WER.
# gpg: Signature made Wed 25 Jan 2017 00:27:51 GMT
# gpg: using RSA key 0x51F9CC91F83FA044
# gpg: Good signature from "Max Filippov <max.filippov@cogentembedded.com>"
# gpg: aka "Max Filippov <jcmvbkbc@gmail.com>"
# Primary key fingerprint: 2B67 854B 98E5 327D CDEB 17D8 51F9 CC91 F83F A044
* remotes/xtensa/tags/20170124-xtensa:
target-xtensa: implement RER/WER instructions
target/xtensa: tests: clean up interrupt tests
target/xtensa: tests: add memctl test
target/xtensa: implement MEMCTL SR
target/xtensa: fix ICACHE/DCACHE options detection
target/xtensa: tests: add ccount write tests
target/xtensa: tests: replace hardcoded interrupt masks
target/xtensa: tests: fix timer tests
target/xtensa: tests: run tests with icount
target/xtensa: don't continue translation after exception
target/xtensa: support icount
target/xtensa: refactor CCOUNT/CCOMPARE
target/xtensa: implement RUNSTALL
target/xtensa: add static vectors selection
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/xtensa/cpu.c | 12 | ||||
-rw-r--r-- | target/xtensa/cpu.h | 60 | ||||
-rw-r--r-- | target/xtensa/helper.c | 13 | ||||
-rw-r--r-- | target/xtensa/helper.h | 9 | ||||
-rw-r--r-- | target/xtensa/op_helper.c | 73 | ||||
-rw-r--r-- | target/xtensa/overlay_tool.h | 37 | ||||
-rw-r--r-- | target/xtensa/translate.c | 245 |
7 files changed, 348 insertions, 101 deletions
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index e8e9f9175b..cd7f95823f 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() */ @@ -60,12 +60,13 @@ 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; 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; @@ -74,6 +75,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) @@ -125,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 7fe82a37af..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 { @@ -129,6 +130,7 @@ enum { ITLBCFG = 91, DTLBCFG = 92, IBREAKENABLE = 96, + MEMCTL = 97, CACHEATTR = 98, ATOMCTL = 99, IBREAKA = 128, @@ -189,6 +191,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 @@ -209,7 +225,8 @@ enum { enum { /* Static vectors */ - EXC_RESET, + EXC_RESET0, + EXC_RESET1, EXC_MEMORY_ERROR, /* Dynamic vectors */ @@ -268,6 +285,8 @@ typedef enum { INTTYPE_MAX } interrupt_type; +struct CPUXtensaState; + typedef struct xtensa_tlb_entry { uint32_t vaddr; uint32_t paddr; @@ -297,6 +316,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; @@ -324,6 +348,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; @@ -365,14 +393,19 @@ 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; + AddressSpace *address_space_er; + MemoryRegion *system_er; 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; + int yield_needed; + unsigned static_vectors; /* Watchpoints for DBREAK registers */ struct CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK]; @@ -437,9 +470,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); @@ -460,7 +491,18 @@ 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) +{ + 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) @@ -539,6 +581,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) @@ -580,6 +623,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/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); + } +} diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h index 0c8adae9d4..cc751c98fb 100644 --- a/target/xtensa/helper.h +++ b/target/xtensa/helper.h @@ -16,10 +16,12 @@ 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) +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) @@ -54,3 +56,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 dc0dd351bb..af2723445d 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; } @@ -385,22 +388,40 @@ 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) +{ + 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(wsr_ccount)(CPUXtensaState *env, uint32_t v) { - xtensa_timer_irq(env, id, active); + 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(advance_ccount)(CPUXtensaState *env, uint32_t d) +void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) { - xtensa_advance_ccount(env, d); + 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); + env->yield_needed = 1; } void HELPER(check_interrupts)(CPUXtensaState *env) @@ -472,6 +493,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); @@ -969,3 +1014,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 e8a7fda3d8..38e9be9ff5 100644 --- a/target/xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h @@ -47,10 +47,26 @@ #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 +#ifndef XCHAL_LOOP_BUFFER_SIZE +#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 ( \ @@ -84,10 +100,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) | \ @@ -103,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 @@ -133,7 +150,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, \ @@ -334,6 +352,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, \ @@ -348,6 +376,7 @@ INTERRUPTS_SECTION, \ TLB_SECTION, \ DEBUG_SECTION, \ + CACHE_SECTION, \ CONFIG_SECTION diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 5a93705fac..263002486c 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; @@ -134,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), @@ -314,20 +314,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 +325,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 +339,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 +348,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 +380,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 +450,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 +472,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); @@ -528,47 +511,60 @@ 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) { - gen_advance_ccount(dc); + 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, [PTEVADDR] = gen_rsr_ptevaddr, }; 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) { @@ -576,68 +572,85 @@ 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 bool gen_wsr_memctl(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + gen_helper_wsr_memctl(cpu_env, v); + return false; } -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; @@ -646,10 +659,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; @@ -658,9 +673,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; @@ -669,24 +685,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(); @@ -696,17 +726,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; @@ -715,42 +748,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 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]; - 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); + 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, @@ -765,6 +828,7 @@ static void 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, @@ -777,6 +841,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, @@ -785,9 +850,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; } } @@ -829,10 +895,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); - gen_advance_ccount(dc); + + 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) @@ -841,7 +914,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 +1109,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 +1157,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); @@ -1134,7 +1204,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; @@ -1169,7 +1239,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); @@ -1188,7 +1258,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 { @@ -1246,7 +1316,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; @@ -1350,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*/ @@ -1534,11 +1612,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; @@ -1759,7 +1841,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; @@ -2517,7 +2601,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 +2830,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 +3048,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 +3144,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) >> @@ -3079,17 +3159,26 @@ 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); + tcg_gen_insn_start(dc.pc); + ++insn_count; gen_exception(&dc, EXCP_DEBUG); + dc.is_jmp = DISAS_UPDATE; + goto done; } do { 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); @@ -3136,7 +3225,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) { |