On Thu, Sep 1, 2011 at 8:45 PM, Max Filippov <jcmvb...@gmail.com> wrote: > 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 <jcmvb...@gmail.com> > --- > target-xtensa/cpu.h | 8 ++ > target-xtensa/helper.c | 1 + > target-xtensa/helpers.h | 8 ++ > target-xtensa/op_helper.c | 185 > +++++++++++++++++++++++++++++++++++++++++++++ > target-xtensa/translate.c | 144 +++++++++++++++++++++++++++++++++-- > 5 files changed, 337 insertions(+), 9 deletions(-) > > diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h > index cae6637..7e662f5 100644 > --- a/target-xtensa/cpu.h > +++ b/target-xtensa/cpu.h > @@ -108,6 +108,8 @@ enum { > enum { > SAR = 3, > SCOMPARE1 = 12, > + WINDOW_BASE = 72, > + WINDOW_START = 73, > EPC1 = 177, > DEPC = 192, > EXCSAVE1 = 209, > @@ -134,6 +136,8 @@ enum { > > #define PS_WOE 0x40000 > > +#define MAX_NAREG 64 > + > enum { > /* Static vectors */ > EXC_RESET, > @@ -185,6 +189,7 @@ enum { > typedef struct XtensaConfig { > const char *name; > uint64_t options; > + unsigned nareg; > int excm_level; > int ndepc; > uint32_t exception_vector[EXC_MAX]; > @@ -196,6 +201,7 @@ typedef struct CPUXtensaState { > uint32_t pc; > uint32_t sregs[256]; > uint32_t uregs[256]; > + uint32_t phys_regs[MAX_NAREG]; > > int exception_taken; > > @@ -214,6 +220,8 @@ int cpu_xtensa_exec(CPUXtensaState *s); > void do_interrupt(CPUXtensaState *s); > int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc); > void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf); > +void xtensa_sync_window_from_phys(CPUState *env); > +void xtensa_sync_phys_from_window(CPUState *env); > > #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) > > diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c > index 44ebb9f..4f86934 100644 > --- a/target-xtensa/helper.c > +++ b/target-xtensa/helper.c > @@ -45,6 +45,7 @@ static const XtensaConfig core_config[] = { > { > .name = "sample-xtensa-core", > .options = -1, > + .nareg = 64, > .ndepc = 1, > .excm_level = 16, > .exception_vector = { > diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h > index 6329c43..0971fde 100644 > --- a/target-xtensa/helpers.h > +++ b/target-xtensa/helpers.h > @@ -5,5 +5,13 @@ DEF_HELPER_2(exception_cause, void, i32, i32) > DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32) > DEF_HELPER_1(nsa, i32, i32) > DEF_HELPER_1(nsau, i32, i32) > +DEF_HELPER_1(wsr_windowbase, void, i32) > +DEF_HELPER_3(entry, void, i32, i32, i32) > +DEF_HELPER_1(retw, i32, i32) > +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_0(dump_state, void) > > #include "def-helper.h" > diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c > index 794a834..7f75422 100644 > --- a/target-xtensa/op_helper.c > +++ b/target-xtensa/op_helper.c > @@ -100,3 +100,188 @@ uint32_t HELPER(nsau)(uint32_t v) > { > return v ? clz32(v) : 32; > } > + > +static void copy_window_from_phys(CPUState *env, > + uint32_t window, uint32_t phys, uint32_t n) > +{ > + assert(phys < env->config->nareg); > + if (phys + n <= env->config->nareg) { > + memcpy(env->regs + window, env->phys_regs + phys, > + n * sizeof(uint32_t)); > + } else { > + uint32_t n1 = env->config->nareg - phys; > + memcpy(env->regs + window, env->phys_regs + phys, > + n1 * sizeof(uint32_t)); > + memcpy(env->regs + window + n1, env->phys_regs, > + (n - n1) * sizeof(uint32_t)); > + } > +} > + > +static void copy_phys_from_window(CPUState *env, > + uint32_t phys, uint32_t window, uint32_t n) > +{ > + assert(phys < env->config->nareg); > + if (phys + n <= env->config->nareg) { > + memcpy(env->phys_regs + phys, env->regs + window, > + n * sizeof(uint32_t)); > + } else { > + uint32_t n1 = env->config->nareg - phys; > + memcpy(env->phys_regs + phys, env->regs + window, > + n1 * sizeof(uint32_t)); > + memcpy(env->phys_regs, env->regs + window + n1, > + (n - n1) * sizeof(uint32_t)); > + } > +} > + > + > +#define WINDOWBASE_BOUND(a) ((a) & (env->config->nareg / 4 - 1)) > +#define WINDOW_BOUND(a) ((a) & (env->config->nareg - 1))
'env' could be a parameter to the macro, though inline functions are preferred over macros these days. > +#define WINDOWSTART_BIT(a) (1 << WINDOWBASE_BOUND(a)) > + > +void xtensa_sync_window_from_phys(CPUState *env) > +{ > + copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16); > +} > + > +void xtensa_sync_phys_from_window(CPUState *env) > +{ > + copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16); > +} > + > +static void rotate_window_abs(uint32_t position) > +{ > + xtensa_sync_phys_from_window(env); > + env->sregs[WINDOW_BASE] = WINDOWBASE_BOUND(position); > + xtensa_sync_window_from_phys(env); > +} > + > +static void rotate_window(uint32_t delta) > +{ > + rotate_window_abs(env->sregs[WINDOW_BASE] + delta); > +} > + > +void HELPER(wsr_windowbase)(uint32_t v) > +{ > + rotate_window_abs(v); > +} > + > +void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm) > +{ > + int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT; > + if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) { > + qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n", > + pc, env->sregs[PS]); > + HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE); > + } else { > + env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3); > + rotate_window(callinc); > + env->sregs[WINDOW_START] |= WINDOWSTART_BIT(env->sregs[WINDOW_BASE]); > + } > +} > + > +void HELPER(window_check)(uint32_t pc, uint32_t w) > +{ > + uint32_t windowbase = WINDOWBASE_BOUND(env->sregs[WINDOW_BASE]); > + uint32_t windowstart = env->sregs[WINDOW_START]; > + uint32_t m, n; > + > + if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) { > + return; > + } > + > + for (n = 1; ; ++n) { > + if (n > w) { > + return; > + } > + if (windowstart & WINDOWSTART_BIT(windowbase + n)) { > + break; > + } > + } > + > + m = WINDOWBASE_BOUND(windowbase + n); > + rotate_window(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)) { > + HELPER(exception)(EXC_WINDOW_OVERFLOW4); > + } else if (windowstart & WINDOWSTART_BIT(m + 2)) { > + HELPER(exception)(EXC_WINDOW_OVERFLOW8); > + } else { > + HELPER(exception)(EXC_WINDOW_OVERFLOW12); > + } > +} > + > +uint32_t HELPER(retw)(uint32_t pc) > +{ > + int n = (env->regs[0] >> 30) & 0x3; > + int m = 0; > + uint32_t windowbase = WINDOWBASE_BOUND(env->sregs[WINDOW_BASE]); > + uint32_t windowstart = env->sregs[WINDOW_START]; > + uint32_t ret_pc = 0; > + > + if (windowstart & WINDOWSTART_BIT(windowbase - 1)) { > + m = 1; > + } else if (windowstart & WINDOWSTART_BIT(windowbase - 2)) { > + m = 2; > + } else if (windowstart & WINDOWSTART_BIT(windowbase - 3)) { > + m = 3; > + } > + > + if (n == 0 || (m != 0 && m != n) || > + ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) { > + qemu_log("Illegal retw instruction(pc = %08x), " > + "PS = %08x, m = %d, n = %d\n", > + pc, env->sregs[PS], m, n); > + HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE); > + } else { > + int owb = windowbase; > + > + ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff); > + > + rotate_window(-n); > + if (windowstart & WINDOWSTART_BIT(env->sregs[WINDOW_BASE])) { > + env->sregs[WINDOW_START] &= ~WINDOWSTART_BIT(owb); > + } else { > + /* window underflow */ > + env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) | > + (windowbase << PS_OWB_SHIFT) | PS_EXCM; > + env->sregs[EPC1] = env->pc = pc; > + > + if (n == 1) { > + HELPER(exception)(EXC_WINDOW_UNDERFLOW4); > + } else if (n == 2) { > + HELPER(exception)(EXC_WINDOW_UNDERFLOW8); > + } else if (n == 3) { > + HELPER(exception)(EXC_WINDOW_UNDERFLOW12); > + } > + } > + } > + return ret_pc; > +} > + > +void HELPER(rotw)(uint32_t imm4) > +{ > + rotate_window(imm4); > +} > + > +void HELPER(restore_owb)(void) > +{ > + rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT); > +} > + > +void HELPER(movsp)(uint32_t pc) > +{ > + if ((env->sregs[WINDOW_START] & > + (WINDOWSTART_BIT(env->sregs[WINDOW_BASE] - 3) | > + WINDOWSTART_BIT(env->sregs[WINDOW_BASE] - 2) | > + WINDOWSTART_BIT(env->sregs[WINDOW_BASE] - 1))) == 0) { > + HELPER(exception_cause)(pc, ALLOCA_CAUSE); > + } > +} > + > +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 de5f947..de393ff 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 callinc = tcg_const_i32(_callinc); > + > + tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS], > + callinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN); > + tcg_temp_free(callinc); > + 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*/ > @@ -1747,6 +1867,12 @@ void cpu_dump_state(CPUState *env, FILE *f, > fprintf_function cpu_fprintf, > for (i = 0; i < 16; ++i) > 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) Braces. > + 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) > -- > 1.7.6 > > >