* [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers
@ 2017-01-15 21:10 Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 1/7] target/xtensa: refactor CCOUNT/CCOMPARE Max Filippov
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Max Filippov @ 2017-01-15 21:10 UTC (permalink / raw)
To: qemu-devel; +Cc: Max Filippov
Hello,
this series reimplements xtensa CCOUNT/CCOMPARE features using QEMU
timers, enables support for running with -icount option and updates
timer tests.
Max Filippov (7):
target/xtensa: refactor CCOUNT/CCOMPARE
target/xtensa: support icount
target/xtensa: don't continue translation after exception
target/xtensa: tests: run tests with icount
target/xtensa: tests: fix timer tests
target/xtensa: tests: replace hardcoded interrupt masks
target/xtensa: tests: add ccount write tests
hw/xtensa/pic_cpu.c | 75 +++-----------
target/xtensa/cpu.h | 21 +++-
target/xtensa/helper.h | 5 +-
target/xtensa/op_helper.c | 37 +++++--
target/xtensa/translate.c | 225 ++++++++++++++++++++++++++++--------------
tests/tcg/xtensa/Makefile | 2 +-
tests/tcg/xtensa/test_timer.S | 105 +++++++++++++-------
7 files changed, 284 insertions(+), 186 deletions(-)
--
2.1.4
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 1/7] target/xtensa: refactor CCOUNT/CCOMPARE
2017-01-15 21:10 [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers Max Filippov
@ 2017-01-15 21:10 ` Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 2/7] target/xtensa: support icount Max Filippov
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Max Filippov @ 2017-01-15 21:10 UTC (permalink / raw)
To: qemu-devel; +Cc: Max Filippov
Xtensa cores may have a register (CCOUNT) that counts core clock cycles.
It may also have a number of registers (CCOMPAREx); when CCOUNT value
passes the value of CCOMPAREx, timer interrupt x is raised.
Currently xtensa target counts a number of completed instructions and
assumes that for CCOUNT one instruction takes one cycle to complete.
It calls helper function to update CCOUNT register at every TB end and
raise timer interrupts. This scheme works very predictably and doesn't
have noticeable performance impact, but it is hard to use with multiple
synchronized processors, especially with coming MTTCG.
Derive CCOUNT from the virtual simulation time, QEMU_CLOCK_VIRTUAL.
Use native QEMU timers for CCOMPARE timers, one timer for each register.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
hw/xtensa/pic_cpu.c | 75 +++++++++--------------------------------------
target/xtensa/cpu.h | 16 ++++++----
target/xtensa/helper.h | 5 ++--
target/xtensa/op_helper.c | 33 ++++++++++++++++-----
target/xtensa/translate.c | 43 ++++++++-------------------
5 files changed, 65 insertions(+), 107 deletions(-)
diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c
index 2bed64f..0e812d7 100644
--- a/hw/xtensa/pic_cpu.c
+++ b/hw/xtensa/pic_cpu.c
@@ -31,22 +31,6 @@
#include "qemu/log.h"
#include "qemu/timer.h"
-void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
-{
- uint32_t old_ccount = env->sregs[CCOUNT] + 1;
-
- env->sregs[CCOUNT] += d;
-
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
- int i;
- for (i = 0; i < env->config->nccompare; ++i) {
- if (env->sregs[CCOMPARE + i] - old_ccount < d) {
- xtensa_timer_irq(env, i, 1);
- }
- }
- }
-}
-
void check_interrupts(CPUXtensaState *env)
{
CPUState *cs = CPU(xtensa_env_get_cpu(env));
@@ -54,17 +38,6 @@ void check_interrupts(CPUXtensaState *env)
uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
int level;
- /* If the CPU is halted advance CCOUNT according to the QEMU_CLOCK_VIRTUAL time
- * elapsed since the moment when it was advanced last time.
- */
- if (cs->halted) {
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- xtensa_advance_ccount(env,
- muldiv64(now - env->halt_clock,
- env->config->clock_freq_khz, 1000000));
- env->halt_clock = now;
- }
for (level = env->config->nlevel; level > minlevel; --level) {
if (env->config->level_mask[level] & int_set_enabled) {
env->pending_irq_level = level;
@@ -109,49 +82,29 @@ void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active)
qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
}
-void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
-{
- int i;
- uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
-
- for (i = 0; i < env->config->nccompare; ++i) {
- if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
- wake_ccount - env->sregs[CCOUNT]) {
- wake_ccount = env->sregs[CCOMPARE + i];
- }
- }
- env->wake_ccount = wake_ccount;
- timer_mod(env->ccompare_timer, env->halt_clock +
- (uint64_t)(wake_ccount - env->sregs[CCOUNT]) *
- 1000000 / env->config->clock_freq_khz);
-}
-
static void xtensa_ccompare_cb(void *opaque)
{
- XtensaCPU *cpu = opaque;
- CPUXtensaState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
+ XtensaCcompareTimer *ccompare = opaque;
+ CPUXtensaState *env = ccompare->env;
+ unsigned i = ccompare - env->ccompare;
- if (cs->halted) {
- env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
- if (!cpu_has_work(cs)) {
- env->sregs[CCOUNT] = env->wake_ccount + 1;
- xtensa_rearm_ccompare_timer(env);
- }
- }
+ xtensa_timer_irq(env, i, 1);
}
void xtensa_irq_init(CPUXtensaState *env)
{
- XtensaCPU *cpu = xtensa_env_get_cpu(env);
-
env->irq_inputs = (void **)qemu_allocate_irqs(
xtensa_set_irq, env, env->config->ninterrupt);
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
- env->config->nccompare > 0) {
- env->ccompare_timer =
- timer_new_ns(QEMU_CLOCK_VIRTUAL, &xtensa_ccompare_cb, cpu);
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+ unsigned i;
+
+ env->time_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ env->ccount_base = env->sregs[CCOUNT];
+ for (i = 0; i < env->config->nccompare; ++i) {
+ env->ccompare[i].env = env;
+ env->ccompare[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ xtensa_ccompare_cb, env->ccompare + i);
+ }
}
}
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 77bd9d2..744af81 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -269,6 +269,8 @@ typedef enum {
INTTYPE_MAX
} interrupt_type;
+struct CPUXtensaState;
+
typedef struct xtensa_tlb_entry {
uint32_t vaddr;
uint32_t paddr;
@@ -298,6 +300,11 @@ typedef struct XtensaGdbRegmap {
XtensaGdbReg reg[1 + 16 + 64 + 256 + 256];
} XtensaGdbRegmap;
+typedef struct XtensaCcompareTimer {
+ struct CPUXtensaState *env;
+ QEMUTimer *timer;
+} XtensaCcompareTimer;
+
struct XtensaConfig {
const char *name;
uint64_t options;
@@ -369,9 +376,10 @@ typedef struct CPUXtensaState {
bool runstall;
int pending_irq_level; /* level of last raised IRQ */
void **irq_inputs;
- QEMUTimer *ccompare_timer;
- uint32_t wake_ccount;
- int64_t halt_clock;
+ XtensaCcompareTimer ccompare[MAX_NCCOMPARE];
+ uint64_t time_base;
+ uint64_t ccount_time;
+ uint32_t ccount_base;
int exception_taken;
unsigned static_vectors;
@@ -439,9 +447,7 @@ void xtensa_register_core(XtensaConfigList *node);
void check_interrupts(CPUXtensaState *s);
void xtensa_irq_init(CPUXtensaState *env);
void *xtensa_get_extint(CPUXtensaState *env, unsigned extint);
-void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d);
void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active);
-void xtensa_rearm_ccompare_timer(CPUXtensaState *env);
int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
void xtensa_sync_window_from_phys(CPUXtensaState *env);
diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h
index 5ea9c5b..427bdc7 100644
--- a/target/xtensa/helper.h
+++ b/target/xtensa/helper.h
@@ -18,8 +18,9 @@ DEF_HELPER_1(simcall, void, env)
DEF_HELPER_1(dump_state, void, env)
DEF_HELPER_3(waiti, void, env, i32, i32)
-DEF_HELPER_3(timer_irq, void, env, i32, i32)
-DEF_HELPER_2(advance_ccount, void, env, i32)
+DEF_HELPER_1(update_ccount, void, env)
+DEF_HELPER_2(wsr_ccount, void, env, i32)
+DEF_HELPER_2(update_ccompare, void, env, i32)
DEF_HELPER_1(check_interrupts, void, env)
DEF_HELPER_3(check_atomctl, void, env, i32, i32)
diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c
index 0a4b214..5e5c7da 100644
--- a/target/xtensa/op_helper.c
+++ b/target/xtensa/op_helper.c
@@ -398,22 +398,39 @@ void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
}
cpu = CPU(xtensa_env_get_cpu(env));
- env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
cpu->halted = 1;
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
- xtensa_rearm_ccompare_timer(env);
- }
HELPER(exception)(env, EXCP_HLT);
}
-void HELPER(timer_irq)(CPUXtensaState *env, uint32_t id, uint32_t active)
+void HELPER(update_ccount)(CPUXtensaState *env)
+{
+ 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);
}
void HELPER(check_interrupts)(CPUXtensaState *env)
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 0858c29..cb42945 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -64,7 +64,6 @@ typedef struct DisasContext {
bool sar_m32_allocated;
TCGv_i32 sar_m32;
- uint32_t ccount_delta;
unsigned window;
bool debug;
@@ -314,20 +313,9 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
tcg_temp_free(tmp);
}
-static void gen_advance_ccount(DisasContext *dc)
-{
- if (dc->ccount_delta > 0) {
- TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
- gen_helper_advance_ccount(cpu_env, tmp);
- tcg_temp_free(tmp);
- }
- dc->ccount_delta = 0;
-}
-
static void gen_exception(DisasContext *dc, int excp)
{
TCGv_i32 tmp = tcg_const_i32(excp);
- gen_advance_ccount(dc);
gen_helper_exception(cpu_env, tmp);
tcg_temp_free(tmp);
}
@@ -336,7 +324,6 @@ static void gen_exception_cause(DisasContext *dc, uint32_t cause)
{
TCGv_i32 tpc = tcg_const_i32(dc->pc);
TCGv_i32 tcause = tcg_const_i32(cause);
- gen_advance_ccount(dc);
gen_helper_exception_cause(cpu_env, tpc, tcause);
tcg_temp_free(tpc);
tcg_temp_free(tcause);
@@ -351,7 +338,6 @@ static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause,
{
TCGv_i32 tpc = tcg_const_i32(dc->pc);
TCGv_i32 tcause = tcg_const_i32(cause);
- gen_advance_ccount(dc);
gen_helper_exception_cause_vaddr(cpu_env, tpc, tcause, vaddr);
tcg_temp_free(tpc);
tcg_temp_free(tcause);
@@ -361,7 +347,6 @@ static void gen_debug_exception(DisasContext *dc, uint32_t cause)
{
TCGv_i32 tpc = tcg_const_i32(dc->pc);
TCGv_i32 tcause = tcg_const_i32(cause);
- gen_advance_ccount(dc);
gen_helper_debug_exception(cpu_env, tpc, tcause);
tcg_temp_free(tpc);
tcg_temp_free(tcause);
@@ -394,7 +379,6 @@ static bool gen_check_cpenable(DisasContext *dc, unsigned cp)
static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
{
tcg_gen_mov_i32(cpu_pc, dest);
- gen_advance_ccount(dc);
if (dc->icount) {
tcg_gen_mov_i32(cpu_SR[ICOUNT], dc->next_icount);
}
@@ -465,7 +449,6 @@ static bool gen_check_loop_end(DisasContext *dc, int slot)
dc->next_pc == dc->lend) {
TCGLabel *label = gen_new_label();
- gen_advance_ccount(dc);
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label);
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1);
gen_jumpi(dc, dc->lbeg, slot);
@@ -488,7 +471,6 @@ static void gen_brcond(DisasContext *dc, TCGCond cond,
{
TCGLabel *label = gen_new_label();
- gen_advance_ccount(dc);
tcg_gen_brcond_i32(cond, t0, t1, label);
gen_jumpi_check_loop_end(dc, 0);
gen_set_label(label);
@@ -530,7 +512,7 @@ static bool gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access)
static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
{
- gen_advance_ccount(dc);
+ gen_helper_update_ccount(cpu_env);
tcg_gen_mov_i32(d, cpu_SR[sr]);
}
@@ -546,6 +528,7 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
static void (* const rsr_handler[256])(DisasContext *dc,
TCGv_i32 d, uint32_t sr) = {
[CCOUNT] = gen_rsr_ccount,
+ [INTSET] = gen_rsr_ccount,
[PTEVADDR] = gen_rsr_ptevaddr,
};
@@ -720,6 +703,11 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
gen_jumpi_check_loop_end(dc, -1);
}
+static void gen_wsr_ccount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+ gen_helper_wsr_ccount(cpu_env, v);
+}
+
static void gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
if (dc->icount) {
@@ -741,10 +729,12 @@ static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
uint32_t id = sr - CCOMPARE;
if (id < dc->config->nccompare) {
uint32_t int_bit = 1 << dc->config->timerint[id];
- gen_advance_ccount(dc);
+ TCGv_i32 tmp = tcg_const_i32(id);
+
tcg_gen_mov_i32(cpu_SR[sr], v);
tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit);
- gen_helper_check_interrupts(cpu_env);
+ gen_helper_update_ccompare(cpu_env, tmp);
+ tcg_temp_free(tmp);
}
}
@@ -777,6 +767,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
[INTCLEAR] = gen_wsr_intclear,
[INTENABLE] = gen_wsr_intenable,
[PS] = gen_wsr_ps,
+ [CCOUNT] = gen_wsr_ccount,
[ICOUNT] = gen_wsr_icount,
[ICOUNTLEVEL] = gen_wsr_icountlevel,
[CCOMPARE] = gen_wsr_ccompare,
@@ -829,7 +820,6 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4)
{
TCGv_i32 pc = tcg_const_i32(dc->next_pc);
TCGv_i32 intlevel = tcg_const_i32(imm4);
- gen_advance_ccount(dc);
gen_helper_waiti(cpu_env, pc, intlevel);
tcg_temp_free(pc);
tcg_temp_free(intlevel);
@@ -841,7 +831,6 @@ static bool gen_window_check1(DisasContext *dc, unsigned r1)
TCGv_i32 pc = tcg_const_i32(dc->pc);
TCGv_i32 w = tcg_const_i32(r1 / 4);
- gen_advance_ccount(dc);
gen_helper_window_check(cpu_env, pc, w);
dc->is_jmp = DISAS_UPDATE;
return false;
@@ -1037,7 +1026,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
{
TCGv_i32 tmp = tcg_const_i32(dc->pc);
- gen_advance_ccount(dc);
gen_helper_retw(tmp, cpu_env, tmp);
gen_jump(dc, tmp);
tcg_temp_free(tmp);
@@ -1086,7 +1074,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
if (gen_window_check2(dc, RRR_T, RRR_S)) {
TCGv_i32 pc = tcg_const_i32(dc->pc);
- gen_advance_ccount(dc);
gen_helper_movsp(cpu_env, pc);
tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
tcg_temp_free(pc);
@@ -2517,7 +2504,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2);
gen_load_store_alignment(dc, 2, addr, true);
- gen_advance_ccount(dc);
tpc = tcg_const_i32(dc->pc);
gen_helper_check_atomctl(cpu_env, tpc, addr);
tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring);
@@ -2747,7 +2733,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
TCGv_i32 pc = tcg_const_i32(dc->pc);
TCGv_i32 s = tcg_const_i32(BRI12_S);
TCGv_i32 imm = tcg_const_i32(BRI12_IMM12);
- gen_advance_ccount(dc);
gen_helper_entry(cpu_env, pc, s, imm);
tcg_temp_free(imm);
tcg_temp_free(s);
@@ -2966,7 +2951,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
{
TCGv_i32 tmp = tcg_const_i32(dc->pc);
- gen_advance_ccount(dc);
gen_helper_retw(tmp, cpu_env, tmp);
gen_jump(dc, tmp);
tcg_temp_free(tmp);
@@ -3063,7 +3047,6 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
dc.lbeg = env->sregs[LBEG];
dc.lend = env->sregs[LEND];
dc.is_jmp = DISAS_NEXT;
- dc.ccount_delta = 0;
dc.debug = tb->flags & XTENSA_TBFLAG_DEBUG;
dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT;
dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >>
@@ -3088,8 +3071,6 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
tcg_gen_insn_start(dc.pc);
++insn_count;
- ++dc.ccount_delta;
-
if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
tcg_gen_movi_i32(cpu_pc, dc.pc);
gen_exception(&dc, EXCP_DEBUG);
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 2/7] target/xtensa: support icount
2017-01-15 21:10 [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 1/7] target/xtensa: refactor CCOUNT/CCOMPARE Max Filippov
@ 2017-01-15 21:10 ` Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 3/7] target/xtensa: don't continue translation after exception Max Filippov
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Max Filippov @ 2017-01-15 21:10 UTC (permalink / raw)
To: qemu-devel; +Cc: Max Filippov
Delimit each instruction that may access timers or IRQ state with
qemu_io_start/qemu_io_end, so that qemu-system-xtensa could be run with
-icount option.
Raise EXCP_YIELD after CCOMPARE reprogramming to let tcg_cpu_exec
recalculate how long this CPU is allowed to run.
RSR now may need to terminate TB, but it can't be done in RSR handler
because the same handler is used for XSR together with WSR handler, which
may also need to terminate TB. Change RSR and WSR handlers return type
to bool indicating whether TB termination is needed (RSR) or has been
done (WSR), and add TB termination after RSR/WSR dispatcher call.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target/xtensa/cpu.h | 5 ++
target/xtensa/op_helper.c | 4 ++
target/xtensa/translate.c | 179 ++++++++++++++++++++++++++++++++++------------
3 files changed, 143 insertions(+), 45 deletions(-)
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 744af81..a10f1ef 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -382,6 +382,7 @@ typedef struct CPUXtensaState {
uint32_t ccount_base;
int exception_taken;
+ int yield_needed;
unsigned static_vectors;
/* Watchpoints for DBREAK registers */
@@ -554,6 +555,7 @@ static inline int cpu_mmu_index(CPUXtensaState *env, bool ifetch)
#define XTENSA_TBFLAG_EXCEPTION 0x4000
#define XTENSA_TBFLAG_WINDOW_MASK 0x18000
#define XTENSA_TBFLAG_WINDOW_SHIFT 15
+#define XTENSA_TBFLAG_YIELD 0x20000
static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
@@ -595,6 +597,9 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
} else {
*flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT;
}
+ if (env->yield_needed) {
+ *flags |= XTENSA_TBFLAG_YIELD;
+ }
}
#include "exec/cpu-all.h"
diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c
index 5e5c7da..864a8f6 100644
--- a/target/xtensa/op_helper.c
+++ b/target/xtensa/op_helper.c
@@ -105,6 +105,9 @@ void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
CPUState *cs = CPU(xtensa_env_get_cpu(env));
cs->exception_index = excp;
+ if (excp == EXCP_YIELD) {
+ env->yield_needed = 0;
+ }
if (excp == EXCP_DEBUG) {
env->exception_taken = 0;
}
@@ -431,6 +434,7 @@ void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i)
dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1;
timer_mod(env->ccompare[i].timer,
env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz);
+ env->yield_needed = 1;
}
void HELPER(check_interrupts)(CPUXtensaState *env)
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index cb42945..96c64d6 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -510,22 +510,31 @@ static bool gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access)
return true;
}
-static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+static bool gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
{
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_update_ccount(cpu_env);
tcg_gen_mov_i32(d, cpu_SR[sr]);
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_end();
+ return true;
+ }
+ return false;
}
-static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+static bool gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
{
tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10);
tcg_gen_or_i32(d, d, cpu_SR[sr]);
tcg_gen_andi_i32(d, d, 0xfffffffc);
+ return false;
}
-static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+static bool gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
{
- static void (* const rsr_handler[256])(DisasContext *dc,
+ static bool (* const rsr_handler[256])(DisasContext *dc,
TCGv_i32 d, uint32_t sr) = {
[CCOUNT] = gen_rsr_ccount,
[INTSET] = gen_rsr_ccount,
@@ -533,25 +542,28 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
};
if (rsr_handler[sr]) {
- rsr_handler[sr](dc, d, sr);
+ return rsr_handler[sr](dc, d, sr);
} else {
tcg_gen_mov_i32(d, cpu_SR[sr]);
+ return false;
}
}
-static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+static bool gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
gen_helper_wsr_lbeg(cpu_env, s);
gen_jumpi_check_loop_end(dc, 0);
+ return false;
}
-static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+static bool gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
gen_helper_wsr_lend(cpu_env, s);
gen_jumpi_check_loop_end(dc, 0);
+ return false;
}
-static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+static bool gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
if (dc->sar_m32_5bit) {
@@ -559,68 +571,79 @@ static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
}
dc->sar_5bit = false;
dc->sar_m32_5bit = false;
+ return false;
}
-static void gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+static bool gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
tcg_gen_andi_i32(cpu_SR[sr], s, 0xffff);
+ return false;
}
-static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+static bool gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001);
/* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
+ return true;
}
-static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+static bool gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
tcg_gen_ext8s_i32(cpu_SR[sr], s);
+ return false;
}
-static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
gen_helper_wsr_windowbase(cpu_env, v);
/* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
+ return true;
}
-static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1);
/* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
+ return true;
}
-static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000);
+ return false;
}
-static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
gen_helper_wsr_rasid(cpu_env, v);
/* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
+ return true;
}
-static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000);
+ return false;
}
-static void gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
gen_helper_wsr_ibreakenable(cpu_env, v);
gen_jumpi_check_loop_end(dc, 0);
+ return true;
}
-static void gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v, 0x3f);
+ return false;
}
-static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
unsigned id = sr - IBREAKA;
@@ -629,10 +652,12 @@ static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
gen_helper_wsr_ibreaka(cpu_env, tmp, v);
tcg_temp_free(tmp);
gen_jumpi_check_loop_end(dc, 0);
+ return true;
}
+ return false;
}
-static void gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
unsigned id = sr - DBREAKA;
@@ -641,9 +666,10 @@ static void gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
gen_helper_wsr_dbreaka(cpu_env, tmp, v);
tcg_temp_free(tmp);
}
+ return false;
}
-static void gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
unsigned id = sr - DBREAKC;
@@ -652,24 +678,38 @@ static void gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v)
gen_helper_wsr_dbreakc(cpu_env, tmp, v);
tcg_temp_free(tmp);
}
+ return false;
}
-static void gen_wsr_cpenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_cpenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v, 0xff);
/* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
+ return true;
}
-static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static void gen_check_interrupts(DisasContext *dc)
+{
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_check_interrupts(cpu_env);
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_end();
+ }
+}
+
+static bool gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v,
dc->config->inttype_mask[INTTYPE_SOFTWARE]);
- gen_helper_check_interrupts(cpu_env);
+ gen_check_interrupts(dc);
gen_jumpi_check_loop_end(dc, 0);
+ return true;
}
-static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
TCGv_i32 tmp = tcg_temp_new_i32();
@@ -679,17 +719,20 @@ static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v)
dc->config->inttype_mask[INTTYPE_SOFTWARE]);
tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp);
tcg_temp_free(tmp);
- gen_helper_check_interrupts(cpu_env);
+ gen_check_interrupts(dc);
+ gen_jumpi_check_loop_end(dc, 0);
+ return true;
}
-static void gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_mov_i32(cpu_SR[sr], v);
- gen_helper_check_interrupts(cpu_env);
+ gen_check_interrupts(dc);
gen_jumpi_check_loop_end(dc, 0);
+ return true;
}
-static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
PS_UM | PS_EXCM | PS_INTLEVEL;
@@ -698,49 +741,72 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
mask |= PS_RING;
}
tcg_gen_andi_i32(cpu_SR[sr], v, mask);
- gen_helper_check_interrupts(cpu_env);
+ gen_check_interrupts(dc);
/* This can change mmu index and tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
+ return true;
}
-static void gen_wsr_ccount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_ccount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_wsr_ccount(cpu_env, v);
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_end();
+ gen_jumpi_check_loop_end(dc, 0);
+ return true;
+ }
+ return false;
}
-static void gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
if (dc->icount) {
tcg_gen_mov_i32(dc->next_icount, v);
} else {
tcg_gen_mov_i32(cpu_SR[sr], v);
}
+ return false;
}
-static void gen_wsr_icountlevel(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_icountlevel(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v, 0xf);
/* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
+ return true;
}
-static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
uint32_t id = sr - CCOMPARE;
+ bool ret = false;
+
if (id < dc->config->nccompare) {
uint32_t int_bit = 1 << dc->config->timerint[id];
TCGv_i32 tmp = tcg_const_i32(id);
tcg_gen_mov_i32(cpu_SR[sr], v);
tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit);
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_update_ccompare(cpu_env, tmp);
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_end();
+ gen_jumpi_check_loop_end(dc, 0);
+ ret = true;
+ }
tcg_temp_free(tmp);
}
+ return ret;
}
-static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+static bool gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
- static void (* const wsr_handler[256])(DisasContext *dc,
+ static bool (* const wsr_handler[256])(DisasContext *dc,
uint32_t sr, TCGv_i32 v) = {
[LBEG] = gen_wsr_lbeg,
[LEND] = gen_wsr_lend,
@@ -776,9 +842,10 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
};
if (wsr_handler[sr]) {
- wsr_handler[sr](dc, sr, s);
+ return wsr_handler[sr](dc, sr, s);
} else {
tcg_gen_mov_i32(cpu_SR[sr], s);
+ return false;
}
}
@@ -820,9 +887,17 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4)
{
TCGv_i32 pc = tcg_const_i32(dc->next_pc);
TCGv_i32 intlevel = tcg_const_i32(imm4);
+
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_waiti(cpu_env, pc, intlevel);
+ if (dc->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_end();
+ }
tcg_temp_free(pc);
tcg_temp_free(intlevel);
+ gen_jumpi_check_loop_end(dc, 0);
}
static bool gen_window_check1(DisasContext *dc, unsigned r1)
@@ -1121,7 +1196,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
case 0: /*RFEx*/
if (gen_check_privilege(dc)) {
tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
- gen_helper_check_interrupts(cpu_env);
+ gen_check_interrupts(dc);
gen_jump(dc, cpu_SR[EPC1]);
}
break;
@@ -1156,7 +1231,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
}
gen_helper_restore_owb(cpu_env);
- gen_helper_check_interrupts(cpu_env);
+ gen_check_interrupts(dc);
gen_jump(dc, cpu_SR[EPC1]);
tcg_temp_free(tmp);
@@ -1175,7 +1250,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
if (gen_check_privilege(dc)) {
tcg_gen_mov_i32(cpu_SR[PS],
cpu_SR[EPS2 + RRR_S - 2]);
- gen_helper_check_interrupts(cpu_env);
+ gen_check_interrupts(dc);
gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]);
}
} else {
@@ -1233,7 +1308,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]);
tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL);
tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S);
- gen_helper_check_interrupts(cpu_env);
+ gen_check_interrupts(dc);
gen_jumpi_check_loop_end(dc, 0);
}
break;
@@ -1521,11 +1596,15 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
(RSR_SR < 64 || gen_check_privilege(dc)) &&
gen_window_check1(dc, RRR_T)) {
TCGv_i32 tmp = tcg_temp_new_i32();
+ bool rsr_end, wsr_end;
tcg_gen_mov_i32(tmp, cpu_R[RRR_T]);
- gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
- gen_wsr(dc, RSR_SR, tmp);
+ rsr_end = gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+ wsr_end = gen_wsr(dc, RSR_SR, tmp);
tcg_temp_free(tmp);
+ if (rsr_end && !wsr_end) {
+ gen_jumpi_check_loop_end(dc, 0);
+ }
}
break;
@@ -1746,7 +1825,9 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
if (gen_check_sr(dc, RSR_SR, SR_R) &&
(RSR_SR < 64 || gen_check_privilege(dc)) &&
gen_window_check1(dc, RRR_T)) {
- gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+ if (gen_rsr(dc, cpu_R[RRR_T], RSR_SR)) {
+ gen_jumpi_check_loop_end(dc, 0);
+ }
}
break;
@@ -3062,6 +3143,14 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
gen_tb_start(tb);
+ if ((tb->cflags & CF_USE_ICOUNT) &&
+ (tb->flags & XTENSA_TBFLAG_YIELD)) {
+ tcg_gen_insn_start(dc.pc);
+ ++insn_count;
+ gen_exception(&dc, EXCP_YIELD);
+ dc.is_jmp = DISAS_UPDATE;
+ goto done;
+ }
if (tb->flags & XTENSA_TBFLAG_EXCEPTION) {
tcg_gen_movi_i32(cpu_pc, dc.pc);
gen_exception(&dc, EXCP_DEBUG);
@@ -3117,7 +3206,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
dc.pc < next_page_start &&
dc.pc + xtensa_insn_len(env, &dc) <= next_page_start &&
!tcg_op_buf_full());
-
+done:
reset_litbase(&dc);
reset_sar_tracker(&dc);
if (dc.icount) {
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 3/7] target/xtensa: don't continue translation after exception
2017-01-15 21:10 [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 1/7] target/xtensa: refactor CCOUNT/CCOMPARE Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 2/7] target/xtensa: support icount Max Filippov
@ 2017-01-15 21:10 ` Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 4/7] target/xtensa: tests: run tests with icount Max Filippov
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Max Filippov @ 2017-01-15 21:10 UTC (permalink / raw)
To: qemu-devel; +Cc: Max Filippov
There's no point in continuing translating guest instructions once an
unconditional exception is thrown.
There's also no point in updating pc before any instruction is
translated, don't do it.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target/xtensa/translate.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 96c64d6..7a198fa 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -3152,8 +3152,11 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
goto done;
}
if (tb->flags & XTENSA_TBFLAG_EXCEPTION) {
- tcg_gen_movi_i32(cpu_pc, dc.pc);
+ tcg_gen_insn_start(dc.pc);
+ ++insn_count;
gen_exception(&dc, EXCP_DEBUG);
+ dc.is_jmp = DISAS_UPDATE;
+ goto done;
}
do {
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 4/7] target/xtensa: tests: run tests with icount
2017-01-15 21:10 [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers Max Filippov
` (2 preceding siblings ...)
2017-01-15 21:10 ` [Qemu-devel] [PATCH 3/7] target/xtensa: don't continue translation after exception Max Filippov
@ 2017-01-15 21:10 ` Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 5/7] target/xtensa: tests: fix timer tests Max Filippov
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Max Filippov @ 2017-01-15 21:10 UTC (permalink / raw)
To: qemu-devel; +Cc: Max Filippov
Timer tests expect certain determinism in CCOUNT updates and timer
interrupts firing. Run QEMU with -icount to get deterministic results.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
tests/tcg/xtensa/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile
index 7f9f2d9..2882c43 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
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 5/7] target/xtensa: tests: fix timer tests
2017-01-15 21:10 [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers Max Filippov
` (3 preceding siblings ...)
2017-01-15 21:10 ` [Qemu-devel] [PATCH 4/7] target/xtensa: tests: run tests with icount Max Filippov
@ 2017-01-15 21:10 ` Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 6/7] target/xtensa: tests: replace hardcoded interrupt masks Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 7/7] target/xtensa: tests: add ccount write tests Max Filippov
6 siblings, 0 replies; 8+ messages in thread
From: Max Filippov @ 2017-01-15 21:10 UTC (permalink / raw)
To: qemu-devel; +Cc: Max Filippov
Don't expect that CCOUNT increments are equal to the number of executed
instructions. Verify that timer interrupt does not fire before the
programmed CCOMPARE value and does fire after.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
tests/tcg/xtensa/test_timer.S | 61 +++++++++++++++++++++++--------------------
1 file changed, 33 insertions(+), 28 deletions(-)
diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S
index f8c6f74..9e6012d 100644
--- a/tests/tcg/xtensa/test_timer.S
+++ b/tests/tcg/xtensa/test_timer.S
@@ -1,12 +1,22 @@
#include "macros.inc"
+#define CCOUNT_SHIFT 4
+#define WAIT_LOOPS 20
+
+.macro make_ccount_delta target, delta
+ rsr \delta, ccount
+ rsr \target, ccount
+ sub \delta, \target, \delta
+ slli \delta, \delta, CCOUNT_SHIFT
+ add \target, \target, \delta
+.endm
+
test_suite timer
test ccount
rsr a3, ccount
rsr a4, ccount
- sub a3, a4, a3
- assert eqi, a3, 1
+ assert ne, a3, a4
test_end
test ccompare
@@ -18,18 +28,18 @@ test ccompare
wsr a2, ccompare1
wsr a2, ccompare2
- movi a3, 20
- rsr a2, ccount
- addi a2, a2, 20
+ make_ccount_delta a2, a15
wsr a2, ccompare0
- rsr a2, interrupt
- assert eqi, a2, 0
- loop a3, 1f
- rsr a3, interrupt
- bnez a3, 2f
1:
- test_fail
+ rsr a3, interrupt
+ rsr a4, ccount
+ rsr a5, interrupt
+ sub a4, a4, a2
+ bgez a4, 2f
+ assert eqi, a3, 0
+ j 1b
2:
+ assert nei, a5, 0
test_end
test ccompare0_interrupt
@@ -42,9 +52,8 @@ test ccompare0_interrupt
wsr a2, ccompare1
wsr a2, ccompare2
- movi a3, 20
- rsr a2, ccount
- addi a2, a2, 20
+ movi a3, WAIT_LOOPS
+ make_ccount_delta a2, a15
wsr a2, ccompare0
rsync
rsr a2, interrupt
@@ -72,9 +81,8 @@ test ccompare1_interrupt
wsr a2, ccompare0
wsr a2, ccompare2
- movi a3, 20
- rsr a2, ccount
- addi a2, a2, 20
+ movi a3, WAIT_LOOPS
+ make_ccount_delta a2, a15
wsr a2, ccompare1
rsync
rsr a2, interrupt
@@ -99,9 +107,8 @@ test ccompare2_interrupt
wsr a2, ccompare0
wsr a2, ccompare1
- movi a3, 20
- rsr a2, ccount
- addi a2, a2, 20
+ movi a3, WAIT_LOOPS
+ make_ccount_delta a2, a15
wsr a2, ccompare2
rsync
rsr a2, interrupt
@@ -125,11 +132,10 @@ test ccompare_interrupt_masked
movi a2, 0
wsr a2, ccompare2
- movi a3, 40
- rsr a2, ccount
- addi a2, a2, 20
+ movi a3, 2 * WAIT_LOOPS
+ make_ccount_delta a2, a15
wsr a2, ccompare1
- addi a2, a2, 20
+ add a2, a2, a15
wsr a2, ccompare0
rsync
rsr a2, interrupt
@@ -156,11 +162,10 @@ test ccompare_interrupt_masked_waiti
movi a2, 0
wsr a2, ccompare2
- movi a3, 40
- rsr a2, ccount
- addi a2, a2, 20
+ movi a3, 2 * WAIT_LOOPS
+ make_ccount_delta a2, a15
wsr a2, ccompare1
- addi a2, a2, 20
+ add a2, a2, a15
wsr a2, ccompare0
rsync
rsr a2, interrupt
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 6/7] target/xtensa: tests: replace hardcoded interrupt masks
2017-01-15 21:10 [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers Max Filippov
` (4 preceding siblings ...)
2017-01-15 21:10 ` [Qemu-devel] [PATCH 5/7] target/xtensa: tests: fix timer tests Max Filippov
@ 2017-01-15 21:10 ` Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 7/7] target/xtensa: tests: add ccount write tests Max Filippov
6 siblings, 0 replies; 8+ messages in thread
From: Max Filippov @ 2017-01-15 21:10 UTC (permalink / raw)
To: qemu-devel; +Cc: Max Filippov
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
tests/tcg/xtensa/test_timer.S | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S
index 9e6012d..844c032 100644
--- a/tests/tcg/xtensa/test_timer.S
+++ b/tests/tcg/xtensa/test_timer.S
@@ -59,7 +59,7 @@ test ccompare0_interrupt
rsr a2, interrupt
assert eqi, a2, 0
- movi a2, 0x40
+ movi a2, 1 << XCHAL_TIMER0_INTERRUPT
wsr a2, intenable
rsil a2, 0
loop a3, 1f
@@ -87,7 +87,7 @@ test ccompare1_interrupt
rsync
rsr a2, interrupt
assert eqi, a2, 0
- movi a2, 0x400
+ movi a2, 1 << XCHAL_TIMER1_INTERRUPT
wsr a2, intenable
rsil a2, 2
loop a3, 1f
@@ -113,7 +113,7 @@ test ccompare2_interrupt
rsync
rsr a2, interrupt
assert eqi, a2, 0
- movi a2, 0x2000
+ movi a2, 1 << XCHAL_TIMER2_INTERRUPT
wsr a2, intenable
rsil a2, 4
loop a3, 1f
@@ -141,7 +141,7 @@ test ccompare_interrupt_masked
rsr a2, interrupt
assert eqi, a2, 0
- movi a2, 0x40
+ movi a2, 1 << XCHAL_TIMER0_INTERRUPT
wsr a2, intenable
rsil a2, 0
loop a3, 1f
@@ -171,7 +171,7 @@ test ccompare_interrupt_masked_waiti
rsr a2, interrupt
assert eqi, a2, 0
- movi a2, 0x40
+ movi a2, 1 << XCHAL_TIMER0_INTERRUPT
wsr a2, intenable
waiti 0
test_fail
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 7/7] target/xtensa: tests: add ccount write tests
2017-01-15 21:10 [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers Max Filippov
` (5 preceding siblings ...)
2017-01-15 21:10 ` [Qemu-devel] [PATCH 6/7] target/xtensa: tests: replace hardcoded interrupt masks Max Filippov
@ 2017-01-15 21:10 ` Max Filippov
6 siblings, 0 replies; 8+ messages in thread
From: Max Filippov @ 2017-01-15 21:10 UTC (permalink / raw)
To: qemu-devel; +Cc: Max Filippov
Check that CCOUNT SR is writable and that CCOMPARE timers are updated
when CCOUNT is written to.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
tests/tcg/xtensa/test_timer.S | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S
index 844c032..6cda71a 100644
--- a/tests/tcg/xtensa/test_timer.S
+++ b/tests/tcg/xtensa/test_timer.S
@@ -19,6 +19,40 @@ test ccount
assert ne, a3, a4
test_end
+test ccount_write
+ rsr a3, ccount
+ rsr a4, ccount
+ sub a4, a4, a3
+ movi a2, 0x12345678
+ wsr a2, ccount
+ esync
+ rsr a3, ccount
+ sub a3, a3, a2
+ slli a4, a4, 2
+ assert ltu, a3, a4
+test_end
+
+test ccount_update_deadline
+ movi a2, 0
+ wsr a2, intenable
+ rsr a2, interrupt
+ wsr a2, intclear
+ movi a2, 0
+ wsr a2, ccompare1
+ wsr a2, ccompare2
+ movi a2, 0x12345678
+ wsr a2, ccompare0
+ rsr a3, interrupt
+ assert eqi, a3, 0
+ movi a2, 0x12345677
+ wsr a2, ccount
+ esync
+ nop
+ rsr a2, interrupt
+ movi a3, 1 << XCHAL_TIMER0_INTERRUPT
+ assert eq, a2, a3
+test_end
+
test ccompare
movi a2, 0
wsr a2, intenable
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2017-01-15 21:11 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-01-15 21:10 [Qemu-devel] [PATCH 0/7] target/xtensa: refactor timers Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 1/7] target/xtensa: refactor CCOUNT/CCOMPARE Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 2/7] target/xtensa: support icount Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 3/7] target/xtensa: don't continue translation after exception Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 4/7] target/xtensa: tests: run tests with icount Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 5/7] target/xtensa: tests: fix timer tests Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 6/7] target/xtensa: tests: replace hardcoded interrupt masks Max Filippov
2017-01-15 21:10 ` [Qemu-devel] [PATCH 7/7] target/xtensa: tests: add ccount write tests Max Filippov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).