mirror of
https://github.com/qemu/qemu.git
synced 2024-11-27 22:03:35 +08:00
target/sparc: Move simple integer load/store to decodetree
Move LDUW, LDUB, LDUH, LDD, LDSW, LDSB, LDSH, LDX, STW, STB, STH, STD, STX. 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
ebbbec9216
commit
0880d20b2e
@ -231,6 +231,28 @@ RESTORE 10 ..... 111101 ..... . ............. @r_r_ri
|
||||
DONE 10 00000 111110 00000 0 0000000000000
|
||||
RETRY 10 00001 111110 00000 0 0000000000000
|
||||
|
||||
##
|
||||
## Major Opcode 11 -- load and store instructions
|
||||
##
|
||||
|
||||
&r_r_ri_asi rd rs1 rs2_or_imm asi imm:bool
|
||||
@r_r_ri_na .. rd:5 ...... rs1:5 imm:1 rs2_or_imm:s13 &r_r_ri_asi asi=-1
|
||||
|
||||
LDUW 11 ..... 000000 ..... . ............. @r_r_ri_na
|
||||
LDUB 11 ..... 000001 ..... . ............. @r_r_ri_na
|
||||
LDUH 11 ..... 000010 ..... . ............. @r_r_ri_na
|
||||
LDD 11 ..... 000011 ..... . ............. @r_r_ri_na
|
||||
LDSW 11 ..... 001000 ..... . ............. @r_r_ri_na
|
||||
LDSB 11 ..... 001001 ..... . ............. @r_r_ri_na
|
||||
LDSH 11 ..... 001010 ..... . ............. @r_r_ri_na
|
||||
LDX 11 ..... 001011 ..... . ............. @r_r_ri_na
|
||||
|
||||
STW 11 ..... 000100 ..... . ............. @r_r_ri_na
|
||||
STB 11 ..... 000101 ..... . ............. @r_r_ri_na
|
||||
STH 11 ..... 000110 ..... . ............. @r_r_ri_na
|
||||
STD 11 ..... 000111 ..... . ............. @r_r_ri_na
|
||||
STX 11 ..... 001110 ..... . ............. @r_r_ri_na
|
||||
|
||||
NCP 10 ----- 110110 ----- --------- ----- # v8 CPop1
|
||||
NCP 10 ----- 110111 ----- --------- ----- # v8 CPop2
|
||||
|
||||
|
@ -4536,6 +4536,117 @@ static bool do_done_retry(DisasContext *dc, bool done)
|
||||
TRANS(DONE, 64, do_done_retry, true)
|
||||
TRANS(RETRY, 64, do_done_retry, false)
|
||||
|
||||
/*
|
||||
* Major opcode 11 -- load and store instructions
|
||||
*/
|
||||
|
||||
static TCGv gen_ldst_addr(DisasContext *dc, int rs1, bool imm, int rs2_or_imm)
|
||||
{
|
||||
TCGv addr, tmp = NULL;
|
||||
|
||||
/* For simplicity, we under-decoded the rs2 form. */
|
||||
if (!imm && rs2_or_imm & ~0x1f) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr = gen_load_gpr(dc, rs1);
|
||||
if (rs2_or_imm) {
|
||||
tmp = tcg_temp_new();
|
||||
if (imm) {
|
||||
tcg_gen_addi_tl(tmp, addr, rs2_or_imm);
|
||||
} else {
|
||||
tcg_gen_add_tl(tmp, addr, cpu_regs[rs2_or_imm]);
|
||||
}
|
||||
addr = tmp;
|
||||
}
|
||||
if (AM_CHECK(dc)) {
|
||||
if (!tmp) {
|
||||
tmp = tcg_temp_new();
|
||||
}
|
||||
tcg_gen_ext32u_tl(tmp, addr);
|
||||
addr = tmp;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
static bool do_ld_gpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
|
||||
{
|
||||
TCGv reg, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
|
||||
DisasASI da;
|
||||
|
||||
if (addr == NULL) {
|
||||
return false;
|
||||
}
|
||||
da = resolve_asi(dc, a->asi, mop);
|
||||
|
||||
reg = gen_dest_gpr(dc, a->rd);
|
||||
gen_ld_asi0(dc, &da, reg, addr);
|
||||
gen_store_gpr(dc, a->rd, reg);
|
||||
return advance_pc(dc);
|
||||
}
|
||||
|
||||
TRANS(LDUW, ALL, do_ld_gpr, a, MO_TEUL)
|
||||
TRANS(LDUB, ALL, do_ld_gpr, a, MO_UB)
|
||||
TRANS(LDUH, ALL, do_ld_gpr, a, MO_TEUW)
|
||||
TRANS(LDSB, ALL, do_ld_gpr, a, MO_SB)
|
||||
TRANS(LDSH, ALL, do_ld_gpr, a, MO_TESW)
|
||||
TRANS(LDSW, 64, do_ld_gpr, a, MO_TESL)
|
||||
TRANS(LDX, 64, do_ld_gpr, a, MO_TEUQ)
|
||||
|
||||
static bool do_st_gpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
|
||||
{
|
||||
TCGv reg, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
|
||||
DisasASI da;
|
||||
|
||||
if (addr == NULL) {
|
||||
return false;
|
||||
}
|
||||
da = resolve_asi(dc, a->asi, mop);
|
||||
|
||||
reg = gen_load_gpr(dc, a->rd);
|
||||
gen_st_asi0(dc, &da, reg, addr);
|
||||
return advance_pc(dc);
|
||||
}
|
||||
|
||||
TRANS(STW, ALL, do_st_gpr, a, MO_TEUL)
|
||||
TRANS(STB, ALL, do_st_gpr, a, MO_UB)
|
||||
TRANS(STH, ALL, do_st_gpr, a, MO_TEUW)
|
||||
TRANS(STX, 64, do_st_gpr, a, MO_TEUQ)
|
||||
|
||||
static bool trans_LDD(DisasContext *dc, arg_r_r_ri_asi *a)
|
||||
{
|
||||
TCGv addr;
|
||||
DisasASI da;
|
||||
|
||||
if (a->rd & 1) {
|
||||
return false;
|
||||
}
|
||||
addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
|
||||
if (addr == NULL) {
|
||||
return false;
|
||||
}
|
||||
da = resolve_asi(dc, a->asi, MO_TEUQ);
|
||||
gen_ldda_asi0(dc, &da, addr, a->rd);
|
||||
return advance_pc(dc);
|
||||
}
|
||||
|
||||
static bool trans_STD(DisasContext *dc, arg_r_r_ri_asi *a)
|
||||
{
|
||||
TCGv addr;
|
||||
DisasASI da;
|
||||
|
||||
if (a->rd & 1) {
|
||||
return false;
|
||||
}
|
||||
addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
|
||||
if (addr == NULL) {
|
||||
return false;
|
||||
}
|
||||
da = resolve_asi(dc, a->asi, MO_TEUQ);
|
||||
gen_stda_asi0(dc, &da, addr, a->rd);
|
||||
return advance_pc(dc);
|
||||
}
|
||||
|
||||
#define CHECK_IU_FEATURE(dc, FEATURE) \
|
||||
if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \
|
||||
goto illegal_insn;
|
||||
@ -5359,47 +5470,15 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
|
||||
|
||||
switch (xop) {
|
||||
case 0x0: /* ld, V9 lduw, load unsigned word */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_ld_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_TEUL | MO_ALIGN);
|
||||
break;
|
||||
case 0x1: /* ldub, load unsigned byte */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_ld_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_UB);
|
||||
break;
|
||||
case 0x2: /* lduh, load unsigned halfword */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_ld_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_TEUW | MO_ALIGN);
|
||||
break;
|
||||
case 0x3: /* ldd, load double word */
|
||||
if (rd & 1)
|
||||
goto illegal_insn;
|
||||
else {
|
||||
TCGv_i64 t64;
|
||||
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
t64 = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(t64, cpu_addr,
|
||||
dc->mem_idx, MO_TEUQ | MO_ALIGN);
|
||||
tcg_gen_trunc_i64_tl(cpu_val, t64);
|
||||
tcg_gen_ext32u_tl(cpu_val, cpu_val);
|
||||
gen_store_gpr(dc, rd + 1, cpu_val);
|
||||
tcg_gen_shri_i64(t64, t64, 32);
|
||||
tcg_gen_trunc_i64_tl(cpu_val, t64);
|
||||
tcg_gen_ext32u_tl(cpu_val, cpu_val);
|
||||
}
|
||||
break;
|
||||
case 0x9: /* ldsb, load signed byte */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_ld_tl(cpu_val, cpu_addr, dc->mem_idx, MO_SB);
|
||||
break;
|
||||
case 0xa: /* ldsh, load signed halfword */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_ld_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_TESW | MO_ALIGN);
|
||||
break;
|
||||
g_assert_not_reached(); /* in decodetree */
|
||||
case 0x08: /* V9 ldsw */
|
||||
case 0x0b: /* V9 ldx */
|
||||
goto illegal_insn; /* in decodetree */
|
||||
case 0xd: /* ldstub */
|
||||
gen_ldstub(dc, cpu_val, cpu_addr, dc->mem_idx);
|
||||
break;
|
||||
@ -5441,16 +5520,6 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_SPARC64
|
||||
case 0x08: /* V9 ldsw */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_ld_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_TESL | MO_ALIGN);
|
||||
break;
|
||||
case 0x0b: /* V9 ldx */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_ld_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_TEUQ | MO_ALIGN);
|
||||
break;
|
||||
case 0x18: /* V9 ldswa */
|
||||
gen_ld_asi(dc, cpu_val, cpu_addr, insn, MO_TESL);
|
||||
break;
|
||||
@ -5543,38 +5612,18 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
|
||||
}
|
||||
} else if (xop < 8 || (xop >= 0x14 && xop < 0x18) ||
|
||||
xop == 0xe || xop == 0x1e) {
|
||||
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
|
||||
TCGv cpu_val = gen_load_gpr(dc, rd);
|
||||
#endif
|
||||
|
||||
switch (xop) {
|
||||
case 0x4: /* st, store word */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_st_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_TEUL | MO_ALIGN);
|
||||
break;
|
||||
case 0x5: /* stb, store byte */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_st_tl(cpu_val, cpu_addr, dc->mem_idx, MO_UB);
|
||||
break;
|
||||
case 0x6: /* sth, store halfword */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_st_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_TEUW | MO_ALIGN);
|
||||
break;
|
||||
case 0x7: /* std, store double word */
|
||||
if (rd & 1)
|
||||
goto illegal_insn;
|
||||
else {
|
||||
TCGv_i64 t64;
|
||||
TCGv lo;
|
||||
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
lo = gen_load_gpr(dc, rd + 1);
|
||||
t64 = tcg_temp_new_i64();
|
||||
tcg_gen_concat_tl_i64(t64, lo, cpu_val);
|
||||
tcg_gen_qemu_st_i64(t64, cpu_addr,
|
||||
dc->mem_idx, MO_TEUQ | MO_ALIGN);
|
||||
}
|
||||
break;
|
||||
g_assert_not_reached(); /* in decodetree */
|
||||
case 0x0e: /* V9 stx */
|
||||
goto illegal_insn; /* in decodetree */
|
||||
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
|
||||
case 0x14: /* sta, V9 stwa, store word alternate */
|
||||
gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEUL);
|
||||
@ -5593,11 +5642,6 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_SPARC64
|
||||
case 0x0e: /* V9 stx */
|
||||
gen_address_mask(dc, cpu_addr);
|
||||
tcg_gen_qemu_st_tl(cpu_val, cpu_addr,
|
||||
dc->mem_idx, MO_TEUQ | MO_ALIGN);
|
||||
break;
|
||||
case 0x1e: /* V9 stxa */
|
||||
gen_st_asi(dc, cpu_val, cpu_addr, insn, MO_TEUQ);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user