aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-xtensa/cpu.h12
-rw-r--r--target-xtensa/helper.h2
-rw-r--r--target-xtensa/op_helper.c29
-rw-r--r--target-xtensa/translate.c61
4 files changed, 42 insertions, 62 deletions
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index ac463f27fe..a1bfbf7acf 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -497,6 +497,8 @@ static inline int cpu_mmu_index(CPUXtensaState *env)
#define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0
#define XTENSA_TBFLAG_CPENABLE_SHIFT 6
#define XTENSA_TBFLAG_EXCEPTION 0x4000
+#define XTENSA_TBFLAG_WINDOW_MASK 0x18000
+#define XTENSA_TBFLAG_WINDOW_SHIFT 15
static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
@@ -528,6 +530,16 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
if (cs->singlestep_enabled && env->exception_taken) {
*flags |= XTENSA_TBFLAG_EXCEPTION;
}
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER) &&
+ (env->sregs[PS] & (PS_WOE | PS_EXCM)) == PS_WOE) {
+ uint32_t windowstart = xtensa_replicate_windowstart(env) >>
+ (env->sregs[WINDOW_BASE] + 1);
+ uint32_t w = ctz32(windowstart | 0x8);
+
+ *flags |= w << XTENSA_TBFLAG_WINDOW_SHIFT;
+ } else {
+ *flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT;
+ }
}
#include "exec/cpu-all.h"
diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h
index ed3af0b737..5ea9c5beec 100644
--- a/target-xtensa/helper.h
+++ b/target-xtensa/helper.h
@@ -9,7 +9,7 @@ DEF_HELPER_2(wsr_windowbase, void, env, i32)
DEF_HELPER_4(entry, void, env, i32, i32, i32)
DEF_HELPER_2(retw, i32, env, i32)
DEF_HELPER_2(rotw, void, env, i32)
-DEF_HELPER_3(window_check, void, env, i32, i32)
+DEF_HELPER_3(window_check, noreturn, env, i32, i32)
DEF_HELPER_1(restore_owb, void, env)
DEF_HELPER_2(movsp, void, env, i32)
DEF_HELPER_2(wsr_lbeg, void, env, i32)
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 872e5a823b..49e86343ed 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -251,34 +251,27 @@ void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
{
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
- uint32_t windowstart = env->sregs[WINDOW_START];
- uint32_t m, n;
+ uint32_t windowstart = xtensa_replicate_windowstart(env) >>
+ (env->sregs[WINDOW_BASE] + 1);
+ uint32_t n = ctz32(windowstart) + 1;
- if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
- return;
- }
+ assert(n <= w);
- for (n = 1; ; ++n) {
- if (n > w) {
- return;
- }
- if (windowstart & windowstart_bit(windowbase + n, env)) {
- break;
- }
- }
-
- m = windowbase_bound(windowbase + n, env);
rotate_window(env, n);
env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
(windowbase << PS_OWB_SHIFT) | PS_EXCM;
env->sregs[EPC1] = env->pc = pc;
- if (windowstart & windowstart_bit(m + 1, env)) {
+ switch (ctz32(windowstart >> n)) {
+ case 0:
HELPER(exception)(env, EXC_WINDOW_OVERFLOW4);
- } else if (windowstart & windowstart_bit(m + 2, env)) {
+ break;
+ case 1:
HELPER(exception)(env, EXC_WINDOW_OVERFLOW8);
- } else {
+ break;
+ default:
HELPER(exception)(env, EXC_WINDOW_OVERFLOW12);
+ break;
}
}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index a81573def6..013e6127be 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -63,7 +63,7 @@ typedef struct DisasContext {
TCGv_i32 sar_m32;
uint32_t ccount_delta;
- unsigned used_window;
+ unsigned window;
bool debug;
bool icount;
@@ -311,26 +311,16 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
tcg_temp_free(tmp);
}
-static void gen_advance_ccount_cond(DisasContext *dc)
+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);
}
-}
-
-static void gen_advance_ccount(DisasContext *dc)
-{
- gen_advance_ccount_cond(dc);
dc->ccount_delta = 0;
}
-static void reset_used_window(DisasContext *dc)
-{
- dc->used_window = 0;
-}
-
static void gen_exception(DisasContext *dc, int excp)
{
TCGv_i32 tmp = tcg_const_i32(excp);
@@ -597,13 +587,15 @@ static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s)
static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
gen_helper_wsr_windowbase(cpu_env, v);
- reset_used_window(dc);
+ /* This can change tb->flags, so exit tb */
+ gen_jumpi_check_loop_end(dc, -1);
}
static void 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);
- reset_used_window(dc);
+ /* This can change tb->flags, so exit tb */
+ gen_jumpi_check_loop_end(dc, -1);
}
static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v)
@@ -712,7 +704,6 @@ 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);
- reset_used_window(dc);
gen_helper_check_interrupts(cpu_env);
/* This can change mmu index and tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
@@ -835,32 +826,13 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4)
static void gen_window_check1(DisasContext *dc, unsigned r1)
{
- if (dc->tb->flags & XTENSA_TBFLAG_EXCM) {
- return;
- }
- if (option_enabled(dc, XTENSA_OPTION_WINDOWED_REGISTER) &&
- r1 / 4 > dc->used_window) {
- int label = gen_new_label();
- TCGv_i32 ws = tcg_temp_new_i32();
-
- dc->used_window = r1 / 4;
- tcg_gen_deposit_i32(ws, cpu_SR[WINDOW_START], cpu_SR[WINDOW_START],
- dc->config->nareg / 4, dc->config->nareg / 4);
- tcg_gen_shr_i32(ws, ws, cpu_SR[WINDOW_BASE]);
- tcg_gen_andi_i32(ws, ws, (2 << (r1 / 4)) - 2);
- tcg_gen_brcondi_i32(TCG_COND_EQ, ws, 0, label);
- {
- TCGv_i32 pc = tcg_const_i32(dc->pc);
- TCGv_i32 w = tcg_const_i32(r1 / 4);
-
- gen_advance_ccount_cond(dc);
- gen_helper_window_check(cpu_env, pc, w);
+ if (r1 / 4 > dc->window) {
+ TCGv_i32 pc = tcg_const_i32(dc->pc);
+ TCGv_i32 w = tcg_const_i32(r1 / 4);
- tcg_temp_free(w);
- tcg_temp_free(pc);
- }
- gen_set_label(label);
- tcg_temp_free(ws);
+ gen_advance_ccount(dc);
+ gen_helper_window_check(cpu_env, pc, w);
+ dc->is_jmp = DISAS_UPDATE;
}
}
@@ -1370,7 +1342,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
gen_helper_rotw(cpu_env, tmp);
tcg_temp_free(tmp);
- reset_used_window(dc);
+ /* This can change tb->flags, so exit tb */
+ gen_jumpi_check_loop_end(dc, -1);
}
break;
@@ -2700,7 +2673,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
tcg_temp_free(imm);
tcg_temp_free(s);
tcg_temp_free(pc);
- reset_used_window(dc);
+ /* This can change tb->flags, so exit tb */
+ gen_jumpi_check_loop_end(dc, -1);
}
break;
@@ -3029,10 +3003,11 @@ void gen_intermediate_code_internal(XtensaCPU *cpu,
dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT;
dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >>
XTENSA_TBFLAG_CPENABLE_SHIFT;
+ dc.window = ((tb->flags & XTENSA_TBFLAG_WINDOW_MASK) >>
+ XTENSA_TBFLAG_WINDOW_SHIFT);
init_litbase(&dc);
init_sar_tracker(&dc);
- reset_used_window(&dc);
if (dc.icount) {
dc.next_icount = tcg_temp_local_new_i32();
}