aboutsummaryrefslogtreecommitdiff
path: root/target/mips/tcg/tx79_translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/mips/tcg/tx79_translate.c')
-rw-r--r--target/mips/tcg/tx79_translate.c382
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;
+}