diff options
Diffstat (limited to 'target/mips')
-rw-r--r-- | target/mips/translate.c | 182 |
1 files changed, 180 insertions, 2 deletions
diff --git a/target/mips/translate.c b/target/mips/translate.c index e83954d782..b335645e03 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -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); |