qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

tx79_translate.c (19786B)


      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 
     35 bool 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 
     67 static bool trans_MFHI1(DisasContext *ctx, arg_r *a)
     68 {
     69     gen_store_gpr(cpu_HI[1], a->rd);
     70 
     71     return true;
     72 }
     73 
     74 static bool trans_MFLO1(DisasContext *ctx, arg_r *a)
     75 {
     76     gen_store_gpr(cpu_LO[1], a->rd);
     77 
     78     return true;
     79 }
     80 
     81 static bool trans_MTHI1(DisasContext *ctx, arg_r *a)
     82 {
     83     gen_load_gpr(cpu_HI[1], a->rs);
     84 
     85     return true;
     86 }
     87 
     88 static 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 
    119 static 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 */
    149 static 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 */
    155 static 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 */
    161 static 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 */
    192 static 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 */
    198 static 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 */
    204 static 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 */
    210 static 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 
    240 static 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 */
    289 static 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 */
    295 static 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 */
    301 static 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 */
    307 static 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 */
    313 static 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 */
    319 static 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 
    337 static 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 
    372 static 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 */
    440 static 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 
    469 static 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 
    476 static 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 */
    517 static bool trans_PEXTLB(DisasContext *ctx, arg_r *a)
    518 {
    519     return trans_PEXTLx(ctx, a, 8);
    520 }
    521 
    522 /* Parallel Extend Lower from Halfword */
    523 static bool trans_PEXTLH(DisasContext *ctx, arg_r *a)
    524 {
    525     return trans_PEXTLx(ctx, a, 16);
    526 }
    527 
    528 /* Parallel Extend Lower from Word */
    529 static 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 */
    552 static 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 */
    596 static 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 */
    618 static 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 */
    641 static 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 */
    660 static 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 }