summaryrefslogtreecommitdiff
path: root/target-xtensa/translate.c
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2011-09-06 03:55:43 +0400
committerBlue Swirl <blauwirbel@gmail.com>2011-09-10 16:57:39 +0000
commit553e44f90645b7f2fc9cec7583844e24cd86019f (patch)
treeb39a447017c7d89faf541939c7b99c7ca65ebb05 /target-xtensa/translate.c
parentf76ebf55cd971c82e867fea97741e48d2f14499d (diff)
downloadqemu-553e44f90645b7f2fc9cec7583844e24cd86019f.tar.gz
target-xtensa: implement windowed registers
See ISA, 4.7.1 for details. Physical registers and currently visible window are separate fields in CPUEnv. Only current window is accessible to TCG. On operations that change window base helpers copy current window to and from physical registers. Window overflow check described in 4.7.1.3 is in separate patch. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'target-xtensa/translate.c')
-rw-r--r--target-xtensa/translate.c145
1 files changed, 136 insertions, 9 deletions
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index bc04a108b9..7a2e07ff60 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -67,6 +67,8 @@ static TCGv_i32 cpu_UR[256];
static const char * const sregnames[256] = {
[SAR] = "SAR",
[SCOMPARE1] = "SCOMPARE1",
+ [WINDOW_BASE] = "WINDOW_BASE",
+ [WINDOW_START] = "WINDOW_START",
[EPC1] = "EPC1",
[DEPC] = "DEPC",
[EXCSAVE1] = "EXCSAVE1",
@@ -217,6 +219,34 @@ static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
tcg_temp_free(tmp);
}
+static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest,
+ int slot)
+{
+ TCGv_i32 tcallinc = tcg_const_i32(callinc);
+
+ tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS],
+ tcallinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN);
+ tcg_temp_free(tcallinc);
+ tcg_gen_movi_i32(cpu_R[callinc << 2],
+ (callinc << 30) | (dc->next_pc & 0x3fffffff));
+ gen_jump_slot(dc, dest, slot);
+}
+
+static void gen_callw(DisasContext *dc, int callinc, TCGv_i32 dest)
+{
+ gen_callw_slot(dc, callinc, dest, -1);
+}
+
+static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot)
+{
+ TCGv_i32 tmp = tcg_const_i32(dest);
+ if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+ slot = -1;
+ }
+ gen_callw_slot(dc, callinc, tmp, slot);
+ tcg_temp_free(tmp);
+}
+
static void gen_brcond(DisasContext *dc, TCGCond cond,
TCGv_i32 t0, TCGv_i32 t1, uint32_t offset)
{
@@ -263,6 +293,11 @@ static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
dc->sar_m32_5bit = false;
}
+static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+ gen_helper_wsr_windowbase(v);
+}
+
static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
@@ -281,6 +316,7 @@ 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) = {
[SAR] = gen_wsr_sar,
+ [WINDOW_BASE] = gen_wsr_windowbase,
[PS] = gen_wsr_ps,
};
@@ -429,7 +465,12 @@ static void disas_xtensa_insn(DisasContext *dc)
case 1: /*RETWw*/
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
- TBD();
+ {
+ TCGv_i32 tmp = tcg_const_i32(dc->pc);
+ gen_helper_retw(tmp, tmp);
+ gen_jump(dc, tmp);
+ tcg_temp_free(tmp);
+ }
break;
case 3: /*reserved*/
@@ -454,7 +495,13 @@ static void disas_xtensa_insn(DisasContext *dc)
case 2: /*CALLX8w*/
case 3: /*CALLX12w*/
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
- TBD();
+ {
+ TCGv_i32 tmp = tcg_temp_new_i32();
+
+ tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]);
+ gen_callw(dc, CALLX_N, tmp);
+ tcg_temp_free(tmp);
+ }
break;
}
break;
@@ -463,7 +510,12 @@ static void disas_xtensa_insn(DisasContext *dc)
case 1: /*MOVSPw*/
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
- TBD();
+ {
+ TCGv_i32 pc = tcg_const_i32(dc->pc);
+ gen_helper_movsp(pc);
+ tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
+ tcg_temp_free(pc);
+ }
break;
case 2: /*SYNC*/
@@ -523,7 +575,27 @@ static void disas_xtensa_insn(DisasContext *dc)
case 4: /*RFWOw*/
case 5: /*RFWUw*/
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
- TBD();
+ gen_check_privilege(dc);
+ {
+ TCGv_i32 tmp = tcg_const_i32(1);
+
+ tcg_gen_andi_i32(
+ cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+ tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]);
+
+ if (RRR_S == 4) {
+ tcg_gen_andc_i32(cpu_SR[WINDOW_START],
+ cpu_SR[WINDOW_START], tmp);
+ } else {
+ tcg_gen_or_i32(cpu_SR[WINDOW_START],
+ cpu_SR[WINDOW_START], tmp);
+ }
+
+ gen_helper_restore_owb();
+ gen_jump(dc, cpu_SR[EPC1]);
+
+ tcg_temp_free(tmp);
+ }
break;
default: /*reserved*/
@@ -670,7 +742,13 @@ static void disas_xtensa_insn(DisasContext *dc)
case 8: /*ROTWw*/
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
- TBD();
+ gen_check_privilege(dc);
+ {
+ TCGv_i32 tmp = tcg_const_i32(
+ RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
+ gen_helper_rotw(tmp);
+ tcg_temp_free(tmp);
+ }
break;
case 14: /*NSAu*/
@@ -1129,7 +1207,35 @@ static void disas_xtensa_insn(DisasContext *dc)
break;
case 9: /*LSC4*/
- TBD();
+ switch (OP2) {
+ case 0: /*L32E*/
+ HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+ gen_check_privilege(dc);
+ {
+ TCGv_i32 addr = tcg_temp_new_i32();
+ tcg_gen_addi_i32(addr, cpu_R[RRR_S],
+ (0xffffffc0 | (RRR_R << 2)));
+ tcg_gen_qemu_ld32u(cpu_R[RRR_T], addr, dc->ring);
+ tcg_temp_free(addr);
+ }
+ break;
+
+ case 4: /*S32E*/
+ HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+ gen_check_privilege(dc);
+ {
+ TCGv_i32 addr = tcg_temp_new_i32();
+ tcg_gen_addi_i32(addr, cpu_R[RRR_S],
+ (0xffffffc0 | (RRR_R << 2)));
+ tcg_gen_qemu_st32(cpu_R[RRR_T], addr, dc->ring);
+ tcg_temp_free(addr);
+ }
+ break;
+
+ default:
+ RESERVED();
+ break;
+ }
break;
case 10: /*FP0*/
@@ -1368,7 +1474,8 @@ static void disas_xtensa_insn(DisasContext *dc)
case 2: /*CALL8w*/
case 3: /*CALL12w*/
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
- TBD();
+ gen_callwi(dc, CALL_N,
+ (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
break;
}
break;
@@ -1411,7 +1518,15 @@ static void disas_xtensa_insn(DisasContext *dc)
switch (BRI8_M) {
case 0: /*ENTRYw*/
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
- TBD();
+ {
+ 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_helper_entry(pc, s, imm);
+ tcg_temp_free(imm);
+ tcg_temp_free(s);
+ tcg_temp_free(pc);
+ }
break;
case 1: /*B1*/
@@ -1576,7 +1691,12 @@ static void disas_xtensa_insn(DisasContext *dc)
case 1: /*RETW.Nn*/
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
- TBD();
+ {
+ TCGv_i32 tmp = tcg_const_i32(dc->pc);
+ gen_helper_retw(tmp, tmp);
+ gen_jump(dc, tmp);
+ tcg_temp_free(tmp);
+ }
break;
case 2: /*BREAK.Nn*/
@@ -1750,6 +1870,13 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i],
(i % 4) == 3 ? '\n' : ' ');
}
+
+ cpu_fprintf(f, "\n");
+
+ for (i = 0; i < env->config->nareg; ++i) {
+ cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i],
+ (i % 4) == 3 ? '\n' : ' ');
+ }
}
void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)