target-sparc: Directly implement block and short ldf/stf asis

Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2015-09-06 08:30:00 -07:00
parent 7705091ca4
commit ca5ce5723f

View File

@ -1989,6 +1989,8 @@ typedef enum {
GET_ASI_EXCP,
GET_ASI_DIRECT,
GET_ASI_DTWINX,
GET_ASI_BLOCK,
GET_ASI_SHORT,
} ASIType;
typedef struct {
@ -2055,18 +2057,33 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
case ASI_AIUPL: /* As if user primary LE */
case ASI_TWINX_AIUP:
case ASI_TWINX_AIUP_L:
case ASI_BLK_AIUP_4V:
case ASI_BLK_AIUP_L_4V:
case ASI_BLK_AIUP:
case ASI_BLK_AIUPL:
mem_idx = MMU_USER_IDX;
break;
case ASI_AIUS: /* As if user secondary */
case ASI_AIUSL: /* As if user secondary LE */
case ASI_TWINX_AIUS:
case ASI_TWINX_AIUS_L:
case ASI_BLK_AIUS_4V:
case ASI_BLK_AIUS_L_4V:
case ASI_BLK_AIUS:
case ASI_BLK_AIUSL:
mem_idx = MMU_USER_SECONDARY_IDX;
break;
case ASI_S: /* Secondary */
case ASI_SL: /* Secondary LE */
case ASI_TWINX_S:
case ASI_TWINX_SL:
case ASI_BLK_COMMIT_S:
case ASI_BLK_S:
case ASI_BLK_SL:
case ASI_FL8_S:
case ASI_FL8_SL:
case ASI_FL16_S:
case ASI_FL16_SL:
if (mem_idx == MMU_USER_IDX) {
mem_idx = MMU_USER_SECONDARY_IDX;
} else if (mem_idx == MMU_KERNEL_IDX) {
@ -2077,6 +2094,13 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
case ASI_PL: /* Primary LE */
case ASI_TWINX_P:
case ASI_TWINX_PL:
case ASI_BLK_COMMIT_P:
case ASI_BLK_P:
case ASI_BLK_PL:
case ASI_FL8_P:
case ASI_FL8_PL:
case ASI_FL16_P:
case ASI_FL16_PL:
break;
}
switch (asi) {
@ -2104,6 +2128,36 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
case ASI_TWINX_SL:
type = GET_ASI_DTWINX;
break;
case ASI_BLK_COMMIT_P:
case ASI_BLK_COMMIT_S:
case ASI_BLK_AIUP_4V:
case ASI_BLK_AIUP_L_4V:
case ASI_BLK_AIUP:
case ASI_BLK_AIUPL:
case ASI_BLK_AIUS_4V:
case ASI_BLK_AIUS_L_4V:
case ASI_BLK_AIUS:
case ASI_BLK_AIUSL:
case ASI_BLK_S:
case ASI_BLK_SL:
case ASI_BLK_P:
case ASI_BLK_PL:
type = GET_ASI_BLOCK;
break;
case ASI_FL8_S:
case ASI_FL8_SL:
case ASI_FL8_P:
case ASI_FL8_PL:
memop = MO_UB;
type = GET_ASI_SHORT;
break;
case ASI_FL16_S:
case ASI_FL16_SL:
case ASI_FL16_P:
case ASI_FL16_PL:
memop = MO_TEUW;
type = GET_ASI_SHORT;
break;
}
/* The little-endian asis all have bit 3 set. */
if (asi & 8) {
@ -2309,6 +2363,40 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr,
}
break;
case GET_ASI_BLOCK:
/* Valid for lddfa on aligned registers only. */
if (size == 8 && (rd & 7) == 0) {
TCGv eight;
int i;
gen_check_align(addr, 0x3f);
gen_address_mask(dc, addr);
eight = tcg_const_tl(8);
for (i = 0; ; ++i) {
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + i], addr,
da.mem_idx, da.memop);
if (i == 7) {
break;
}
tcg_gen_add_tl(addr, addr, eight);
}
tcg_temp_free(eight);
} else {
gen_exception(dc, TT_ILL_INSN);
}
break;
case GET_ASI_SHORT:
/* Valid for lddfa only. */
if (size == 8) {
gen_address_mask(dc, addr);
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
} else {
gen_exception(dc, TT_ILL_INSN);
}
break;
default:
{
TCGv_i32 r_asi = tcg_const_i32(da.asi);
@ -2355,6 +2443,40 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr,
}
break;
case GET_ASI_BLOCK:
/* Valid for stdfa on aligned registers only. */
if (size == 8 && (rd & 7) == 0) {
TCGv eight;
int i;
gen_check_align(addr, 0x3f);
gen_address_mask(dc, addr);
eight = tcg_const_tl(8);
for (i = 0; ; ++i) {
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + i], addr,
da.mem_idx, da.memop);
if (i == 7) {
break;
}
tcg_gen_add_tl(addr, addr, eight);
}
tcg_temp_free(eight);
} else {
gen_exception(dc, TT_ILL_INSN);
}
break;
case GET_ASI_SHORT:
/* Valid for stdfa only. */
if (size == 8) {
gen_address_mask(dc, addr);
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
} else {
gen_exception(dc, TT_ILL_INSN);
}
break;
default:
{
TCGv_i32 r_asi = tcg_const_i32(da.asi);