diff options
Diffstat (limited to 'target/mips/tcg/tx79_translate.c')
-rw-r--r-- | target/mips/tcg/tx79_translate.c | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/target/mips/tcg/tx79_translate.c b/target/mips/tcg/tx79_translate.c index ad83774b97..395d6afa1f 100644 --- a/target/mips/tcg/tx79_translate.c +++ b/target/mips/tcg/tx79_translate.c @@ -2,12 +2,14 @@ * Toshiba TX79-specific instructions translation routines * * Copyright (c) 2018 Fredrik Noring + * Copyright (c) 2021 Philippe Mathieu-Daudé * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" #include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" #include "exec/helper-gen.h" #include "translate.h" @@ -114,6 +116,53 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a) * PSUBUW rd, rs, rt Parallel Subtract with Unsigned saturation Word */ +static bool trans_parallel_arith(DisasContext *ctx, arg_rtype *a, + void (*gen_logic_i64)(TCGv_i64, TCGv_i64, TCGv_i64)) +{ + TCGv_i64 ax, bx; + + if (a->rd == 0) { + /* nop */ + return true; + } + + ax = tcg_temp_new_i64(); + bx = tcg_temp_new_i64(); + + /* Lower half */ + gen_load_gpr(ax, a->rs); + gen_load_gpr(bx, a->rt); + gen_logic_i64(cpu_gpr[a->rd], ax, bx); + + /* Upper half */ + gen_load_gpr_hi(ax, a->rs); + gen_load_gpr_hi(bx, a->rt); + gen_logic_i64(cpu_gpr_hi[a->rd], ax, bx); + + tcg_temp_free(bx); + tcg_temp_free(ax); + + return true; +} + +/* Parallel Subtract Byte */ +static bool trans_PSUBB(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_arith(ctx, a, tcg_gen_vec_sub8_i64); +} + +/* Parallel Subtract Halfword */ +static bool trans_PSUBH(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_arith(ctx, a, tcg_gen_vec_sub16_i64); +} + +/* Parallel Subtract Word */ +static bool trans_PSUBW(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_arith(ctx, a, tcg_gen_vec_sub32_i64); +} + /* * Min/Max (4 instructions) * ------------------------ @@ -139,6 +188,30 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a) * PNOR rd, rs, rt Parallel NOR */ +/* Parallel And */ +static bool trans_PAND(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_arith(ctx, a, tcg_gen_and_i64); +} + +/* Parallel Or */ +static bool trans_POR(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_arith(ctx, a, tcg_gen_or_i64); +} + +/* Parallel Exclusive Or */ +static bool trans_PXOR(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_arith(ctx, a, tcg_gen_xor_i64); +} + +/* Parallel Not Or */ +static bool trans_PNOR(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_arith(ctx, a, tcg_gen_nor_i64); +} + /* * Shift (9 instructions) * ---------------------- @@ -164,6 +237,90 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a) * PCEQW rd, rs, rt Parallel Compare for Equal Word */ +static bool trans_parallel_compare(DisasContext *ctx, arg_rtype *a, + TCGCond cond, unsigned wlen) +{ + TCGv_i64 c0, c1, ax, bx, t0, t1, t2; + + if (a->rd == 0) { + /* nop */ + return true; + } + + c0 = tcg_const_tl(0); + c1 = tcg_const_tl(0xffffffff); + ax = tcg_temp_new_i64(); + bx = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + + /* Lower half */ + gen_load_gpr(ax, a->rs); + gen_load_gpr(bx, a->rt); + for (int i = 0; i < (64 / wlen); i++) { + tcg_gen_sextract_i64(t0, ax, wlen * i, wlen); + tcg_gen_sextract_i64(t1, bx, wlen * i, wlen); + tcg_gen_movcond_i64(cond, t2, t1, t0, c1, c0); + tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], t2, wlen * i, wlen); + } + /* Upper half */ + gen_load_gpr_hi(ax, a->rs); + gen_load_gpr_hi(bx, a->rt); + for (int i = 0; i < (64 / wlen); i++) { + tcg_gen_sextract_i64(t0, ax, wlen * i, wlen); + tcg_gen_sextract_i64(t1, bx, wlen * i, wlen); + tcg_gen_movcond_i64(cond, t2, t1, t0, c1, c0); + tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], t2, wlen * i, wlen); + } + + tcg_temp_free(t2); + tcg_temp_free(t1); + tcg_temp_free(t0); + tcg_temp_free(bx); + tcg_temp_free(ax); + tcg_temp_free(c1); + tcg_temp_free(c0); + + return true; +} + +/* Parallel Compare for Greater Than Byte */ +static bool trans_PCGTB(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_compare(ctx, a, TCG_COND_GE, 8); +} + +/* Parallel Compare for Equal Byte */ +static bool trans_PCEQB(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_compare(ctx, a, TCG_COND_EQ, 8); +} + +/* Parallel Compare for Greater Than Halfword */ +static bool trans_PCGTH(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_compare(ctx, a, TCG_COND_GE, 16); +} + +/* Parallel Compare for Equal Halfword */ +static bool trans_PCEQH(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_compare(ctx, a, TCG_COND_EQ, 16); +} + +/* Parallel Compare for Greater Than Word */ +static bool trans_PCGTW(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_compare(ctx, a, TCG_COND_GE, 32); +} + +/* Parallel Compare for Equal Word */ +static bool trans_PCEQW(DisasContext *ctx, arg_rtype *a) +{ + return trans_parallel_compare(ctx, a, TCG_COND_EQ, 32); +} + /* * LZC (1 instruction) * ------------------- @@ -177,6 +334,68 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a) * SQ rt, offset(base) Store Quadword */ +static bool trans_LQ(DisasContext *ctx, arg_itype *a) +{ + TCGv_i64 t0; + TCGv addr; + + if (a->rt == 0) { + /* nop */ + return true; + } + + t0 = tcg_temp_new_i64(); + addr = tcg_temp_new(); + + gen_base_offset_addr(ctx, addr, a->base, a->offset); + /* + * Clear least-significant four bits of the effective + * address, effectively creating an aligned address. + */ + tcg_gen_andi_tl(addr, addr, ~0xf); + + /* Lower half */ + tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEQ); + gen_store_gpr(t0, a->rt); + + /* Upper half */ + tcg_gen_addi_i64(addr, addr, 8); + tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEQ); + gen_store_gpr_hi(t0, a->rt); + + tcg_temp_free(t0); + tcg_temp_free(addr); + + return true; +} + +static bool trans_SQ(DisasContext *ctx, arg_itype *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv addr = tcg_temp_new(); + + gen_base_offset_addr(ctx, addr, a->base, a->offset); + /* + * Clear least-significant four bits of the effective + * address, effectively creating an aligned address. + */ + tcg_gen_andi_tl(addr, addr, ~0xf); + + /* Lower half */ + gen_load_gpr(t0, a->rt); + tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEQ); + + /* Upper half */ + tcg_gen_addi_i64(addr, addr, 8); + gen_load_gpr_hi(t0, a->rt); + tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEQ); + + tcg_temp_free(addr); + tcg_temp_free(t0); + + return true; +} + /* * Multiply and Divide (19 instructions) * ------------------------------------- @@ -217,6 +436,141 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a) * PEXTLW rd, rs, rt Parallel Extend Lower from Word */ +/* Parallel Pack to Word */ +static bool trans_PPACW(DisasContext *ctx, arg_rtype *a) +{ + TCGv_i64 a0, b0, t0; + + if (a->rd == 0) { + /* nop */ + return true; + } + + a0 = tcg_temp_new_i64(); + b0 = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + + gen_load_gpr(a0, a->rs); + gen_load_gpr(b0, a->rt); + + gen_load_gpr_hi(t0, a->rt); /* b1 */ + tcg_gen_deposit_i64(cpu_gpr[a->rd], b0, t0, 32, 32); + + gen_load_gpr_hi(t0, a->rs); /* a1 */ + tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], a0, t0, 32, 32); + + tcg_temp_free(t0); + tcg_temp_free(b0); + tcg_temp_free(a0); + + return true; +} + +static void gen_pextw(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_deposit_i64(dl, b, a, 32, 32); + tcg_gen_shri_i64(b, b, 32); + tcg_gen_deposit_i64(dh, a, b, 0, 32); +} + +static bool trans_PEXTLx(DisasContext *ctx, arg_rtype *a, unsigned wlen) +{ + TCGv_i64 ax, bx; + + if (a->rd == 0) { + /* nop */ + return true; + } + + ax = tcg_temp_new_i64(); + bx = tcg_temp_new_i64(); + + gen_load_gpr(ax, a->rs); + gen_load_gpr(bx, a->rt); + + /* Lower half */ + for (int i = 0; i < 64 / (2 * wlen); i++) { + tcg_gen_deposit_i64(cpu_gpr[a->rd], + cpu_gpr[a->rd], bx, 2 * wlen * i, wlen); + tcg_gen_deposit_i64(cpu_gpr[a->rd], + cpu_gpr[a->rd], ax, 2 * wlen * i + wlen, wlen); + tcg_gen_shri_i64(bx, bx, wlen); + tcg_gen_shri_i64(ax, ax, wlen); + } + /* Upper half */ + for (int i = 0; i < 64 / (2 * wlen); i++) { + tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], + cpu_gpr_hi[a->rd], bx, 2 * wlen * i, wlen); + tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], + cpu_gpr_hi[a->rd], ax, 2 * wlen * i + wlen, wlen); + tcg_gen_shri_i64(bx, bx, wlen); + tcg_gen_shri_i64(ax, ax, wlen); + } + + tcg_temp_free(bx); + tcg_temp_free(ax); + + return true; +} + +/* Parallel Extend Lower from Byte */ +static bool trans_PEXTLB(DisasContext *ctx, arg_rtype *a) +{ + return trans_PEXTLx(ctx, a, 8); +} + +/* Parallel Extend Lower from Halfword */ +static bool trans_PEXTLH(DisasContext *ctx, arg_rtype *a) +{ + return trans_PEXTLx(ctx, a, 16); +} + +/* Parallel Extend Lower from Word */ +static bool trans_PEXTLW(DisasContext *ctx, arg_rtype *a) +{ + TCGv_i64 ax, bx; + + if (a->rd == 0) { + /* nop */ + return true; + } + + ax = tcg_temp_new_i64(); + bx = tcg_temp_new_i64(); + + gen_load_gpr(ax, a->rs); + gen_load_gpr(bx, a->rt); + gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx); + + tcg_temp_free(bx); + tcg_temp_free(ax); + + return true; +} + +/* Parallel Extend Upper from Word */ +static bool trans_PEXTUW(DisasContext *ctx, arg_rtype *a) +{ + TCGv_i64 ax, bx; + + if (a->rd == 0) { + /* nop */ + return true; + } + + ax = tcg_temp_new_i64(); + bx = tcg_temp_new_i64(); + + gen_load_gpr_hi(ax, a->rs); + gen_load_gpr_hi(bx, a->rt); + gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx); + + tcg_temp_free(bx); + tcg_temp_free(ax); + + return true; +} + /* * Others (16 instructions) * ------------------------ @@ -301,3 +655,31 @@ static bool trans_PCPYUD(DisasContext *s, arg_rtype *a) return true; } + +/* Parallel Rotate 3 Words Left */ +static bool trans_PROT3W(DisasContext *ctx, arg_rtype *a) +{ + TCGv_i64 ax; + + if (a->rd == 0) { + /* nop */ + return true; + } + if (a->rt == 0) { + tcg_gen_movi_i64(cpu_gpr[a->rd], 0); + tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0); + return true; + } + + ax = tcg_temp_new_i64(); + + tcg_gen_mov_i64(ax, cpu_gpr_hi[a->rt]); + tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], ax, cpu_gpr[a->rt], 0, 32); + + tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rt], ax, 0, 32); + tcg_gen_rotri_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], 32); + + tcg_temp_free(ax); + + return true; +} |