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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJYh/EHAAoJEFH5zJH4P6BEpbMP/ilUpDqeSJNP7k1oObABd0cK
 TFOQ3eXtjvmsl9YT17VU8bQpGHZ9R9qP37TcxPBfWAMs/IMtxCCEAclZwEKpGbrB
 L+GypHH2uXvsf4kH2SvElLTULvhOLlxEkfROkxJ++Pverhk/D8JAVxWNb1C4AU/z
 YIIyH8G2Jj2p4ZYvD9OH0Jmv4FfPWljb1unJzu8Y6XynY/Zh7B4xEsvx44E09/l5
 m450tL+Bs/3faoQgznRUMNR3pCUKYBpQEV1pr0Rbcrs/mp58CH71HyAhr0fH/5OT
 yhD7CGj7e6NqhV+vJvnoU6Z5wTRVUD1Reeb8EIzvqLz+4FJTV9L6BWHEIjvZy4TK
 EIakPNl9jbBRxzAwx8PGXm3xxyTznOs/c+K0u2zcFHPnUxnfTmk+MtkfeTjNvx3x
 jiaSXhkaMguf1dOzhiJbjS7s6Kl6NIu7Pta28ItovOOR4AgHbHz6CVHg5Li1bCD9
 dyjwnwflb8dWXQRojg6cA1qQBiq323+2lKz0IaUUtErnbGNst5sRIlAjxN9wjn0H
 giHPspisKV431vN4ZQnEAmOikNfyGd53b/r+a2na0pP1MaYJ0of5Rl0R6YwNfrUa
 MWp0AVF/+qG9ZBpuH8m+1oa3x1Fnc3+2fvWDafcS75lBRa7eyGuHabpO450bOpHB
 ftrtVBYDRt3+HAoAYKHT
 =WOcm
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2017-01-25 16:36:57 +00:00
commit e32c41e4f6
12 changed files with 456 additions and 203 deletions

View File

@ -31,22 +31,6 @@
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/timer.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) void check_interrupts(CPUXtensaState *env)
{ {
CPUState *cs = CPU(xtensa_env_get_cpu(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]; uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
int level; 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) { for (level = env->config->nlevel; level > minlevel; --level) {
if (env->config->level_mask[level] & int_set_enabled) { if (env->config->level_mask[level] & int_set_enabled) {
env->pending_irq_level = level; 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); 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) static void xtensa_ccompare_cb(void *opaque)
{ {
XtensaCPU *cpu = opaque; XtensaCcompareTimer *ccompare = opaque;
CPUXtensaState *env = &cpu->env; CPUXtensaState *env = ccompare->env;
CPUState *cs = CPU(cpu); unsigned i = ccompare - env->ccompare;
if (cs->halted) { xtensa_timer_irq(env, i, 1);
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);
}
}
} }
void xtensa_irq_init(CPUXtensaState *env) void xtensa_irq_init(CPUXtensaState *env)
{ {
XtensaCPU *cpu = xtensa_env_get_cpu(env);
env->irq_inputs = (void **)qemu_allocate_irqs( env->irq_inputs = (void **)qemu_allocate_irqs(
xtensa_set_irq, env, env->config->ninterrupt); xtensa_set_irq, env, env->config->ninterrupt);
if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) && if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
env->config->nccompare > 0) { unsigned i;
env->ccompare_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, &xtensa_ccompare_cb, cpu); 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);
}
} }
} }

View File

@ -47,7 +47,7 @@ static bool xtensa_cpu_has_work(CPUState *cs)
{ {
XtensaCPU *cpu = XTENSA_CPU(cs); XtensaCPU *cpu = XTENSA_CPU(cs);
return cpu->env.pending_irq_level; return !cpu->env.runstall && cpu->env.pending_irq_level;
} }
/* CPUClass::reset() */ /* CPUClass::reset() */
@ -60,12 +60,13 @@ static void xtensa_cpu_reset(CPUState *s)
xcc->parent_reset(s); xcc->parent_reset(s);
env->exception_taken = 0; 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[LITBASE] &= ~1;
env->sregs[PS] = xtensa_option_enabled(env->config, env->sregs[PS] = xtensa_option_enabled(env->config,
XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
env->sregs[VECBASE] = env->config->vecbase; env->sregs[VECBASE] = env->config->vecbase;
env->sregs[IBREAKENABLE] = 0; env->sregs[IBREAKENABLE] = 0;
env->sregs[MEMCTL] = MEMCTL_IL0EN & env->config->memctl_mask;
env->sregs[CACHEATTR] = 0x22222222; env->sregs[CACHEATTR] = 0x22222222;
env->sregs[ATOMCTL] = xtensa_option_enabled(env->config, env->sregs[ATOMCTL] = xtensa_option_enabled(env->config,
XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15; XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15;
@ -74,6 +75,7 @@ static void xtensa_cpu_reset(CPUState *s)
env->pending_irq_level = 0; env->pending_irq_level = 0;
reset_mmu(env); reset_mmu(env);
s->halted = env->runstall;
} }
static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) 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; cs->env_ptr = env;
env->config = xcc->config; 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) { if (tcg_enabled() && !tcg_inited) {
tcg_inited = true; tcg_inited = true;
xtensa_translate_init(); xtensa_translate_init();

View File

@ -103,6 +103,7 @@ enum {
XTENSA_OPTION_PROCESSOR_ID, XTENSA_OPTION_PROCESSOR_ID,
XTENSA_OPTION_DEBUG, XTENSA_OPTION_DEBUG,
XTENSA_OPTION_TRACE_PORT, XTENSA_OPTION_TRACE_PORT,
XTENSA_OPTION_EXTERN_REGS,
}; };
enum { enum {
@ -129,6 +130,7 @@ enum {
ITLBCFG = 91, ITLBCFG = 91,
DTLBCFG = 92, DTLBCFG = 92,
IBREAKENABLE = 96, IBREAKENABLE = 96,
MEMCTL = 97,
CACHEATTR = 98, CACHEATTR = 98,
ATOMCTL = 99, ATOMCTL = 99,
IBREAKA = 128, IBREAKA = 128,
@ -189,6 +191,20 @@ enum {
#define DBREAKC_SB_LB (DBREAKC_SB | DBREAKC_LB) #define DBREAKC_SB_LB (DBREAKC_SB | DBREAKC_LB)
#define DBREAKC_MASK 0x3f #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_NAREG 64
#define MAX_NINTERRUPT 32 #define MAX_NINTERRUPT 32
#define MAX_NLEVEL 6 #define MAX_NLEVEL 6
@ -209,7 +225,8 @@ enum {
enum { enum {
/* Static vectors */ /* Static vectors */
EXC_RESET, EXC_RESET0,
EXC_RESET1,
EXC_MEMORY_ERROR, EXC_MEMORY_ERROR,
/* Dynamic vectors */ /* Dynamic vectors */
@ -268,6 +285,8 @@ typedef enum {
INTTYPE_MAX INTTYPE_MAX
} interrupt_type; } interrupt_type;
struct CPUXtensaState;
typedef struct xtensa_tlb_entry { typedef struct xtensa_tlb_entry {
uint32_t vaddr; uint32_t vaddr;
uint32_t paddr; uint32_t paddr;
@ -297,6 +316,11 @@ typedef struct XtensaGdbRegmap {
XtensaGdbReg reg[1 + 16 + 64 + 256 + 256]; XtensaGdbReg reg[1 + 16 + 64 + 256 + 256];
} XtensaGdbRegmap; } XtensaGdbRegmap;
typedef struct XtensaCcompareTimer {
struct CPUXtensaState *env;
QEMUTimer *timer;
} XtensaCcompareTimer;
struct XtensaConfig { struct XtensaConfig {
const char *name; const char *name;
uint64_t options; uint64_t options;
@ -324,6 +348,10 @@ struct XtensaConfig {
unsigned nibreak; unsigned nibreak;
unsigned ndbreak; unsigned ndbreak;
unsigned icache_ways;
unsigned dcache_ways;
uint32_t memctl_mask;
uint32_t configid[2]; uint32_t configid[2];
uint32_t clock_freq_khz; uint32_t clock_freq_khz;
@ -365,14 +393,19 @@ typedef struct CPUXtensaState {
xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE]; xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE]; xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE];
unsigned autorefill_idx; unsigned autorefill_idx;
bool runstall;
AddressSpace *address_space_er;
MemoryRegion *system_er;
int pending_irq_level; /* level of last raised IRQ */ int pending_irq_level; /* level of last raised IRQ */
void **irq_inputs; void **irq_inputs;
QEMUTimer *ccompare_timer; XtensaCcompareTimer ccompare[MAX_NCCOMPARE];
uint32_t wake_ccount; uint64_t time_base;
int64_t halt_clock; uint64_t ccount_time;
uint32_t ccount_base;
int exception_taken; int exception_taken;
int yield_needed;
unsigned static_vectors;
/* Watchpoints for DBREAK registers */ /* Watchpoints for DBREAK registers */
struct CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK]; struct CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK];
@ -437,9 +470,7 @@ void xtensa_register_core(XtensaConfigList *node);
void check_interrupts(CPUXtensaState *s); void check_interrupts(CPUXtensaState *s);
void xtensa_irq_init(CPUXtensaState *env); void xtensa_irq_init(CPUXtensaState *env);
void *xtensa_get_extint(CPUXtensaState *env, unsigned extint); 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_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); int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf); void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
void xtensa_sync_window_from_phys(CPUXtensaState *env); 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 reset_mmu(CPUXtensaState *env);
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env); void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env);
void debug_exception_env(CPUXtensaState *new_env, uint32_t cause); 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_BIT(opt) (((uint64_t)1) << (opt))
#define XTENSA_OPTION_ALL (~(uint64_t)0) #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_EXCEPTION 0x4000
#define XTENSA_TBFLAG_WINDOW_MASK 0x18000 #define XTENSA_TBFLAG_WINDOW_MASK 0x18000
#define XTENSA_TBFLAG_WINDOW_SHIFT 15 #define XTENSA_TBFLAG_WINDOW_SHIFT 15
#define XTENSA_TBFLAG_YIELD 0x20000
static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags) 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 { } else {
*flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT; *flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT;
} }
if (env->yield_needed) {
*flags |= XTENSA_TBFLAG_YIELD;
}
} }
#include "exec/cpu-all.h" #include "exec/cpu-all.h"

View File

@ -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"); 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);
}
}

View File

@ -16,10 +16,12 @@ DEF_HELPER_1(simcall, void, env)
DEF_HELPER_1(dump_state, void, env) DEF_HELPER_1(dump_state, void, env)
DEF_HELPER_3(waiti, void, env, i32, i32) DEF_HELPER_3(waiti, void, env, i32, i32)
DEF_HELPER_3(timer_irq, void, env, i32, i32) DEF_HELPER_1(update_ccount, void, env)
DEF_HELPER_2(advance_ccount, void, env, i32) 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_1(check_interrupts, void, env)
DEF_HELPER_3(check_atomctl, void, env, i32, i32) 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(itlb_hit_test, void, env, i32)
DEF_HELPER_2(wsr_rasid, 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(ult_s, void, env, i32, f32, f32)
DEF_HELPER_4(ole_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_4(ule_s, void, env, i32, f32, f32)
DEF_HELPER_2(rer, i32, env, i32)
DEF_HELPER_3(wer, void, env, i32, i32)

View File

@ -105,6 +105,9 @@ void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
CPUState *cs = CPU(xtensa_env_get_cpu(env)); CPUState *cs = CPU(xtensa_env_get_cpu(env));
cs->exception_index = excp; cs->exception_index = excp;
if (excp == EXCP_YIELD) {
env->yield_needed = 0;
}
if (excp == EXCP_DEBUG) { if (excp == EXCP_DEBUG) {
env->exception_taken = 0; 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)); cpu = CPU(xtensa_env_get_cpu(env));
env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
cpu->halted = 1; cpu->halted = 1;
if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
xtensa_rearm_ccompare_timer(env);
}
HELPER(exception)(env, EXCP_HLT); 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);
env->yield_needed = 1;
} }
void HELPER(check_interrupts)(CPUXtensaState *env) 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) void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v)
{ {
XtensaCPU *cpu = xtensa_env_get_cpu(env); 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); int v = float32_compare_quiet(a, b, &env->fp_status);
set_br(env, v != float_relation_greater, br); 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);
}

View File

@ -47,10 +47,26 @@
#define XCHAL_VECBASE_RESET_VADDR 0 #define XCHAL_VECBASE_RESET_VADDR 0
#endif #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 #ifndef XCHAL_HW_MIN_VERSION
#define XCHAL_HW_MIN_VERSION 0 #define XCHAL_HW_MIN_VERSION 0
#endif #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 XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0)
#define XTENSA_OPTIONS ( \ #define XTENSA_OPTIONS ( \
@ -84,10 +100,10 @@
XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT) | \ XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT) | \
XCHAL_OPTION(XCHAL_HAVE_CCOUNT, XTENSA_OPTION_TIMER_INTERRUPT) | \ XCHAL_OPTION(XCHAL_HAVE_CCOUNT, XTENSA_OPTION_TIMER_INTERRUPT) | \
/* Local memory, TODO */ \ /* 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, \ XCHAL_OPTION(XCHAL_ICACHE_LINE_LOCKABLE, \
XTENSA_OPTION_ICACHE_INDEX_LOCK) | \ 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, \ XCHAL_OPTION(XCHAL_DCACHE_LINE_LOCKABLE, \
XTENSA_OPTION_DCACHE_INDEX_LOCK) | \ XTENSA_OPTION_DCACHE_INDEX_LOCK) | \
XCHAL_OPTION(XCHAL_UNALIGNED_LOAD_HW, XTENSA_OPTION_HW_ALIGNMENT) | \ 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_HAVE_DEBUG, XTENSA_OPTION_DEBUG) |\
XCHAL_OPTION(XCHAL_NUM_MISC_REGS > 0, XTENSA_OPTION_MISC_SR) | \ XCHAL_OPTION(XCHAL_NUM_MISC_REGS > 0, XTENSA_OPTION_MISC_SR) | \
XCHAL_OPTION(XCHAL_HAVE_THREADPTR, XTENSA_OPTION_THREAD_POINTER) | \ 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 #ifndef XCHAL_WINDOW_OF4_VECOFS
#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 #define XCHAL_WINDOW_OF4_VECOFS 0x00000000
@ -133,7 +150,8 @@
#endif #endif
#define EXCEPTION_VECTORS { \ #define EXCEPTION_VECTORS { \
[EXC_RESET] = XCHAL_RESET_VECTOR_VADDR, \ [EXC_RESET0] = XCHAL_RESET_VECTOR0_VADDR, \
[EXC_RESET1] = XCHAL_RESET_VECTOR1_VADDR, \
WINDOW_VECTORS \ WINDOW_VECTORS \
[EXC_KERNEL] = XCHAL_KERNEL_VECTOR_VADDR, \ [EXC_KERNEL] = XCHAL_KERNEL_VECTOR_VADDR, \
[EXC_USER] = XCHAL_USER_VECTOR_VADDR, \ [EXC_USER] = XCHAL_USER_VECTOR_VADDR, \
@ -334,6 +352,16 @@
.nibreak = XCHAL_NUM_IBREAK, \ .nibreak = XCHAL_NUM_IBREAK, \
.ndbreak = XCHAL_NUM_DBREAK .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 \ #define CONFIG_SECTION \
.configid = { \ .configid = { \
XCHAL_HW_CONFIGID0, \ XCHAL_HW_CONFIGID0, \
@ -348,6 +376,7 @@
INTERRUPTS_SECTION, \ INTERRUPTS_SECTION, \
TLB_SECTION, \ TLB_SECTION, \
DEBUG_SECTION, \ DEBUG_SECTION, \
CACHE_SECTION, \
CONFIG_SECTION CONFIG_SECTION

View File

@ -64,7 +64,6 @@ typedef struct DisasContext {
bool sar_m32_allocated; bool sar_m32_allocated;
TCGv_i32 sar_m32; TCGv_i32 sar_m32;
uint32_t ccount_delta;
unsigned window; unsigned window;
bool debug; bool debug;
@ -134,6 +133,7 @@ static const XtensaReg sregnames[256] = {
[ITLBCFG] = XTENSA_REG("ITLBCFG", XTENSA_OPTION_MMU), [ITLBCFG] = XTENSA_REG("ITLBCFG", XTENSA_OPTION_MMU),
[DTLBCFG] = XTENSA_REG("DTLBCFG", XTENSA_OPTION_MMU), [DTLBCFG] = XTENSA_REG("DTLBCFG", XTENSA_OPTION_MMU),
[IBREAKENABLE] = XTENSA_REG("IBREAKENABLE", XTENSA_OPTION_DEBUG), [IBREAKENABLE] = XTENSA_REG("IBREAKENABLE", XTENSA_OPTION_DEBUG),
[MEMCTL] = XTENSA_REG_BITS("MEMCTL", XTENSA_OPTION_ALL),
[CACHEATTR] = XTENSA_REG("CACHEATTR", XTENSA_OPTION_CACHEATTR), [CACHEATTR] = XTENSA_REG("CACHEATTR", XTENSA_OPTION_CACHEATTR),
[ATOMCTL] = XTENSA_REG("ATOMCTL", XTENSA_OPTION_ATOMCTL), [ATOMCTL] = XTENSA_REG("ATOMCTL", XTENSA_OPTION_ATOMCTL),
[IBREAKA] = XTENSA_REG("IBREAKA0", XTENSA_OPTION_DEBUG), [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); 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) static void gen_exception(DisasContext *dc, int excp)
{ {
TCGv_i32 tmp = tcg_const_i32(excp); TCGv_i32 tmp = tcg_const_i32(excp);
gen_advance_ccount(dc);
gen_helper_exception(cpu_env, tmp); gen_helper_exception(cpu_env, tmp);
tcg_temp_free(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 tpc = tcg_const_i32(dc->pc);
TCGv_i32 tcause = tcg_const_i32(cause); TCGv_i32 tcause = tcg_const_i32(cause);
gen_advance_ccount(dc);
gen_helper_exception_cause(cpu_env, tpc, tcause); gen_helper_exception_cause(cpu_env, tpc, tcause);
tcg_temp_free(tpc); tcg_temp_free(tpc);
tcg_temp_free(tcause); 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 tpc = tcg_const_i32(dc->pc);
TCGv_i32 tcause = tcg_const_i32(cause); TCGv_i32 tcause = tcg_const_i32(cause);
gen_advance_ccount(dc);
gen_helper_exception_cause_vaddr(cpu_env, tpc, tcause, vaddr); gen_helper_exception_cause_vaddr(cpu_env, tpc, tcause, vaddr);
tcg_temp_free(tpc); tcg_temp_free(tpc);
tcg_temp_free(tcause); 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 tpc = tcg_const_i32(dc->pc);
TCGv_i32 tcause = tcg_const_i32(cause); TCGv_i32 tcause = tcg_const_i32(cause);
gen_advance_ccount(dc);
gen_helper_debug_exception(cpu_env, tpc, tcause); gen_helper_debug_exception(cpu_env, tpc, tcause);
tcg_temp_free(tpc); tcg_temp_free(tpc);
tcg_temp_free(tcause); 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) static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
{ {
tcg_gen_mov_i32(cpu_pc, dest); tcg_gen_mov_i32(cpu_pc, dest);
gen_advance_ccount(dc);
if (dc->icount) { if (dc->icount) {
tcg_gen_mov_i32(cpu_SR[ICOUNT], dc->next_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) { dc->next_pc == dc->lend) {
TCGLabel *label = gen_new_label(); TCGLabel *label = gen_new_label();
gen_advance_ccount(dc);
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label); tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label);
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1); tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1);
gen_jumpi(dc, dc->lbeg, slot); gen_jumpi(dc, dc->lbeg, slot);
@ -488,7 +472,6 @@ static void gen_brcond(DisasContext *dc, TCGCond cond,
{ {
TCGLabel *label = gen_new_label(); TCGLabel *label = gen_new_label();
gen_advance_ccount(dc);
tcg_gen_brcond_i32(cond, t0, t1, label); tcg_gen_brcond_i32(cond, t0, t1, label);
gen_jumpi_check_loop_end(dc, 0); gen_jumpi_check_loop_end(dc, 0);
gen_set_label(label); gen_set_label(label);
@ -528,47 +511,60 @@ static bool gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access)
return true; 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]); 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_shri_i32(d, cpu_SR[EXCVADDR], 10);
tcg_gen_or_i32(d, d, cpu_SR[sr]); tcg_gen_or_i32(d, d, cpu_SR[sr]);
tcg_gen_andi_i32(d, d, 0xfffffffc); 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) = { TCGv_i32 d, uint32_t sr) = {
[CCOUNT] = gen_rsr_ccount, [CCOUNT] = gen_rsr_ccount,
[INTSET] = gen_rsr_ccount,
[PTEVADDR] = gen_rsr_ptevaddr, [PTEVADDR] = gen_rsr_ptevaddr,
}; };
if (rsr_handler[sr]) { if (rsr_handler[sr]) {
rsr_handler[sr](dc, d, sr); return rsr_handler[sr](dc, d, sr);
} else { } else {
tcg_gen_mov_i32(d, cpu_SR[sr]); 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_helper_wsr_lbeg(cpu_env, s);
gen_jumpi_check_loop_end(dc, 0); 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_helper_wsr_lend(cpu_env, s);
gen_jumpi_check_loop_end(dc, 0); 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); tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
if (dc->sar_m32_5bit) { 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_5bit = false;
dc->sar_m32_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); 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); tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001);
/* This can change tb->flags, so exit tb */ /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1); 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); 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); gen_helper_wsr_windowbase(cpu_env, v);
/* This can change tb->flags, so exit tb */ /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1); 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); tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1);
/* This can change tb->flags, so exit tb */ /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1); 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); 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); gen_helper_wsr_rasid(cpu_env, v);
/* This can change tb->flags, so exit tb */ /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1); 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); 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_helper_wsr_ibreakenable(cpu_env, v);
gen_jumpi_check_loop_end(dc, 0); 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_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); 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; 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); gen_helper_wsr_ibreaka(cpu_env, tmp, v);
tcg_temp_free(tmp); tcg_temp_free(tmp);
gen_jumpi_check_loop_end(dc, 0); 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; 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); gen_helper_wsr_dbreaka(cpu_env, tmp, v);
tcg_temp_free(tmp); 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; 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); gen_helper_wsr_dbreakc(cpu_env, tmp, v);
tcg_temp_free(tmp); 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); tcg_gen_andi_i32(cpu_SR[sr], v, 0xff);
/* This can change tb->flags, so exit tb */ /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1); 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, tcg_gen_andi_i32(cpu_SR[sr], v,
dc->config->inttype_mask[INTTYPE_SOFTWARE]); dc->config->inttype_mask[INTTYPE_SOFTWARE]);
gen_helper_check_interrupts(cpu_env); gen_check_interrupts(dc);
gen_jumpi_check_loop_end(dc, 0); 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(); 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]); dc->config->inttype_mask[INTTYPE_SOFTWARE]);
tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp); tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp);
tcg_temp_free(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); 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); 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 | uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
PS_UM | PS_EXCM | PS_INTLEVEL; 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; mask |= PS_RING;
} }
tcg_gen_andi_i32(cpu_SR[sr], v, mask); 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 */ /* This can change mmu index and tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1); gen_jumpi_check_loop_end(dc, -1);
return true;
} }
static void gen_wsr_icount(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 bool gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{ {
if (dc->icount) { if (dc->icount) {
tcg_gen_mov_i32(dc->next_icount, v); tcg_gen_mov_i32(dc->next_icount, v);
} else { } else {
tcg_gen_mov_i32(cpu_SR[sr], v); 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); tcg_gen_andi_i32(cpu_SR[sr], v, 0xf);
/* This can change tb->flags, so exit tb */ /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1); 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; uint32_t id = sr - CCOMPARE;
bool ret = false;
if (id < dc->config->nccompare) { if (id < dc->config->nccompare) {
uint32_t int_bit = 1 << dc->config->timerint[id]; 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_mov_i32(cpu_SR[sr], v);
tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit); 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) = { uint32_t sr, TCGv_i32 v) = {
[LBEG] = gen_wsr_lbeg, [LBEG] = gen_wsr_lbeg,
[LEND] = gen_wsr_lend, [LEND] = gen_wsr_lend,
@ -765,6 +828,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
[ITLBCFG] = gen_wsr_tlbcfg, [ITLBCFG] = gen_wsr_tlbcfg,
[DTLBCFG] = gen_wsr_tlbcfg, [DTLBCFG] = gen_wsr_tlbcfg,
[IBREAKENABLE] = gen_wsr_ibreakenable, [IBREAKENABLE] = gen_wsr_ibreakenable,
[MEMCTL] = gen_wsr_memctl,
[ATOMCTL] = gen_wsr_atomctl, [ATOMCTL] = gen_wsr_atomctl,
[IBREAKA] = gen_wsr_ibreaka, [IBREAKA] = gen_wsr_ibreaka,
[IBREAKA + 1] = 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, [INTCLEAR] = gen_wsr_intclear,
[INTENABLE] = gen_wsr_intenable, [INTENABLE] = gen_wsr_intenable,
[PS] = gen_wsr_ps, [PS] = gen_wsr_ps,
[CCOUNT] = gen_wsr_ccount,
[ICOUNT] = gen_wsr_icount, [ICOUNT] = gen_wsr_icount,
[ICOUNTLEVEL] = gen_wsr_icountlevel, [ICOUNTLEVEL] = gen_wsr_icountlevel,
[CCOMPARE] = gen_wsr_ccompare, [CCOMPARE] = gen_wsr_ccompare,
@ -785,9 +850,10 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
}; };
if (wsr_handler[sr]) { if (wsr_handler[sr]) {
wsr_handler[sr](dc, sr, s); return wsr_handler[sr](dc, sr, s);
} else { } else {
tcg_gen_mov_i32(cpu_SR[sr], s); 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 pc = tcg_const_i32(dc->next_pc);
TCGv_i32 intlevel = tcg_const_i32(imm4); 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); gen_helper_waiti(cpu_env, pc, intlevel);
if (dc->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
}
tcg_temp_free(pc); tcg_temp_free(pc);
tcg_temp_free(intlevel); tcg_temp_free(intlevel);
gen_jumpi_check_loop_end(dc, 0);
} }
static bool gen_window_check1(DisasContext *dc, unsigned r1) 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 pc = tcg_const_i32(dc->pc);
TCGv_i32 w = tcg_const_i32(r1 / 4); TCGv_i32 w = tcg_const_i32(r1 / 4);
gen_advance_ccount(dc);
gen_helper_window_check(cpu_env, pc, w); gen_helper_window_check(cpu_env, pc, w);
dc->is_jmp = DISAS_UPDATE; dc->is_jmp = DISAS_UPDATE;
return false; return false;
@ -1037,7 +1109,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
{ {
TCGv_i32 tmp = tcg_const_i32(dc->pc); TCGv_i32 tmp = tcg_const_i32(dc->pc);
gen_advance_ccount(dc);
gen_helper_retw(tmp, cpu_env, tmp); gen_helper_retw(tmp, cpu_env, tmp);
gen_jump(dc, tmp); gen_jump(dc, tmp);
tcg_temp_free(tmp); tcg_temp_free(tmp);
@ -1086,7 +1157,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
if (gen_window_check2(dc, RRR_T, RRR_S)) { if (gen_window_check2(dc, RRR_T, RRR_S)) {
TCGv_i32 pc = tcg_const_i32(dc->pc); TCGv_i32 pc = tcg_const_i32(dc->pc);
gen_advance_ccount(dc);
gen_helper_movsp(cpu_env, pc); gen_helper_movsp(cpu_env, pc);
tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]); tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
tcg_temp_free(pc); tcg_temp_free(pc);
@ -1134,7 +1204,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
case 0: /*RFEx*/ case 0: /*RFEx*/
if (gen_check_privilege(dc)) { if (gen_check_privilege(dc)) {
tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); 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]); gen_jump(dc, cpu_SR[EPC1]);
} }
break; break;
@ -1169,7 +1239,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
} }
gen_helper_restore_owb(cpu_env); gen_helper_restore_owb(cpu_env);
gen_helper_check_interrupts(cpu_env); gen_check_interrupts(dc);
gen_jump(dc, cpu_SR[EPC1]); gen_jump(dc, cpu_SR[EPC1]);
tcg_temp_free(tmp); tcg_temp_free(tmp);
@ -1188,7 +1258,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
if (gen_check_privilege(dc)) { if (gen_check_privilege(dc)) {
tcg_gen_mov_i32(cpu_SR[PS], tcg_gen_mov_i32(cpu_SR[PS],
cpu_SR[EPS2 + RRR_S - 2]); 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]); gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]);
} }
} else { } 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_mov_i32(cpu_R[RRR_T], cpu_SR[PS]);
tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL); tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL);
tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S); 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); gen_jumpi_check_loop_end(dc, 0);
} }
break; break;
@ -1350,11 +1420,19 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
break; break;
case 6: /*RER*/ 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; break;
case 7: /*WER*/ 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; break;
case 8: /*ROTWw*/ case 8: /*ROTWw*/
@ -1534,11 +1612,15 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
(RSR_SR < 64 || gen_check_privilege(dc)) && (RSR_SR < 64 || gen_check_privilege(dc)) &&
gen_window_check1(dc, RRR_T)) { gen_window_check1(dc, RRR_T)) {
TCGv_i32 tmp = tcg_temp_new_i32(); TCGv_i32 tmp = tcg_temp_new_i32();
bool rsr_end, wsr_end;
tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); tcg_gen_mov_i32(tmp, cpu_R[RRR_T]);
gen_rsr(dc, cpu_R[RRR_T], RSR_SR); rsr_end = gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
gen_wsr(dc, RSR_SR, tmp); wsr_end = gen_wsr(dc, RSR_SR, tmp);
tcg_temp_free(tmp); tcg_temp_free(tmp);
if (rsr_end && !wsr_end) {
gen_jumpi_check_loop_end(dc, 0);
}
} }
break; break;
@ -1759,7 +1841,9 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
if (gen_check_sr(dc, RSR_SR, SR_R) && if (gen_check_sr(dc, RSR_SR, SR_R) &&
(RSR_SR < 64 || gen_check_privilege(dc)) && (RSR_SR < 64 || gen_check_privilege(dc)) &&
gen_window_check1(dc, RRR_T)) { 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; 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); tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2);
gen_load_store_alignment(dc, 2, addr, true); gen_load_store_alignment(dc, 2, addr, true);
gen_advance_ccount(dc);
tpc = tcg_const_i32(dc->pc); tpc = tcg_const_i32(dc->pc);
gen_helper_check_atomctl(cpu_env, tpc, addr); gen_helper_check_atomctl(cpu_env, tpc, addr);
tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring); 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 pc = tcg_const_i32(dc->pc);
TCGv_i32 s = tcg_const_i32(BRI12_S); TCGv_i32 s = tcg_const_i32(BRI12_S);
TCGv_i32 imm = tcg_const_i32(BRI12_IMM12); TCGv_i32 imm = tcg_const_i32(BRI12_IMM12);
gen_advance_ccount(dc);
gen_helper_entry(cpu_env, pc, s, imm); gen_helper_entry(cpu_env, pc, s, imm);
tcg_temp_free(imm); tcg_temp_free(imm);
tcg_temp_free(s); tcg_temp_free(s);
@ -2966,7 +3048,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
{ {
TCGv_i32 tmp = tcg_const_i32(dc->pc); TCGv_i32 tmp = tcg_const_i32(dc->pc);
gen_advance_ccount(dc);
gen_helper_retw(tmp, cpu_env, tmp); gen_helper_retw(tmp, cpu_env, tmp);
gen_jump(dc, tmp); gen_jump(dc, tmp);
tcg_temp_free(tmp); tcg_temp_free(tmp);
@ -3063,7 +3144,6 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
dc.lbeg = env->sregs[LBEG]; dc.lbeg = env->sregs[LBEG];
dc.lend = env->sregs[LEND]; dc.lend = env->sregs[LEND];
dc.is_jmp = DISAS_NEXT; dc.is_jmp = DISAS_NEXT;
dc.ccount_delta = 0;
dc.debug = tb->flags & XTENSA_TBFLAG_DEBUG; dc.debug = tb->flags & XTENSA_TBFLAG_DEBUG;
dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT; dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT;
dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >> dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >>
@ -3079,17 +3159,26 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
gen_tb_start(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) { 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); gen_exception(&dc, EXCP_DEBUG);
dc.is_jmp = DISAS_UPDATE;
goto done;
} }
do { do {
tcg_gen_insn_start(dc.pc); tcg_gen_insn_start(dc.pc);
++insn_count; ++insn_count;
++dc.ccount_delta;
if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) { if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
tcg_gen_movi_i32(cpu_pc, dc.pc); tcg_gen_movi_i32(cpu_pc, dc.pc);
gen_exception(&dc, EXCP_DEBUG); gen_exception(&dc, EXCP_DEBUG);
@ -3136,7 +3225,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
dc.pc < next_page_start && dc.pc < next_page_start &&
dc.pc + xtensa_insn_len(env, &dc) <= next_page_start && dc.pc + xtensa_insn_len(env, &dc) <= next_page_start &&
!tcg_op_buf_full()); !tcg_op_buf_full());
done:
reset_litbase(&dc); reset_litbase(&dc);
reset_sar_tracker(&dc); reset_sar_tracker(&dc);
if (dc.icount) { if (dc.icount) {

View File

@ -5,7 +5,7 @@ CROSS=xtensa-$(CORE)-elf-
ifndef XT ifndef XT
SIM = ../../../xtensa-softmmu/qemu-system-xtensa 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 SIMDEBUG = -s -S
else else
SIM = xt-run SIM = xt-run

View File

@ -1,5 +1,7 @@
#include "macros.inc" #include "macros.inc"
#define LSBIT(v) ((v) ^ ((v) & ((v) - 1)))
test_suite interrupt test_suite interrupt
.macro clear_interrupts .macro clear_interrupts
@ -46,14 +48,17 @@ test soft_disabled
set_vector kernel, 1f set_vector kernel, 1f
clear_interrupts clear_interrupts
movi a2, 0x80 movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE)
wsr a2, intset wsr a2, intset
esync esync
rsr a3, interrupt rsr a3, interrupt
movi a4, ~XCHAL_INTTYPE_MASK_TIMER
and a3, a3, a4
assert eq, a2, a3 assert eq, a2, a3
wsr a2, intclear wsr a2, intclear
esync esync
rsr a3, interrupt rsr a3, interrupt
and a3, a3, a4
assert eqi, a3, 0 assert eqi, a3, 0
j 2f j 2f
1: 1:
@ -65,10 +70,12 @@ test soft_intenable
set_vector kernel, 1f set_vector kernel, 1f
clear_interrupts clear_interrupts
movi a2, 0x80 movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE)
wsr a2, intset wsr a2, intset
esync esync
rsr a3, interrupt rsr a3, interrupt
movi a4, ~XCHAL_INTTYPE_MASK_TIMER
and a3, a3, a4
assert eq, a2, a3 assert eq, a2, a3
rsil a3, 0 rsil a3, 0
wsr a2, intenable wsr a2, intenable
@ -82,10 +89,12 @@ test soft_rsil
set_vector kernel, 1f set_vector kernel, 1f
clear_interrupts clear_interrupts
movi a2, 0x80 movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE)
wsr a2, intset wsr a2, intset
esync esync
rsr a3, interrupt rsr a3, interrupt
movi a4, ~XCHAL_INTTYPE_MASK_TIMER
and a3, a3, a4
assert eq, a2, a3 assert eq, a2, a3
wsr a2, intenable wsr a2, intenable
rsil a3, 0 rsil a3, 0
@ -99,10 +108,12 @@ test soft_waiti
set_vector kernel, 1f set_vector kernel, 1f
clear_interrupts clear_interrupts
movi a2, 0x80 movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE)
wsr a2, intset wsr a2, intset
esync esync
rsr a3, interrupt rsr a3, interrupt
movi a4, ~XCHAL_INTTYPE_MASK_TIMER
and a3, a3, a4
assert eq, a2, a3 assert eq, a2, a3
wsr a2, intenable wsr a2, intenable
waiti 0 waiti 0
@ -116,10 +127,12 @@ test soft_user
set_vector user, 2f set_vector user, 2f
clear_interrupts clear_interrupts
movi a2, 0x80 movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE)
wsr a2, intset wsr a2, intset
esync esync
rsr a3, interrupt rsr a3, interrupt
movi a4, ~XCHAL_INTTYPE_MASK_TIMER
and a3, a3, a4
assert eq, a2, a3 assert eq, a2, a3
wsr a2, intenable wsr a2, intenable
@ -139,7 +152,7 @@ test soft_priority
set_vector level3, 2f set_vector level3, 2f
clear_interrupts clear_interrupts
movi a2, 0x880 movi a2, XCHAL_INTTYPE_MASK_SOFTWARE
wsr a2, intenable wsr a2, intenable
rsil a3, 0 rsil a3, 0
esync esync
@ -161,7 +174,7 @@ test eps_epc_rfi
clear_interrupts clear_interrupts
reset_ps reset_ps
movi a2, 0x880 movi a2, XCHAL_INTTYPE_MASK_SOFTWARE
wsr a2, intenable wsr a2, intenable
rsil a3, 0 rsil a3, 0
rsr a3, ps rsr a3, ps

View File

@ -44,6 +44,7 @@ test_end
test_sr acchi, 1 test_sr acchi, 1
test_sr acclo, 1 test_sr acclo, 1
test_sr /*memctl*/97, 0
test_sr_mask /*atomctl*/99, 0, 0 test_sr_mask /*atomctl*/99, 0, 0
test_sr_mask /*br*/4, 0, 0 test_sr_mask /*br*/4, 0, 0
test_sr_mask /*cacheattr*/98, 0, 0 test_sr_mask /*cacheattr*/98, 0, 0

View File

@ -1,12 +1,56 @@
#include "macros.inc" #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_suite timer
test ccount test ccount
rsr a3, ccount rsr a3, ccount
rsr a4, ccount rsr a4, ccount
sub a3, a4, a3 assert ne, a3, a4
assert eqi, a3, 1 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_end
test ccompare test ccompare
@ -18,18 +62,18 @@ test ccompare
wsr a2, ccompare1 wsr a2, ccompare1
wsr a2, ccompare2 wsr a2, ccompare2
movi a3, 20 make_ccount_delta a2, a15
rsr a2, ccount
addi a2, a2, 20
wsr a2, ccompare0 wsr a2, ccompare0
rsr a2, interrupt
assert eqi, a2, 0
loop a3, 1f
rsr a3, interrupt
bnez a3, 2f
1: 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: 2:
assert nei, a5, 0
test_end test_end
test ccompare0_interrupt test ccompare0_interrupt
@ -42,15 +86,14 @@ test ccompare0_interrupt
wsr a2, ccompare1 wsr a2, ccompare1
wsr a2, ccompare2 wsr a2, ccompare2
movi a3, 20 movi a3, WAIT_LOOPS
rsr a2, ccount make_ccount_delta a2, a15
addi a2, a2, 20
wsr a2, ccompare0 wsr a2, ccompare0
rsync rsync
rsr a2, interrupt rsr a2, interrupt
assert eqi, a2, 0 assert eqi, a2, 0
movi a2, 0x40 movi a2, 1 << XCHAL_TIMER0_INTERRUPT
wsr a2, intenable wsr a2, intenable
rsil a2, 0 rsil a2, 0
loop a3, 1f loop a3, 1f
@ -72,14 +115,13 @@ test ccompare1_interrupt
wsr a2, ccompare0 wsr a2, ccompare0
wsr a2, ccompare2 wsr a2, ccompare2
movi a3, 20 movi a3, WAIT_LOOPS
rsr a2, ccount make_ccount_delta a2, a15
addi a2, a2, 20
wsr a2, ccompare1 wsr a2, ccompare1
rsync rsync
rsr a2, interrupt rsr a2, interrupt
assert eqi, a2, 0 assert eqi, a2, 0
movi a2, 0x400 movi a2, 1 << XCHAL_TIMER1_INTERRUPT
wsr a2, intenable wsr a2, intenable
rsil a2, 2 rsil a2, 2
loop a3, 1f loop a3, 1f
@ -99,14 +141,13 @@ test ccompare2_interrupt
wsr a2, ccompare0 wsr a2, ccompare0
wsr a2, ccompare1 wsr a2, ccompare1
movi a3, 20 movi a3, WAIT_LOOPS
rsr a2, ccount make_ccount_delta a2, a15
addi a2, a2, 20
wsr a2, ccompare2 wsr a2, ccompare2
rsync rsync
rsr a2, interrupt rsr a2, interrupt
assert eqi, a2, 0 assert eqi, a2, 0
movi a2, 0x2000 movi a2, 1 << XCHAL_TIMER2_INTERRUPT
wsr a2, intenable wsr a2, intenable
rsil a2, 4 rsil a2, 4
loop a3, 1f loop a3, 1f
@ -125,17 +166,16 @@ test ccompare_interrupt_masked
movi a2, 0 movi a2, 0
wsr a2, ccompare2 wsr a2, ccompare2
movi a3, 40 movi a3, 2 * WAIT_LOOPS
rsr a2, ccount make_ccount_delta a2, a15
addi a2, a2, 20
wsr a2, ccompare1 wsr a2, ccompare1
addi a2, a2, 20 add a2, a2, a15
wsr a2, ccompare0 wsr a2, ccompare0
rsync rsync
rsr a2, interrupt rsr a2, interrupt
assert eqi, a2, 0 assert eqi, a2, 0
movi a2, 0x40 movi a2, 1 << XCHAL_TIMER0_INTERRUPT
wsr a2, intenable wsr a2, intenable
rsil a2, 0 rsil a2, 0
loop a3, 1f loop a3, 1f
@ -156,17 +196,16 @@ test ccompare_interrupt_masked_waiti
movi a2, 0 movi a2, 0
wsr a2, ccompare2 wsr a2, ccompare2
movi a3, 40 movi a3, 2 * WAIT_LOOPS
rsr a2, ccount make_ccount_delta a2, a15
addi a2, a2, 20
wsr a2, ccompare1 wsr a2, ccompare1
addi a2, a2, 20 add a2, a2, a15
wsr a2, ccompare0 wsr a2, ccompare0
rsync rsync
rsr a2, interrupt rsr a2, interrupt
assert eqi, a2, 0 assert eqi, a2, 0
movi a2, 0x40 movi a2, 1 << XCHAL_TIMER0_INTERRUPT
wsr a2, intenable wsr a2, intenable
waiti 0 waiti 0
test_fail test_fail