summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-xtensa/cpu.h3
-rw-r--r--target-xtensa/helpers.h2
-rw-r--r--target-xtensa/op_helper.c20
-rw-r--r--target-xtensa/translate.c77
4 files changed, 93 insertions, 9 deletions
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 7e662f5402..97badf26c8 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -106,6 +106,9 @@ enum {
};
enum {
+ LBEG = 0,
+ LEND = 1,
+ LCOUNT = 2,
SAR = 3,
SCOMPARE1 = 12,
WINDOW_BASE = 72,
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index 0971fde8da..b318c5a82c 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -12,6 +12,8 @@ DEF_HELPER_1(rotw, void, i32)
DEF_HELPER_2(window_check, void, i32, i32)
DEF_HELPER_0(restore_owb, void)
DEF_HELPER_1(movsp, void, i32)
+DEF_HELPER_1(wsr_lbeg, void, i32)
+DEF_HELPER_1(wsr_lend, void, i32)
DEF_HELPER_0(dump_state, void)
#include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 7c3fb88a96..5e0f56f6da 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -288,6 +288,26 @@ void HELPER(movsp)(uint32_t pc)
}
}
+void HELPER(wsr_lbeg)(uint32_t v)
+{
+ if (env->sregs[LBEG] != v) {
+ tb_invalidate_phys_page_range(
+ env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ env->sregs[LBEG] = v;
+ }
+}
+
+void HELPER(wsr_lend)(uint32_t v)
+{
+ if (env->sregs[LEND] != v) {
+ tb_invalidate_phys_page_range(
+ env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ env->sregs[LEND] = v;
+ tb_invalidate_phys_page_range(
+ env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ }
+}
+
void HELPER(dump_state)(void)
{
cpu_dump_state(env, stderr, fprintf, 0);
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 7a2e07ff60..8f4500750c 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -47,6 +47,8 @@ typedef struct DisasContext {
uint32_t next_pc;
int cring;
int ring;
+ uint32_t lbeg;
+ uint32_t lend;
int is_jmp;
int singlestep_enabled;
@@ -65,6 +67,9 @@ static TCGv_i32 cpu_UR[256];
#include "gen-icount.h"
static const char * const sregnames[256] = {
+ [LBEG] = "LBEG",
+ [LEND] = "LEND",
+ [LCOUNT] = "LCOUNT",
[SAR] = "SAR",
[SCOMPARE1] = "SCOMPARE1",
[WINDOW_BASE] = "WINDOW_BASE",
@@ -247,13 +252,37 @@ static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot)
tcg_temp_free(tmp);
}
+static bool gen_check_loop_end(DisasContext *dc, int slot)
+{
+ if (option_enabled(dc, XTENSA_OPTION_LOOP) &&
+ !(dc->tb->flags & XTENSA_TBFLAG_EXCM) &&
+ dc->next_pc == dc->lend) {
+ int 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);
+ gen_set_label(label);
+ gen_jumpi(dc, dc->next_pc, -1);
+ return true;
+ }
+ return false;
+}
+
+static void gen_jumpi_check_loop_end(DisasContext *dc, int slot)
+{
+ if (!gen_check_loop_end(dc, slot)) {
+ gen_jumpi(dc, dc->next_pc, slot);
+ }
+}
+
static void gen_brcond(DisasContext *dc, TCGCond cond,
TCGv_i32 t0, TCGv_i32 t1, uint32_t offset)
{
int label = gen_new_label();
tcg_gen_brcond_i32(cond, t0, t1, label);
- gen_jumpi(dc, dc->next_pc, 0);
+ gen_jumpi_check_loop_end(dc, 0);
gen_set_label(label);
gen_jumpi(dc, dc->pc + offset, 1);
}
@@ -283,6 +312,16 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
}
}
+static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+ gen_helper_wsr_lbeg(s);
+}
+
+static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+ gen_helper_wsr_lend(s);
+}
+
static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
@@ -308,13 +347,15 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
}
tcg_gen_andi_i32(cpu_SR[sr], v, mask);
/* This can change mmu index, so exit tb */
- gen_jumpi(dc, dc->next_pc, -1);
+ gen_jumpi_check_loop_end(dc, -1);
}
static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
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,
[WINDOW_BASE] = gen_wsr_windowbase,
[PS] = gen_wsr_ps,
@@ -1542,15 +1583,29 @@ static void disas_xtensa_insn(DisasContext *dc)
break;
case 8: /*LOOP*/
- TBD();
- break;
-
case 9: /*LOOPNEZ*/
- TBD();
- break;
-
case 10: /*LOOPGTZ*/
- TBD();
+ HAS_OPTION(XTENSA_OPTION_LOOP);
+ {
+ uint32_t lend = dc->pc + RRI8_IMM8 + 4;
+ TCGv_i32 tmp = tcg_const_i32(lend);
+
+ tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1);
+ tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc);
+ gen_wsr_lend(dc, LEND, tmp);
+ tcg_temp_free(tmp);
+
+ if (BRI8_R > 8) {
+ int label = gen_new_label();
+ tcg_gen_brcondi_i32(
+ BRI8_R == 9 ? TCG_COND_NE : TCG_COND_GT,
+ cpu_R[RRI8_S], 0, label);
+ gen_jumpi(dc, lend, 1);
+ gen_set_label(label);
+ }
+
+ gen_jumpi(dc, dc->next_pc, 0);
+ }
break;
default: /*reserved*/
@@ -1727,7 +1782,9 @@ static void disas_xtensa_insn(DisasContext *dc)
break;
}
+ gen_check_loop_end(dc, 0);
dc->pc = dc->next_pc;
+
return;
invalid_opcode:
@@ -1773,6 +1830,8 @@ static void gen_intermediate_code_internal(
dc.pc = pc_start;
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.is_jmp = DISAS_NEXT;
init_sar_tracker(&dc);