diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index 2bed64f15b1901276b0e96b7a638d9d445d748d7..0e812d7f061c3639283eacd5b3c2ea055031c2c0 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.c b/target/xtensa/cpu.c index e8e9f9175b80bedf922cfe49aa133817ec0b2837..cd7f95823f769624571eaabc1cb78c1f60f9bd5f 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 7fe82a37af42eb9077b56d1542298472c397ec25..7e7131a596d4092c0af93e306b9641a2fe018fee 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 768b32c4172400ccdf61180e90e0139b6e8d4373..c67d715c4b9c692ea2f4332830871b9b5f425b80 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 0c8adae9d4603d4e19cff8a0dfa255886265e261..cc751c98fbd090460ccbeda4d64b1efb78c9595d 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 dc0dd351bbec6fb5e413ae0964c297c20d431193..af2723445d4bc317a755b1b333f28535e2502fa7 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 e8a7fda3d82d6fd1b650e0696b4b5753a1ece440..38e9be9ff56357c15621be455bc412797689bf0d 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 5a93705face6d3a7e1994f6088614575d6762a39..263002486c5d9aabc4d9626f00e43dddb15b0107 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) { diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile index 7f9f2d96c3708e8b754b8be238f62df8eabab503..2882c431e4a9814704c97da46b0db536cfaf913f 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 diff --git a/tests/tcg/xtensa/test_interrupt.S b/tests/tcg/xtensa/test_interrupt.S index 334ddab28718f3afaf963aa34cc6c7d9da0a7ddf..876683518ee55b9f1aabd6a5f9edcf69cdf45181 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 diff --git a/tests/tcg/xtensa/test_sr.S b/tests/tcg/xtensa/test_sr.S index 4fac46e80f87069d216236ab5f1d8fac76e544f7..42e3e5e386d4e70d085a3a51dbe3751d819572b3 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 diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S index f8c6f7423a965b843f1803fd04e0ed7865fe1d1d..6cda71adbb0697eaccab000b73ca2c24b7420031 100644 --- a/tests/tcg/xtensa/test_timer.S +++ b/tests/tcg/xtensa/test_timer.S @@ -1,12 +1,56 @@ #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 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 @@ -18,18 +62,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,15 +86,14 @@ 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 assert eqi, a2, 0 - movi a2, 0x40 + movi a2, 1 << XCHAL_TIMER0_INTERRUPT wsr a2, intenable rsil a2, 0 loop a3, 1f @@ -72,14 +115,13 @@ 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 assert eqi, a2, 0 - movi a2, 0x400 + movi a2, 1 << XCHAL_TIMER1_INTERRUPT wsr a2, intenable rsil a2, 2 loop a3, 1f @@ -99,14 +141,13 @@ 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 assert eqi, a2, 0 - movi a2, 0x2000 + movi a2, 1 << XCHAL_TIMER2_INTERRUPT wsr a2, intenable rsil a2, 4 loop a3, 1f @@ -125,17 +166,16 @@ 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 assert eqi, a2, 0 - movi a2, 0x40 + movi a2, 1 << XCHAL_TIMER0_INTERRUPT wsr a2, intenable rsil a2, 0 loop a3, 1f @@ -156,17 +196,16 @@ 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 assert eqi, a2, 0 - movi a2, 0x40 + movi a2, 1 << XCHAL_TIMER0_INTERRUPT wsr a2, intenable waiti 0 test_fail