int excm_level;
int ndepc;
unsigned inst_fetch_width;
+ unsigned max_insn_size;
uint32_t vecbase;
uint32_t exception_vector[EXC_MAX];
unsigned ninterrupt;
#define XTENSA_TBFLAG_CALLINC_MASK 0x180000
#define XTENSA_TBFLAG_CALLINC_SHIFT 19
+#define XTENSA_CSBASE_LEND_MASK 0x0000ffff
+#define XTENSA_CSBASE_LEND_SHIFT 0
+#define XTENSA_CSBASE_LBEG_OFF_MASK 0x00ff0000
+#define XTENSA_CSBASE_LBEG_OFF_SHIFT 16
+
static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
*flags |= xtensa_get_ring(env);
if (env->sregs[PS] & PS_EXCM) {
*flags |= XTENSA_TBFLAG_EXCM;
+ } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_LOOP)) {
+ target_ulong lend_dist =
+ env->sregs[LEND] - (env->pc & -(1u << TARGET_PAGE_BITS));
+
+ /*
+ * 0 in the csbase_lend field means that there may not be a loopback
+ * for any instruction that starts inside this page. Any other value
+ * means that an instruction that ends at this offset from the page
+ * start may loop back and will need loopback code to be generated.
+ *
+ * lend_dist is 0 when LEND points to the start of the page, but
+ * no instruction that starts inside this page may end at offset 0,
+ * so it's still correct.
+ *
+ * When an instruction ends at a page boundary it may only start in
+ * the previous page. lend_dist will be encoded as TARGET_PAGE_SIZE
+ * for the TB that contains this instruction.
+ */
+ if (lend_dist < (1u << TARGET_PAGE_BITS) + env->config->max_insn_size) {
+ target_ulong lbeg_off = env->sregs[LEND] - env->sregs[LBEG];
+
+ *cs_base = lend_dist;
+ if (lbeg_off < 256) {
+ *cs_base |= lbeg_off << XTENSA_CSBASE_LBEG_OFF_SHIFT;
+ }
+ }
}
if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
(env->sregs[LITBASE] & 1)) {
uint32_t pc;
int cring;
int ring;
- uint32_t lbeg;
+ uint32_t lbeg_off;
uint32_t lend;
bool sar_5bit;
static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
{
TCGv_i32 tmp = tcg_const_i32(dest);
-#ifndef CONFIG_USER_ONLY
if (((dc->base.pc_first ^ dest) & TARGET_PAGE_MASK) != 0) {
slot = -1;
}
-#endif
gen_jump_slot(dc, tmp, slot);
tcg_temp_free(tmp);
}
static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot)
{
TCGv_i32 tmp = tcg_const_i32(dest);
-#ifndef CONFIG_USER_ONLY
if (((dc->base.pc_first ^ dest) & TARGET_PAGE_MASK) != 0) {
slot = -1;
}
-#endif
gen_callw_slot(dc, callinc, tmp, slot);
tcg_temp_free(tmp);
}
static bool gen_check_loop_end(DisasContext *dc, int slot)
{
- if (option_enabled(dc, XTENSA_OPTION_LOOP) &&
- !(dc->base.tb->flags & XTENSA_TBFLAG_EXCM) &&
- dc->base.pc_next == dc->lend) {
+ if (dc->base.pc_next == dc->lend) {
TCGLabel *label = gen_new_label();
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);
+ if (dc->lbeg_off) {
+ gen_jumpi(dc, dc->base.pc_next - dc->lbeg_off, slot);
+ } else {
+ gen_jump(dc, cpu_SR[LBEG]);
+ }
gen_set_label(label);
gen_jumpi(dc, dc->base.pc_next, -1);
return true;
}
}
-static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
-{
- gen_helper_wsr_lbeg(cpu_env, s);
-}
-
-static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
-{
- gen_helper_wsr_lend(cpu_env, s);
-}
-
static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
{
static void (* const wsr_handler[256])(DisasContext *dc,
uint32_t sr, TCGv_i32 v) = {
- [LBEG] = gen_wsr_lbeg,
- [LEND] = gen_wsr_lend,
[SAR] = gen_wsr_sar,
[BR] = gen_wsr_br,
[LITBASE] = gen_wsr_litbase,
}
dc->base.pc_next = dc->pc + len;
- if (xtensa_option_enabled(dc->config, XTENSA_OPTION_LOOP) &&
- dc->lbeg == dc->pc &&
- ((dc->pc ^ (dc->base.pc_next - 1)) & -dc->config->inst_fetch_width)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "unaligned first instruction of a loop (pc = %08x)\n",
- dc->pc);
- }
for (i = 1; i < len; ++i) {
b[i] = cpu_ldub_code(env, dc->pc + i);
}
dc->pc = dc->base.pc_first;
dc->ring = tb_flags & XTENSA_TBFLAG_RING_MASK;
dc->cring = (tb_flags & XTENSA_TBFLAG_EXCM) ? 0 : dc->ring;
- dc->lbeg = env->sregs[LBEG];
- dc->lend = env->sregs[LEND];
+ dc->lbeg_off = (dc->base.tb->cs_base & XTENSA_CSBASE_LBEG_OFF_MASK) >>
+ XTENSA_CSBASE_LBEG_OFF_SHIFT;
+ dc->lend = (dc->base.tb->cs_base & XTENSA_CSBASE_LEND_MASK) +
+ (dc->base.pc_first & TARGET_PAGE_MASK);
dc->debug = tb_flags & XTENSA_TBFLAG_DEBUG;
dc->icount = tb_flags & XTENSA_TBFLAG_ICOUNT;
dc->cpenable = (tb_flags & XTENSA_TBFLAG_CPENABLE_MASK) >>
const uint32_t par[])
{
uint32_t lend = arg[1];
- TCGv_i32 tmp = tcg_const_i32(lend);
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[arg[0]], 1);
tcg_gen_movi_i32(cpu_SR[LBEG], dc->base.pc_next);
- gen_helper_wsr_lend(cpu_env, tmp);
- tcg_temp_free(tmp);
+ tcg_gen_movi_i32(cpu_SR[LEND], lend);
if (par[0] != TCG_COND_NEVER) {
TCGLabel *label = gen_new_label();
.translate = translate_wsr,
.test_ill = test_ill_wsr,
.par = (const uint32_t[]){LBEG},
- .op_flags = XTENSA_OP_EXIT_TB_0,
+ .op_flags = XTENSA_OP_EXIT_TB_M1,
.windowed_register_op = 0x1,
}, {
.name = "wsr.lcount",
.translate = translate_wsr,
.test_ill = test_ill_wsr,
.par = (const uint32_t[]){LEND},
- .op_flags = XTENSA_OP_EXIT_TB_0,
+ .op_flags = XTENSA_OP_EXIT_TB_M1,
.windowed_register_op = 0x1,
}, {
.name = "wsr.litbase",
.translate = translate_xsr,
.test_ill = test_ill_xsr,
.par = (const uint32_t[]){LBEG},
- .op_flags = XTENSA_OP_EXIT_TB_0,
+ .op_flags = XTENSA_OP_EXIT_TB_M1,
.windowed_register_op = 0x1,
}, {
.name = "xsr.lcount",
.translate = translate_xsr,
.test_ill = test_ill_xsr,
.par = (const uint32_t[]){LEND},
- .op_flags = XTENSA_OP_EXIT_TB_0,
+ .op_flags = XTENSA_OP_EXIT_TB_M1,
.windowed_register_op = 0x1,
}, {
.name = "xsr.litbase",