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:
Jiaxun Yang 2020-10-16 14:51:55 +08:00 committed by Philippe Mathieu-Daudé
parent e10a0ca17d
commit fd723105c1

View file

@ -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);