mirror of https://gitee.com/openkylin/qemu.git
target/mips: Add loongson-ext lswc2 group of instructions (Part 2)
LWC2 & SWC2 have been rewritten by Loongson EXT vendor ASE as "load/store quad word" and "shifted load/store" groups of instructions. This patch add implementation of these instructions: gslwlc1: similar to lwl but RT is FPR instead of GPR gslwrc1: similar to lwr but RT is FPR instead of GPR gsldlc1: similar to ldl but RT is FPR instead of GPR gsldrc1: similar to ldr but RT is FPR instead of GPR gsswlc1: similar to swl but RT is FPR instead of GPR gsswrc1: similar to swr but RT is FPR instead of GPR gssdlc1: similar to sdl but RT is FPR instead of GPR gssdrc1: similar to sdr but RT is FPR instead of GPR Details of Loongson-EXT is here: https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> Signed-off-by: Huacai Chen <chenhc@lemote.com> Message-Id: <1602831120-3377-4-git-send-email-chenhc@lemote.com> [PMD: Reuse t1 on MIPS32, reintroduce t2/fp0] Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
This commit is contained in:
parent
e10a0ca17d
commit
fd723105c1
target/mips
|
@ -471,6 +471,19 @@ enum {
|
|||
OPC_GSSHFS = OPC_SWC2,
|
||||
};
|
||||
|
||||
/* Loongson EXT shifted load/store opcodes */
|
||||
#define MASK_LOONGSON_GSSHFLS(op) (MASK_OP_MAJOR(op) | (op & 0xc03f))
|
||||
enum {
|
||||
OPC_GSLWLC1 = 0x4 | OPC_GSSHFL,
|
||||
OPC_GSLWRC1 = 0x5 | OPC_GSSHFL,
|
||||
OPC_GSLDLC1 = 0x6 | OPC_GSSHFL,
|
||||
OPC_GSLDRC1 = 0x7 | OPC_GSSHFL,
|
||||
OPC_GSSWLC1 = 0x4 | OPC_GSSHFS,
|
||||
OPC_GSSWRC1 = 0x5 | OPC_GSSHFS,
|
||||
OPC_GSSDLC1 = 0x6 | OPC_GSSHFS,
|
||||
OPC_GSSDRC1 = 0x7 | OPC_GSSHFS,
|
||||
};
|
||||
|
||||
/* BSHFL opcodes */
|
||||
#define MASK_BSHFL(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
|
||||
|
||||
|
@ -5924,12 +5937,13 @@ no_rd:
|
|||
static void gen_loongson_lswc2(DisasContext *ctx, int rt,
|
||||
int rs, int rd)
|
||||
{
|
||||
TCGv t0;
|
||||
TCGv t0, t1, t2;
|
||||
TCGv_i32 fp0;
|
||||
#if defined(TARGET_MIPS64)
|
||||
TCGv t1;
|
||||
int lsq_rt1 = ctx->opcode & 0x1f;
|
||||
int lsq_offset = sextract32(ctx->opcode, 6, 9) << 4;
|
||||
#endif
|
||||
int shf_offset = sextract32(ctx->opcode, 6, 8);
|
||||
|
||||
t0 = tcg_temp_new();
|
||||
|
||||
|
@ -5986,6 +6000,170 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
|
|||
tcg_temp_free(t1);
|
||||
break;
|
||||
#endif
|
||||
case OPC_GSSHFL:
|
||||
switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
|
||||
case OPC_GSLWLC1:
|
||||
check_cp1_enabled(ctx);
|
||||
gen_base_offset_addr(ctx, t0, rs, shf_offset);
|
||||
t1 = tcg_temp_new();
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
|
||||
tcg_gen_andi_tl(t1, t0, 3);
|
||||
#ifndef TARGET_WORDS_BIGENDIAN
|
||||
tcg_gen_xori_tl(t1, t1, 3);
|
||||
#endif
|
||||
tcg_gen_shli_tl(t1, t1, 3);
|
||||
tcg_gen_andi_tl(t0, t0, ~3);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
|
||||
tcg_gen_shl_tl(t0, t0, t1);
|
||||
t2 = tcg_const_tl(-1);
|
||||
tcg_gen_shl_tl(t2, t2, t1);
|
||||
fp0 = tcg_temp_new_i32();
|
||||
gen_load_fpr32(ctx, fp0, rt);
|
||||
tcg_gen_ext_i32_tl(t1, fp0);
|
||||
tcg_gen_andc_tl(t1, t1, t2);
|
||||
tcg_temp_free(t2);
|
||||
tcg_gen_or_tl(t0, t0, t1);
|
||||
tcg_temp_free(t1);
|
||||
#if defined(TARGET_MIPS64)
|
||||
tcg_gen_extrl_i64_i32(fp0, t0);
|
||||
#else
|
||||
tcg_gen_ext32s_tl(fp0, t0);
|
||||
#endif
|
||||
gen_store_fpr32(ctx, fp0, rt);
|
||||
tcg_temp_free_i32(fp0);
|
||||
break;
|
||||
case OPC_GSLWRC1:
|
||||
check_cp1_enabled(ctx);
|
||||
gen_base_offset_addr(ctx, t0, rs, shf_offset);
|
||||
t1 = tcg_temp_new();
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
|
||||
tcg_gen_andi_tl(t1, t0, 3);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
tcg_gen_xori_tl(t1, t1, 3);
|
||||
#endif
|
||||
tcg_gen_shli_tl(t1, t1, 3);
|
||||
tcg_gen_andi_tl(t0, t0, ~3);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
|
||||
tcg_gen_shr_tl(t0, t0, t1);
|
||||
tcg_gen_xori_tl(t1, t1, 31);
|
||||
t2 = tcg_const_tl(0xfffffffeull);
|
||||
tcg_gen_shl_tl(t2, t2, t1);
|
||||
fp0 = tcg_temp_new_i32();
|
||||
gen_load_fpr32(ctx, fp0, rt);
|
||||
tcg_gen_ext_i32_tl(t1, fp0);
|
||||
tcg_gen_and_tl(t1, t1, t2);
|
||||
tcg_temp_free(t2);
|
||||
tcg_gen_or_tl(t0, t0, t1);
|
||||
tcg_temp_free(t1);
|
||||
#if defined(TARGET_MIPS64)
|
||||
tcg_gen_extrl_i64_i32(fp0, t0);
|
||||
#else
|
||||
tcg_gen_ext32s_tl(fp0, t0);
|
||||
#endif
|
||||
gen_store_fpr32(ctx, fp0, rt);
|
||||
tcg_temp_free_i32(fp0);
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_GSLDLC1:
|
||||
check_cp1_enabled(ctx);
|
||||
gen_base_offset_addr(ctx, t0, rs, shf_offset);
|
||||
t1 = tcg_temp_new();
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
|
||||
tcg_gen_andi_tl(t1, t0, 7);
|
||||
#ifndef TARGET_WORDS_BIGENDIAN
|
||||
tcg_gen_xori_tl(t1, t1, 7);
|
||||
#endif
|
||||
tcg_gen_shli_tl(t1, t1, 3);
|
||||
tcg_gen_andi_tl(t0, t0, ~7);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_shl_tl(t0, t0, t1);
|
||||
t2 = tcg_const_tl(-1);
|
||||
tcg_gen_shl_tl(t2, t2, t1);
|
||||
gen_load_fpr64(ctx, t1, rt);
|
||||
tcg_gen_andc_tl(t1, t1, t2);
|
||||
tcg_temp_free(t2);
|
||||
tcg_gen_or_tl(t0, t0, t1);
|
||||
tcg_temp_free(t1);
|
||||
gen_store_fpr64(ctx, t0, rt);
|
||||
break;
|
||||
case OPC_GSLDRC1:
|
||||
check_cp1_enabled(ctx);
|
||||
gen_base_offset_addr(ctx, t0, rs, shf_offset);
|
||||
t1 = tcg_temp_new();
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
|
||||
tcg_gen_andi_tl(t1, t0, 7);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
tcg_gen_xori_tl(t1, t1, 7);
|
||||
#endif
|
||||
tcg_gen_shli_tl(t1, t1, 3);
|
||||
tcg_gen_andi_tl(t0, t0, ~7);
|
||||
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
|
||||
tcg_gen_shr_tl(t0, t0, t1);
|
||||
tcg_gen_xori_tl(t1, t1, 63);
|
||||
t2 = tcg_const_tl(0xfffffffffffffffeull);
|
||||
tcg_gen_shl_tl(t2, t2, t1);
|
||||
gen_load_fpr64(ctx, t1, rt);
|
||||
tcg_gen_and_tl(t1, t1, t2);
|
||||
tcg_temp_free(t2);
|
||||
tcg_gen_or_tl(t0, t0, t1);
|
||||
tcg_temp_free(t1);
|
||||
gen_store_fpr64(ctx, t0, rt);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
MIPS_INVAL("loongson_gsshfl");
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OPC_GSSHFS:
|
||||
switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
|
||||
case OPC_GSSWLC1:
|
||||
check_cp1_enabled(ctx);
|
||||
t1 = tcg_temp_new();
|
||||
gen_base_offset_addr(ctx, t0, rs, shf_offset);
|
||||
fp0 = tcg_temp_new_i32();
|
||||
gen_load_fpr32(ctx, fp0, rt);
|
||||
tcg_gen_ext_i32_tl(t1, fp0);
|
||||
gen_helper_0e2i(swl, t1, t0, ctx->mem_idx);
|
||||
tcg_temp_free_i32(fp0);
|
||||
tcg_temp_free(t1);
|
||||
break;
|
||||
case OPC_GSSWRC1:
|
||||
check_cp1_enabled(ctx);
|
||||
t1 = tcg_temp_new();
|
||||
gen_base_offset_addr(ctx, t0, rs, shf_offset);
|
||||
fp0 = tcg_temp_new_i32();
|
||||
gen_load_fpr32(ctx, fp0, rt);
|
||||
tcg_gen_ext_i32_tl(t1, fp0);
|
||||
gen_helper_0e2i(swr, t1, t0, ctx->mem_idx);
|
||||
tcg_temp_free_i32(fp0);
|
||||
tcg_temp_free(t1);
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_GSSDLC1:
|
||||
check_cp1_enabled(ctx);
|
||||
t1 = tcg_temp_new();
|
||||
gen_base_offset_addr(ctx, t0, rs, shf_offset);
|
||||
gen_load_fpr64(ctx, t1, rt);
|
||||
gen_helper_0e2i(sdl, t1, t0, ctx->mem_idx);
|
||||
tcg_temp_free(t1);
|
||||
break;
|
||||
case OPC_GSSDRC1:
|
||||
check_cp1_enabled(ctx);
|
||||
t1 = tcg_temp_new();
|
||||
gen_base_offset_addr(ctx, t0, rs, shf_offset);
|
||||
gen_load_fpr64(ctx, t1, rt);
|
||||
gen_helper_0e2i(sdr, t1, t0, ctx->mem_idx);
|
||||
tcg_temp_free(t1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
MIPS_INVAL("loongson_gsshfs");
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MIPS_INVAL("loongson_gslsq");
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
|
|
Loading…
Reference in New Issue