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