target-xtensa: record available window in TB flags
Record last valid 4-register window pane number in TB flags so that a window overflow exception throw point is known at the translation time. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
85d36377e4
commit
2db59a76c4
@ -497,6 +497,8 @@ static inline int cpu_mmu_index(CPUXtensaState *env)
|
|||||||
#define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0
|
#define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0
|
||||||
#define XTENSA_TBFLAG_CPENABLE_SHIFT 6
|
#define XTENSA_TBFLAG_CPENABLE_SHIFT 6
|
||||||
#define XTENSA_TBFLAG_EXCEPTION 0x4000
|
#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,
|
static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
|
||||||
target_ulong *cs_base, int *flags)
|
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) {
|
if (cs->singlestep_enabled && env->exception_taken) {
|
||||||
*flags |= XTENSA_TBFLAG_EXCEPTION;
|
*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"
|
#include "exec/cpu-all.h"
|
||||||
|
@ -9,7 +9,7 @@ DEF_HELPER_2(wsr_windowbase, void, env, i32)
|
|||||||
DEF_HELPER_4(entry, void, env, i32, i32, i32)
|
DEF_HELPER_4(entry, void, env, i32, i32, i32)
|
||||||
DEF_HELPER_2(retw, i32, env, i32)
|
DEF_HELPER_2(retw, i32, env, i32)
|
||||||
DEF_HELPER_2(rotw, void, 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_1(restore_owb, void, env)
|
||||||
DEF_HELPER_2(movsp, void, env, i32)
|
DEF_HELPER_2(movsp, void, env, i32)
|
||||||
DEF_HELPER_2(wsr_lbeg, void, env, i32)
|
DEF_HELPER_2(wsr_lbeg, void, env, i32)
|
||||||
|
@ -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)
|
void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
|
||||||
{
|
{
|
||||||
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
|
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
|
||||||
uint32_t windowstart = env->sregs[WINDOW_START];
|
uint32_t windowstart = xtensa_replicate_windowstart(env) >>
|
||||||
uint32_t m, n;
|
(env->sregs[WINDOW_BASE] + 1);
|
||||||
|
uint32_t n = ctz32(windowstart) + 1;
|
||||||
|
|
||||||
if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
|
assert(n <= w);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
rotate_window(env, n);
|
||||||
env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
|
env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
|
||||||
(windowbase << PS_OWB_SHIFT) | PS_EXCM;
|
(windowbase << PS_OWB_SHIFT) | PS_EXCM;
|
||||||
env->sregs[EPC1] = env->pc = pc;
|
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);
|
HELPER(exception)(env, EXC_WINDOW_OVERFLOW4);
|
||||||
} else if (windowstart & windowstart_bit(m + 2, env)) {
|
break;
|
||||||
|
case 1:
|
||||||
HELPER(exception)(env, EXC_WINDOW_OVERFLOW8);
|
HELPER(exception)(env, EXC_WINDOW_OVERFLOW8);
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
HELPER(exception)(env, EXC_WINDOW_OVERFLOW12);
|
HELPER(exception)(env, EXC_WINDOW_OVERFLOW12);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ typedef struct DisasContext {
|
|||||||
TCGv_i32 sar_m32;
|
TCGv_i32 sar_m32;
|
||||||
|
|
||||||
uint32_t ccount_delta;
|
uint32_t ccount_delta;
|
||||||
unsigned used_window;
|
unsigned window;
|
||||||
|
|
||||||
bool debug;
|
bool debug;
|
||||||
bool icount;
|
bool icount;
|
||||||
@ -311,26 +311,16 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
|
|||||||
tcg_temp_free(tmp);
|
tcg_temp_free(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_advance_ccount_cond(DisasContext *dc)
|
static void gen_advance_ccount(DisasContext *dc)
|
||||||
{
|
{
|
||||||
if (dc->ccount_delta > 0) {
|
if (dc->ccount_delta > 0) {
|
||||||
TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
|
TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
|
||||||
gen_helper_advance_ccount(cpu_env, tmp);
|
gen_helper_advance_ccount(cpu_env, tmp);
|
||||||
tcg_temp_free(tmp);
|
tcg_temp_free(tmp);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void gen_advance_ccount(DisasContext *dc)
|
|
||||||
{
|
|
||||||
gen_advance_ccount_cond(dc);
|
|
||||||
dc->ccount_delta = 0;
|
dc->ccount_delta = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset_used_window(DisasContext *dc)
|
|
||||||
{
|
|
||||||
dc->used_window = 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);
|
||||||
@ -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)
|
static void 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);
|
||||||
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)
|
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);
|
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)
|
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;
|
mask |= PS_RING;
|
||||||
}
|
}
|
||||||
tcg_gen_andi_i32(cpu_SR[sr], v, mask);
|
tcg_gen_andi_i32(cpu_SR[sr], v, mask);
|
||||||
reset_used_window(dc);
|
|
||||||
gen_helper_check_interrupts(cpu_env);
|
gen_helper_check_interrupts(cpu_env);
|
||||||
/* 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);
|
||||||
@ -835,32 +826,13 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4)
|
|||||||
|
|
||||||
static void gen_window_check1(DisasContext *dc, unsigned r1)
|
static void gen_window_check1(DisasContext *dc, unsigned r1)
|
||||||
{
|
{
|
||||||
if (dc->tb->flags & XTENSA_TBFLAG_EXCM) {
|
if (r1 / 4 > dc->window) {
|
||||||
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 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_cond(dc);
|
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;
|
||||||
tcg_temp_free(w);
|
|
||||||
tcg_temp_free(pc);
|
|
||||||
}
|
|
||||||
gen_set_label(label);
|
|
||||||
tcg_temp_free(ws);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1370,7 +1342,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
|
|||||||
RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
|
RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
|
||||||
gen_helper_rotw(cpu_env, tmp);
|
gen_helper_rotw(cpu_env, tmp);
|
||||||
tcg_temp_free(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;
|
break;
|
||||||
|
|
||||||
@ -2700,7 +2673,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
|
|||||||
tcg_temp_free(imm);
|
tcg_temp_free(imm);
|
||||||
tcg_temp_free(s);
|
tcg_temp_free(s);
|
||||||
tcg_temp_free(pc);
|
tcg_temp_free(pc);
|
||||||
reset_used_window(dc);
|
/* This can change tb->flags, so exit tb */
|
||||||
|
gen_jumpi_check_loop_end(dc, -1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3029,10 +3003,11 @@ void gen_intermediate_code_internal(XtensaCPU *cpu,
|
|||||||
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) >>
|
||||||
XTENSA_TBFLAG_CPENABLE_SHIFT;
|
XTENSA_TBFLAG_CPENABLE_SHIFT;
|
||||||
|
dc.window = ((tb->flags & XTENSA_TBFLAG_WINDOW_MASK) >>
|
||||||
|
XTENSA_TBFLAG_WINDOW_SHIFT);
|
||||||
|
|
||||||
init_litbase(&dc);
|
init_litbase(&dc);
|
||||||
init_sar_tracker(&dc);
|
init_sar_tracker(&dc);
|
||||||
reset_used_window(&dc);
|
|
||||||
if (dc.icount) {
|
if (dc.icount) {
|
||||||
dc.next_icount = tcg_temp_local_new_i32();
|
dc.next_icount = tcg_temp_local_new_i32();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user