target/sparc: Move JMPL, RETT, RETURN to decodetree
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
d3c7e8ad74
commit
86b82fe021
@ -28,6 +28,7 @@ CALL 01 i:s30
|
||||
|
||||
&r_r_ri rd rs1 rs2_or_imm imm:bool
|
||||
@n_r_ri .. ..... ...... rs1:5 imm:1 rs2_or_imm:s13 &r_r_ri rd=0
|
||||
@r_r_ri .. rd:5 ...... rs1:5 imm:1 rs2_or_imm:s13 &r_r_ri
|
||||
|
||||
&r_r_ri_cc rd rs1 rs2_or_imm imm:bool cc:bool
|
||||
@r_r_ri_cc .. rd:5 . cc:1 .... rs1:5 imm:1 rs2_or_imm:s13 &r_r_ri_cc
|
||||
@ -217,6 +218,12 @@ MOVcc 10 rd:5 101100 1 cond:4 imm:1 cc:1 0 rs2_or_imm:s11
|
||||
MOVfcc 10 rd:5 101100 0 cond:4 imm:1 cc:2 rs2_or_imm:s11
|
||||
MOVR 10 rd:5 101111 rs1:5 imm:1 cond:3 rs2_or_imm:s10
|
||||
|
||||
JMPL 10 ..... 111000 ..... . ............. @r_r_ri
|
||||
{
|
||||
RETT 10 00000 111001 ..... . ............. @n_r_ri
|
||||
RETURN 10 00000 111001 ..... . ............. @n_r_ri
|
||||
}
|
||||
|
||||
NCP 10 ----- 110110 ----- --------- ----- # v8 CPop1
|
||||
NCP 10 ----- 110111 ----- --------- ----- # v8 CPop2
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
# define gen_helper_rdpsr(D, E) qemu_build_not_reached()
|
||||
# define gen_helper_rett(E) qemu_build_not_reached()
|
||||
# define gen_helper_power_down(E) qemu_build_not_reached()
|
||||
# define gen_helper_wrpsr(E, S) qemu_build_not_reached()
|
||||
#else
|
||||
@ -4377,6 +4378,85 @@ static bool trans_MOVR(DisasContext *dc, arg_MOVR *a)
|
||||
return do_mov_cond(dc, &cmp, a->rd, src2);
|
||||
}
|
||||
|
||||
static bool do_add_special(DisasContext *dc, arg_r_r_ri *a,
|
||||
bool (*func)(DisasContext *dc, int rd, TCGv src))
|
||||
{
|
||||
TCGv src1, sum;
|
||||
|
||||
/* For simplicity, we under-decoded the rs2 form. */
|
||||
if (!a->imm && a->rs2_or_imm & ~0x1f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Always load the sum into a new temporary.
|
||||
* This is required to capture the value across a window change,
|
||||
* e.g. SAVE and RESTORE, and may be optimized away otherwise.
|
||||
*/
|
||||
sum = tcg_temp_new();
|
||||
src1 = gen_load_gpr(dc, a->rs1);
|
||||
if (a->imm || a->rs2_or_imm == 0) {
|
||||
tcg_gen_addi_tl(sum, src1, a->rs2_or_imm);
|
||||
} else {
|
||||
tcg_gen_add_tl(sum, src1, cpu_regs[a->rs2_or_imm]);
|
||||
}
|
||||
return func(dc, a->rd, sum);
|
||||
}
|
||||
|
||||
static bool do_jmpl(DisasContext *dc, int rd, TCGv src)
|
||||
{
|
||||
/*
|
||||
* Preserve pc across advance, so that we can delay
|
||||
* the writeback to rd until after src is consumed.
|
||||
*/
|
||||
target_ulong cur_pc = dc->pc;
|
||||
|
||||
gen_check_align(dc, src, 3);
|
||||
|
||||
gen_mov_pc_npc(dc);
|
||||
tcg_gen_mov_tl(cpu_npc, src);
|
||||
gen_address_mask(dc, cpu_npc);
|
||||
gen_store_gpr(dc, rd, tcg_constant_tl(cur_pc));
|
||||
|
||||
dc->npc = DYNAMIC_PC_LOOKUP;
|
||||
return true;
|
||||
}
|
||||
|
||||
TRANS(JMPL, ALL, do_add_special, a, do_jmpl)
|
||||
|
||||
static bool do_rett(DisasContext *dc, int rd, TCGv src)
|
||||
{
|
||||
if (!supervisor(dc)) {
|
||||
return raise_priv(dc);
|
||||
}
|
||||
|
||||
gen_check_align(dc, src, 3);
|
||||
|
||||
gen_mov_pc_npc(dc);
|
||||
tcg_gen_mov_tl(cpu_npc, src);
|
||||
gen_helper_rett(tcg_env);
|
||||
|
||||
dc->npc = DYNAMIC_PC;
|
||||
return true;
|
||||
}
|
||||
|
||||
TRANS(RETT, 32, do_add_special, a, do_rett)
|
||||
|
||||
static bool do_return(DisasContext *dc, int rd, TCGv src)
|
||||
{
|
||||
gen_check_align(dc, src, 3);
|
||||
|
||||
gen_mov_pc_npc(dc);
|
||||
tcg_gen_mov_tl(cpu_npc, src);
|
||||
gen_address_mask(dc, cpu_npc);
|
||||
|
||||
gen_helper_restore(tcg_env);
|
||||
dc->npc = DYNAMIC_PC_LOOKUP;
|
||||
return true;
|
||||
}
|
||||
|
||||
TRANS(RETURN, 64, do_add_special, a, do_return)
|
||||
|
||||
#define CHECK_IU_FEATURE(dc, FEATURE) \
|
||||
if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \
|
||||
goto illegal_insn;
|
||||
@ -5174,30 +5254,6 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
|
||||
} else if (xop == 0x37) {
|
||||
/* V8 CPop2, V9 impdep2 */
|
||||
goto illegal_insn; /* in decodetree */
|
||||
#ifdef TARGET_SPARC64
|
||||
} else if (xop == 0x39) { /* V9 return */
|
||||
save_state(dc);
|
||||
cpu_src1 = get_src1(dc, insn);
|
||||
cpu_tmp0 = tcg_temp_new();
|
||||
if (IS_IMM) { /* immediate */
|
||||
simm = GET_FIELDs(insn, 19, 31);
|
||||
tcg_gen_addi_tl(cpu_tmp0, cpu_src1, simm);
|
||||
} else { /* register */
|
||||
rs2 = GET_FIELD(insn, 27, 31);
|
||||
if (rs2) {
|
||||
cpu_src2 = gen_load_gpr(dc, rs2);
|
||||
tcg_gen_add_tl(cpu_tmp0, cpu_src1, cpu_src2);
|
||||
} else {
|
||||
tcg_gen_mov_tl(cpu_tmp0, cpu_src1);
|
||||
}
|
||||
}
|
||||
gen_check_align(dc, cpu_tmp0, 3);
|
||||
gen_helper_restore(tcg_env);
|
||||
gen_mov_pc_npc(dc);
|
||||
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
|
||||
dc->npc = DYNAMIC_PC_LOOKUP;
|
||||
goto jmp_insn;
|
||||
#endif
|
||||
} else {
|
||||
cpu_src1 = get_src1(dc, insn);
|
||||
cpu_tmp0 = tcg_temp_new();
|
||||
@ -5215,28 +5271,8 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
|
||||
}
|
||||
switch (xop) {
|
||||
case 0x38: /* jmpl */
|
||||
{
|
||||
gen_check_align(dc, cpu_tmp0, 3);
|
||||
gen_store_gpr(dc, rd, tcg_constant_tl(dc->pc));
|
||||
gen_mov_pc_npc(dc);
|
||||
gen_address_mask(dc, cpu_tmp0);
|
||||
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
|
||||
dc->npc = DYNAMIC_PC_LOOKUP;
|
||||
}
|
||||
goto jmp_insn;
|
||||
#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
|
||||
case 0x39: /* rett, V9 return */
|
||||
{
|
||||
if (!supervisor(dc))
|
||||
goto priv_insn;
|
||||
gen_check_align(dc, cpu_tmp0, 3);
|
||||
gen_mov_pc_npc(dc);
|
||||
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
|
||||
dc->npc = DYNAMIC_PC;
|
||||
gen_helper_rett(tcg_env);
|
||||
}
|
||||
goto jmp_insn;
|
||||
#endif
|
||||
g_assert_not_reached(); /* in decode tree */
|
||||
case 0x3b: /* flush */
|
||||
/* nop */
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user