qemu/target/mips/tcg/tx79_translate.c
<<
>>
Prefs
   1/*
   2 * Toshiba TX79-specific instructions translation routines
   3 *
   4 *  Copyright (c) 2018 Fredrik Noring
   5 *  Copyright (c) 2021 Philippe Mathieu-Daudé
   6 *
   7 * SPDX-License-Identifier: GPL-2.0-or-later
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "tcg/tcg-op.h"
  12#include "tcg/tcg-op-gvec.h"
  13#include "exec/helper-gen.h"
  14#include "translate.h"
  15
  16/* Include the auto-generated decoder.  */
  17#include "decode-tx79.c.inc"
  18
  19/*
  20 *     Overview of the TX79-specific instruction set
  21 *     =============================================
  22 *
  23 * The R5900 and the C790 have 128-bit wide GPRs, where the upper 64 bits
  24 * are only used by the specific quadword (128-bit) LQ/SQ load/store
  25 * instructions and certain multimedia instructions (MMIs). These MMIs
  26 * configure the 128-bit data path as two 64-bit, four 32-bit, eight 16-bit
  27 * or sixteen 8-bit paths.
  28 *
  29 * Reference:
  30 *
  31 * The Toshiba TX System RISC TX79 Core Architecture manual,
  32 * https://wiki.qemu.org/File:C790.pdf
  33 */
  34
  35bool decode_ext_tx79(DisasContext *ctx, uint32_t insn)
  36{
  37    if (TARGET_LONG_BITS == 64 && decode_tx79(ctx, insn)) {
  38        return true;
  39    }
  40    return false;
  41}
  42
  43/*
  44 *     Three-Operand Multiply and Multiply-Add (4 instructions)
  45 *     --------------------------------------------------------
  46 * MADD    [rd,] rs, rt      Multiply/Add
  47 * MADDU   [rd,] rs, rt      Multiply/Add Unsigned
  48 * MULT    [rd,] rs, rt      Multiply (3-operand)
  49 * MULTU   [rd,] rs, rt      Multiply Unsigned (3-operand)
  50 */
  51
  52/*
  53 *     Multiply Instructions for Pipeline 1 (10 instructions)
  54 *     ------------------------------------------------------
  55 * MULT1   [rd,] rs, rt      Multiply Pipeline 1
  56 * MULTU1  [rd,] rs, rt      Multiply Unsigned Pipeline 1
  57 * DIV1    rs, rt            Divide Pipeline 1
  58 * DIVU1   rs, rt            Divide Unsigned Pipeline 1
  59 * MADD1   [rd,] rs, rt      Multiply-Add Pipeline 1
  60 * MADDU1  [rd,] rs, rt      Multiply-Add Unsigned Pipeline 1
  61 * MFHI1   rd                Move From HI1 Register
  62 * MFLO1   rd                Move From LO1 Register
  63 * MTHI1   rs                Move To HI1 Register
  64 * MTLO1   rs                Move To LO1 Register
  65 */
  66
  67static bool trans_MFHI1(DisasContext *ctx, arg_r *a)
  68{
  69    gen_store_gpr(cpu_HI[1], a->rd);
  70
  71    return true;
  72}
  73
  74static bool trans_MFLO1(DisasContext *ctx, arg_r *a)
  75{
  76    gen_store_gpr(cpu_LO[1], a->rd);
  77
  78    return true;
  79}
  80
  81static bool trans_MTHI1(DisasContext *ctx, arg_r *a)
  82{
  83    gen_load_gpr(cpu_HI[1], a->rs);
  84
  85    return true;
  86}
  87
  88static bool trans_MTLO1(DisasContext *ctx, arg_r *a)
  89{
  90    gen_load_gpr(cpu_LO[1], a->rs);
  91
  92    return true;
  93}
  94
  95/*
  96 *     Arithmetic (19 instructions)
  97 *     ----------------------------
  98 * PADDB   rd, rs, rt        Parallel Add Byte
  99 * PSUBB   rd, rs, rt        Parallel Subtract Byte
 100 * PADDH   rd, rs, rt        Parallel Add Halfword
 101 * PSUBH   rd, rs, rt        Parallel Subtract Halfword
 102 * PADDW   rd, rs, rt        Parallel Add Word
 103 * PSUBW   rd, rs, rt        Parallel Subtract Word
 104 * PADSBH  rd, rs, rt        Parallel Add/Subtract Halfword
 105 * PADDSB  rd, rs, rt        Parallel Add with Signed Saturation Byte
 106 * PSUBSB  rd, rs, rt        Parallel Subtract with Signed Saturation Byte
 107 * PADDSH  rd, rs, rt        Parallel Add with Signed Saturation Halfword
 108 * PSUBSH  rd, rs, rt        Parallel Subtract with Signed Saturation Halfword
 109 * PADDSW  rd, rs, rt        Parallel Add with Signed Saturation Word
 110 * PSUBSW  rd, rs, rt        Parallel Subtract with Signed Saturation Word
 111 * PADDUB  rd, rs, rt        Parallel Add with Unsigned saturation Byte
 112 * PSUBUB  rd, rs, rt        Parallel Subtract with Unsigned saturation Byte
 113 * PADDUH  rd, rs, rt        Parallel Add with Unsigned saturation Halfword
 114 * PSUBUH  rd, rs, rt        Parallel Subtract with Unsigned saturation Halfword
 115 * PADDUW  rd, rs, rt        Parallel Add with Unsigned saturation Word
 116 * PSUBUW  rd, rs, rt        Parallel Subtract with Unsigned saturation Word
 117 */
 118
 119static bool trans_parallel_arith(DisasContext *ctx, arg_r *a,
 120                                 void (*gen_logic_i64)(TCGv_i64, TCGv_i64, TCGv_i64))
 121{
 122    TCGv_i64 ax, bx;
 123
 124    if (a->rd == 0) {
 125        /* nop */
 126        return true;
 127    }
 128
 129    ax = tcg_temp_new_i64();
 130    bx = tcg_temp_new_i64();
 131
 132    /* Lower half */
 133    gen_load_gpr(ax, a->rs);
 134    gen_load_gpr(bx, a->rt);
 135    gen_logic_i64(cpu_gpr[a->rd], ax, bx);
 136
 137    /* Upper half */
 138    gen_load_gpr_hi(ax, a->rs);
 139    gen_load_gpr_hi(bx, a->rt);
 140    gen_logic_i64(cpu_gpr_hi[a->rd], ax, bx);
 141
 142    tcg_temp_free(bx);
 143    tcg_temp_free(ax);
 144
 145    return true;
 146}
 147
 148/* Parallel Subtract Byte */
 149static bool trans_PSUBB(DisasContext *ctx, arg_r *a)
 150{
 151    return trans_parallel_arith(ctx, a, tcg_gen_vec_sub8_i64);
 152}
 153
 154/* Parallel Subtract Halfword */
 155static bool trans_PSUBH(DisasContext *ctx, arg_r *a)
 156{
 157    return trans_parallel_arith(ctx, a, tcg_gen_vec_sub16_i64);
 158}
 159
 160/* Parallel Subtract Word */
 161static bool trans_PSUBW(DisasContext *ctx, arg_r *a)
 162{
 163    return trans_parallel_arith(ctx, a, tcg_gen_vec_sub32_i64);
 164}
 165
 166/*
 167 *     Min/Max (4 instructions)
 168 *     ------------------------
 169 * PMAXH   rd, rs, rt        Parallel Maximum Halfword
 170 * PMINH   rd, rs, rt        Parallel Minimum Halfword
 171 * PMAXW   rd, rs, rt        Parallel Maximum Word
 172 * PMINW   rd, rs, rt        Parallel Minimum Word
 173 */
 174
 175/*
 176 *     Absolute (2 instructions)
 177 *     -------------------------
 178 * PABSH   rd, rt            Parallel Absolute Halfword
 179 * PABSW   rd, rt            Parallel Absolute Word
 180 */
 181
 182/*
 183 *     Logical (4 instructions)
 184 *     ------------------------
 185 * PAND    rd, rs, rt        Parallel AND
 186 * POR     rd, rs, rt        Parallel OR
 187 * PXOR    rd, rs, rt        Parallel XOR
 188 * PNOR    rd, rs, rt        Parallel NOR
 189 */
 190
 191/* Parallel And */
 192static bool trans_PAND(DisasContext *ctx, arg_r *a)
 193{
 194    return trans_parallel_arith(ctx, a, tcg_gen_and_i64);
 195}
 196
 197/* Parallel Or */
 198static bool trans_POR(DisasContext *ctx, arg_r *a)
 199{
 200    return trans_parallel_arith(ctx, a, tcg_gen_or_i64);
 201}
 202
 203/* Parallel Exclusive Or */
 204static bool trans_PXOR(DisasContext *ctx, arg_r *a)
 205{
 206    return trans_parallel_arith(ctx, a, tcg_gen_xor_i64);
 207}
 208
 209/* Parallel Not Or */
 210static bool trans_PNOR(DisasContext *ctx, arg_r *a)
 211{
 212    return trans_parallel_arith(ctx, a, tcg_gen_nor_i64);
 213}
 214
 215/*
 216 *     Shift (9 instructions)
 217 *     ----------------------
 218 * PSLLH   rd, rt, sa        Parallel Shift Left Logical Halfword
 219 * PSRLH   rd, rt, sa        Parallel Shift Right Logical Halfword
 220 * PSRAH   rd, rt, sa        Parallel Shift Right Arithmetic Halfword
 221 * PSLLW   rd, rt, sa        Parallel Shift Left Logical Word
 222 * PSRLW   rd, rt, sa        Parallel Shift Right Logical Word
 223 * PSRAW   rd, rt, sa        Parallel Shift Right Arithmetic Word
 224 * PSLLVW  rd, rt, rs        Parallel Shift Left Logical Variable Word
 225 * PSRLVW  rd, rt, rs        Parallel Shift Right Logical Variable Word
 226 * PSRAVW  rd, rt, rs        Parallel Shift Right Arithmetic Variable Word
 227 */
 228
 229/*
 230 *     Compare (6 instructions)
 231 *     ------------------------
 232 * PCGTB   rd, rs, rt        Parallel Compare for Greater Than Byte
 233 * PCEQB   rd, rs, rt        Parallel Compare for Equal Byte
 234 * PCGTH   rd, rs, rt        Parallel Compare for Greater Than Halfword
 235 * PCEQH   rd, rs, rt        Parallel Compare for Equal Halfword
 236 * PCGTW   rd, rs, rt        Parallel Compare for Greater Than Word
 237 * PCEQW   rd, rs, rt        Parallel Compare for Equal Word
 238 */
 239
 240static bool trans_parallel_compare(DisasContext *ctx, arg_r *a,
 241                                   TCGCond cond, unsigned wlen)
 242{
 243    TCGv_i64 c0, c1, ax, bx, t0, t1, t2;
 244
 245    if (a->rd == 0) {
 246        /* nop */
 247        return true;
 248    }
 249
 250    c0 = tcg_const_tl(0);
 251    c1 = tcg_const_tl(0xffffffff);
 252    ax = tcg_temp_new_i64();
 253    bx = tcg_temp_new_i64();
 254    t0 = tcg_temp_new_i64();
 255    t1 = tcg_temp_new_i64();
 256    t2 = tcg_temp_new_i64();
 257
 258    /* Lower half */
 259    gen_load_gpr(ax, a->rs);
 260    gen_load_gpr(bx, a->rt);
 261    for (int i = 0; i < (64 / wlen); i++) {
 262        tcg_gen_sextract_i64(t0, ax, wlen * i, wlen);
 263        tcg_gen_sextract_i64(t1, bx, wlen * i, wlen);
 264        tcg_gen_movcond_i64(cond, t2, t1, t0, c1, c0);
 265        tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], t2, wlen * i, wlen);
 266    }
 267    /* Upper half */
 268    gen_load_gpr_hi(ax, a->rs);
 269    gen_load_gpr_hi(bx, a->rt);
 270    for (int i = 0; i < (64 / wlen); i++) {
 271        tcg_gen_sextract_i64(t0, ax, wlen * i, wlen);
 272        tcg_gen_sextract_i64(t1, bx, wlen * i, wlen);
 273        tcg_gen_movcond_i64(cond, t2, t1, t0, c1, c0);
 274        tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], t2, wlen * i, wlen);
 275    }
 276
 277    tcg_temp_free(t2);
 278    tcg_temp_free(t1);
 279    tcg_temp_free(t0);
 280    tcg_temp_free(bx);
 281    tcg_temp_free(ax);
 282    tcg_temp_free(c1);
 283    tcg_temp_free(c0);
 284
 285    return true;
 286}
 287
 288/* Parallel Compare for Greater Than Byte */
 289static bool trans_PCGTB(DisasContext *ctx, arg_r *a)
 290{
 291    return trans_parallel_compare(ctx, a, TCG_COND_GE, 8);
 292}
 293
 294/* Parallel Compare for Equal Byte */
 295static bool trans_PCEQB(DisasContext *ctx, arg_r *a)
 296{
 297    return trans_parallel_compare(ctx, a, TCG_COND_EQ, 8);
 298}
 299
 300/* Parallel Compare for Greater Than Halfword */
 301static bool trans_PCGTH(DisasContext *ctx, arg_r *a)
 302{
 303    return trans_parallel_compare(ctx, a, TCG_COND_GE, 16);
 304}
 305
 306/* Parallel Compare for Equal Halfword */
 307static bool trans_PCEQH(DisasContext *ctx, arg_r *a)
 308{
 309    return trans_parallel_compare(ctx, a, TCG_COND_EQ, 16);
 310}
 311
 312/* Parallel Compare for Greater Than Word */
 313static bool trans_PCGTW(DisasContext *ctx, arg_r *a)
 314{
 315    return trans_parallel_compare(ctx, a, TCG_COND_GE, 32);
 316}
 317
 318/* Parallel Compare for Equal Word */
 319static bool trans_PCEQW(DisasContext *ctx, arg_r *a)
 320{
 321    return trans_parallel_compare(ctx, a, TCG_COND_EQ, 32);
 322}
 323
 324/*
 325 *     LZC (1 instruction)
 326 *     -------------------
 327 * PLZCW   rd, rs            Parallel Leading Zero or One Count Word
 328 */
 329
 330/*
 331 *     Quadword Load and Store (2 instructions)
 332 *     ----------------------------------------
 333 * LQ      rt, offset(base)  Load Quadword
 334 * SQ      rt, offset(base)  Store Quadword
 335 */
 336
 337static bool trans_LQ(DisasContext *ctx, arg_i *a)
 338{
 339    TCGv_i64 t0;
 340    TCGv addr;
 341
 342    if (a->rt == 0) {
 343        /* nop */
 344        return true;
 345    }
 346
 347    t0 = tcg_temp_new_i64();
 348    addr = tcg_temp_new();
 349
 350    gen_base_offset_addr(ctx, addr, a->base, a->offset);
 351    /*
 352     * Clear least-significant four bits of the effective
 353     * address, effectively creating an aligned address.
 354     */
 355    tcg_gen_andi_tl(addr, addr, ~0xf);
 356
 357    /* Lower half */
 358    tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
 359    gen_store_gpr(t0, a->rt);
 360
 361    /* Upper half */
 362    tcg_gen_addi_i64(addr, addr, 8);
 363    tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
 364    gen_store_gpr_hi(t0, a->rt);
 365
 366    tcg_temp_free(t0);
 367    tcg_temp_free(addr);
 368
 369    return true;
 370}
 371
 372static bool trans_SQ(DisasContext *ctx, arg_i *a)
 373{
 374    TCGv_i64 t0 = tcg_temp_new_i64();
 375    TCGv addr = tcg_temp_new();
 376
 377    gen_base_offset_addr(ctx, addr, a->base, a->offset);
 378    /*
 379     * Clear least-significant four bits of the effective
 380     * address, effectively creating an aligned address.
 381     */
 382    tcg_gen_andi_tl(addr, addr, ~0xf);
 383
 384    /* Lower half */
 385    gen_load_gpr(t0, a->rt);
 386    tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
 387
 388    /* Upper half */
 389    tcg_gen_addi_i64(addr, addr, 8);
 390    gen_load_gpr_hi(t0, a->rt);
 391    tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
 392
 393    tcg_temp_free(addr);
 394    tcg_temp_free(t0);
 395
 396    return true;
 397}
 398
 399/*
 400 *     Multiply and Divide (19 instructions)
 401 *     -------------------------------------
 402 * PMULTW  rd, rs, rt        Parallel Multiply Word
 403 * PMULTUW rd, rs, rt        Parallel Multiply Unsigned Word
 404 * PDIVW   rs, rt            Parallel Divide Word
 405 * PDIVUW  rs, rt            Parallel Divide Unsigned Word
 406 * PMADDW  rd, rs, rt        Parallel Multiply-Add Word
 407 * PMADDUW rd, rs, rt        Parallel Multiply-Add Unsigned Word
 408 * PMSUBW  rd, rs, rt        Parallel Multiply-Subtract Word
 409 * PMULTH  rd, rs, rt        Parallel Multiply Halfword
 410 * PMADDH  rd, rs, rt        Parallel Multiply-Add Halfword
 411 * PMSUBH  rd, rs, rt        Parallel Multiply-Subtract Halfword
 412 * PHMADH  rd, rs, rt        Parallel Horizontal Multiply-Add Halfword
 413 * PHMSBH  rd, rs, rt        Parallel Horizontal Multiply-Subtract Halfword
 414 * PDIVBW  rs, rt            Parallel Divide Broadcast Word
 415 * PMFHI   rd                Parallel Move From HI Register
 416 * PMFLO   rd                Parallel Move From LO Register
 417 * PMTHI   rs                Parallel Move To HI Register
 418 * PMTLO   rs                Parallel Move To LO Register
 419 * PMFHL   rd                Parallel Move From HI/LO Register
 420 * PMTHL   rs                Parallel Move To HI/LO Register
 421 */
 422
 423/*
 424 *     Pack/Extend (11 instructions)
 425 *     -----------------------------
 426 * PPAC5   rd, rt            Parallel Pack to 5 bits
 427 * PPACB   rd, rs, rt        Parallel Pack to Byte
 428 * PPACH   rd, rs, rt        Parallel Pack to Halfword
 429 * PPACW   rd, rs, rt        Parallel Pack to Word
 430 * PEXT5   rd, rt            Parallel Extend Upper from 5 bits
 431 * PEXTUB  rd, rs, rt        Parallel Extend Upper from Byte
 432 * PEXTLB  rd, rs, rt        Parallel Extend Lower from Byte
 433 * PEXTUH  rd, rs, rt        Parallel Extend Upper from Halfword
 434 * PEXTLH  rd, rs, rt        Parallel Extend Lower from Halfword
 435 * PEXTUW  rd, rs, rt        Parallel Extend Upper from Word
 436 * PEXTLW  rd, rs, rt        Parallel Extend Lower from Word
 437 */
 438
 439/* Parallel Pack to Word */
 440static bool trans_PPACW(DisasContext *ctx, arg_r *a)
 441{
 442    TCGv_i64 a0, b0, t0;
 443
 444    if (a->rd == 0) {
 445        /* nop */
 446        return true;
 447    }
 448
 449    a0 = tcg_temp_new_i64();
 450    b0 = tcg_temp_new_i64();
 451    t0 = tcg_temp_new_i64();
 452
 453    gen_load_gpr(a0, a->rs);
 454    gen_load_gpr(b0, a->rt);
 455
 456    gen_load_gpr_hi(t0, a->rt); /* b1 */
 457    tcg_gen_deposit_i64(cpu_gpr[a->rd], b0, t0, 32, 32);
 458
 459    gen_load_gpr_hi(t0, a->rs); /* a1 */
 460    tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], a0, t0, 32, 32);
 461
 462    tcg_temp_free(t0);
 463    tcg_temp_free(b0);
 464    tcg_temp_free(a0);
 465
 466    return true;
 467}
 468
 469static void gen_pextw(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 a, TCGv_i64 b)
 470{
 471    tcg_gen_deposit_i64(dl, b, a, 32, 32);
 472    tcg_gen_shri_i64(b, b, 32);
 473    tcg_gen_deposit_i64(dh, a, b, 0, 32);
 474}
 475
 476static bool trans_PEXTLx(DisasContext *ctx, arg_r *a, unsigned wlen)
 477{
 478    TCGv_i64 ax, bx;
 479
 480    if (a->rd == 0) {
 481        /* nop */
 482        return true;
 483    }
 484
 485    ax = tcg_temp_new_i64();
 486    bx = tcg_temp_new_i64();
 487
 488    gen_load_gpr(ax, a->rs);
 489    gen_load_gpr(bx, a->rt);
 490
 491    /* Lower half */
 492    for (int i = 0; i < 64 / (2 * wlen); i++) {
 493        tcg_gen_deposit_i64(cpu_gpr[a->rd],
 494                            cpu_gpr[a->rd], bx, 2 * wlen * i, wlen);
 495        tcg_gen_deposit_i64(cpu_gpr[a->rd],
 496                            cpu_gpr[a->rd], ax, 2 * wlen * i + wlen, wlen);
 497        tcg_gen_shri_i64(bx, bx, wlen);
 498        tcg_gen_shri_i64(ax, ax, wlen);
 499    }
 500    /* Upper half */
 501    for (int i = 0; i < 64 / (2 * wlen); i++) {
 502        tcg_gen_deposit_i64(cpu_gpr_hi[a->rd],
 503                            cpu_gpr_hi[a->rd], bx, 2 * wlen * i, wlen);
 504        tcg_gen_deposit_i64(cpu_gpr_hi[a->rd],
 505                            cpu_gpr_hi[a->rd], ax, 2 * wlen * i + wlen, wlen);
 506        tcg_gen_shri_i64(bx, bx, wlen);
 507        tcg_gen_shri_i64(ax, ax, wlen);
 508    }
 509
 510    tcg_temp_free(bx);
 511    tcg_temp_free(ax);
 512
 513    return true;
 514}
 515
 516/* Parallel Extend Lower from Byte */
 517static bool trans_PEXTLB(DisasContext *ctx, arg_r *a)
 518{
 519    return trans_PEXTLx(ctx, a, 8);
 520}
 521
 522/* Parallel Extend Lower from Halfword */
 523static bool trans_PEXTLH(DisasContext *ctx, arg_r *a)
 524{
 525    return trans_PEXTLx(ctx, a, 16);
 526}
 527
 528/* Parallel Extend Lower from Word */
 529static bool trans_PEXTLW(DisasContext *ctx, arg_r *a)
 530{
 531    TCGv_i64 ax, bx;
 532
 533    if (a->rd == 0) {
 534        /* nop */
 535        return true;
 536    }
 537
 538    ax = tcg_temp_new_i64();
 539    bx = tcg_temp_new_i64();
 540
 541    gen_load_gpr(ax, a->rs);
 542    gen_load_gpr(bx, a->rt);
 543    gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx);
 544
 545    tcg_temp_free(bx);
 546    tcg_temp_free(ax);
 547
 548    return true;
 549}
 550
 551/* Parallel Extend Upper from Word */
 552static bool trans_PEXTUW(DisasContext *ctx, arg_r *a)
 553{
 554    TCGv_i64 ax, bx;
 555
 556    if (a->rd == 0) {
 557        /* nop */
 558        return true;
 559    }
 560
 561    ax = tcg_temp_new_i64();
 562    bx = tcg_temp_new_i64();
 563
 564    gen_load_gpr_hi(ax, a->rs);
 565    gen_load_gpr_hi(bx, a->rt);
 566    gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx);
 567
 568    tcg_temp_free(bx);
 569    tcg_temp_free(ax);
 570
 571    return true;
 572}
 573
 574/*
 575 *     Others (16 instructions)
 576 *     ------------------------
 577 * PCPYH   rd, rt            Parallel Copy Halfword
 578 * PCPYLD  rd, rs, rt        Parallel Copy Lower Doubleword
 579 * PCPYUD  rd, rs, rt        Parallel Copy Upper Doubleword
 580 * PREVH   rd, rt            Parallel Reverse Halfword
 581 * PINTH   rd, rs, rt        Parallel Interleave Halfword
 582 * PINTEH  rd, rs, rt        Parallel Interleave Even Halfword
 583 * PEXEH   rd, rt            Parallel Exchange Even Halfword
 584 * PEXCH   rd, rt            Parallel Exchange Center Halfword
 585 * PEXEW   rd, rt            Parallel Exchange Even Word
 586 * PEXCW   rd, rt            Parallel Exchange Center Word
 587 * QFSRV   rd, rs, rt        Quadword Funnel Shift Right Variable
 588 * MFSA    rd                Move from Shift Amount Register
 589 * MTSA    rs                Move to Shift Amount Register
 590 * MTSAB   rs, immediate     Move Byte Count to Shift Amount Register
 591 * MTSAH   rs, immediate     Move Halfword Count to Shift Amount Register
 592 * PROT3W  rd, rt            Parallel Rotate 3 Words
 593 */
 594
 595/* Parallel Copy Halfword */
 596static bool trans_PCPYH(DisasContext *s, arg_r *a)
 597{
 598    if (a->rd == 0) {
 599        /* nop */
 600        return true;
 601    }
 602
 603    if (a->rt == 0) {
 604        tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
 605        tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
 606        return true;
 607    }
 608
 609    tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rt], cpu_gpr[a->rt], 16, 16);
 610    tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], cpu_gpr[a->rd], 32, 32);
 611    tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rt], cpu_gpr_hi[a->rt], 16, 16);
 612    tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], 32, 32);
 613
 614    return true;
 615}
 616
 617/* Parallel Copy Lower Doubleword */
 618static bool trans_PCPYLD(DisasContext *s, arg_r *a)
 619{
 620    if (a->rd == 0) {
 621        /* nop */
 622        return true;
 623    }
 624
 625    if (a->rs == 0) {
 626        tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
 627    } else {
 628        tcg_gen_mov_i64(cpu_gpr_hi[a->rd], cpu_gpr[a->rs]);
 629    }
 630
 631    if (a->rt == 0) {
 632        tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
 633    } else if (a->rd != a->rt) {
 634        tcg_gen_mov_i64(cpu_gpr[a->rd], cpu_gpr[a->rt]);
 635    }
 636
 637    return true;
 638}
 639
 640/* Parallel Copy Upper Doubleword */
 641static bool trans_PCPYUD(DisasContext *s, arg_r *a)
 642{
 643    if (a->rd == 0) {
 644        /* nop */
 645        return true;
 646    }
 647
 648    gen_load_gpr_hi(cpu_gpr[a->rd], a->rs);
 649
 650    if (a->rt == 0) {
 651        tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
 652    } else if (a->rd != a->rt) {
 653        tcg_gen_mov_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rt]);
 654    }
 655
 656    return true;
 657}
 658
 659/* Parallel Rotate 3 Words Left */
 660static bool trans_PROT3W(DisasContext *ctx, arg_r *a)
 661{
 662    TCGv_i64 ax;
 663
 664    if (a->rd == 0) {
 665        /* nop */
 666        return true;
 667    }
 668    if (a->rt == 0) {
 669        tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
 670        tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
 671        return true;
 672    }
 673
 674    ax = tcg_temp_new_i64();
 675
 676    tcg_gen_mov_i64(ax, cpu_gpr_hi[a->rt]);
 677    tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], ax, cpu_gpr[a->rt], 0, 32);
 678
 679    tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rt], ax, 0, 32);
 680    tcg_gen_rotri_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], 32);
 681
 682    tcg_temp_free(ax);
 683
 684    return true;
 685}
 686