xref: /openbmc/qemu/target/mips/tcg/tx79_translate.c (revision d044b7c3)
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     return true;
142 }
143 
144 /* Parallel Subtract Byte */
145 static bool trans_PSUBB(DisasContext *ctx, arg_r *a)
146 {
147     return trans_parallel_arith(ctx, a, tcg_gen_vec_sub8_i64);
148 }
149 
150 /* Parallel Subtract Halfword */
151 static bool trans_PSUBH(DisasContext *ctx, arg_r *a)
152 {
153     return trans_parallel_arith(ctx, a, tcg_gen_vec_sub16_i64);
154 }
155 
156 /* Parallel Subtract Word */
157 static bool trans_PSUBW(DisasContext *ctx, arg_r *a)
158 {
159     return trans_parallel_arith(ctx, a, tcg_gen_vec_sub32_i64);
160 }
161 
162 /*
163  *     Min/Max (4 instructions)
164  *     ------------------------
165  * PMAXH   rd, rs, rt        Parallel Maximum Halfword
166  * PMINH   rd, rs, rt        Parallel Minimum Halfword
167  * PMAXW   rd, rs, rt        Parallel Maximum Word
168  * PMINW   rd, rs, rt        Parallel Minimum Word
169  */
170 
171 /*
172  *     Absolute (2 instructions)
173  *     -------------------------
174  * PABSH   rd, rt            Parallel Absolute Halfword
175  * PABSW   rd, rt            Parallel Absolute Word
176  */
177 
178 /*
179  *     Logical (4 instructions)
180  *     ------------------------
181  * PAND    rd, rs, rt        Parallel AND
182  * POR     rd, rs, rt        Parallel OR
183  * PXOR    rd, rs, rt        Parallel XOR
184  * PNOR    rd, rs, rt        Parallel NOR
185  */
186 
187 /* Parallel And */
188 static bool trans_PAND(DisasContext *ctx, arg_r *a)
189 {
190     return trans_parallel_arith(ctx, a, tcg_gen_and_i64);
191 }
192 
193 /* Parallel Or */
194 static bool trans_POR(DisasContext *ctx, arg_r *a)
195 {
196     return trans_parallel_arith(ctx, a, tcg_gen_or_i64);
197 }
198 
199 /* Parallel Exclusive Or */
200 static bool trans_PXOR(DisasContext *ctx, arg_r *a)
201 {
202     return trans_parallel_arith(ctx, a, tcg_gen_xor_i64);
203 }
204 
205 /* Parallel Not Or */
206 static bool trans_PNOR(DisasContext *ctx, arg_r *a)
207 {
208     return trans_parallel_arith(ctx, a, tcg_gen_nor_i64);
209 }
210 
211 /*
212  *     Shift (9 instructions)
213  *     ----------------------
214  * PSLLH   rd, rt, sa        Parallel Shift Left Logical Halfword
215  * PSRLH   rd, rt, sa        Parallel Shift Right Logical Halfword
216  * PSRAH   rd, rt, sa        Parallel Shift Right Arithmetic Halfword
217  * PSLLW   rd, rt, sa        Parallel Shift Left Logical Word
218  * PSRLW   rd, rt, sa        Parallel Shift Right Logical Word
219  * PSRAW   rd, rt, sa        Parallel Shift Right Arithmetic Word
220  * PSLLVW  rd, rt, rs        Parallel Shift Left Logical Variable Word
221  * PSRLVW  rd, rt, rs        Parallel Shift Right Logical Variable Word
222  * PSRAVW  rd, rt, rs        Parallel Shift Right Arithmetic Variable Word
223  */
224 
225 /*
226  *     Compare (6 instructions)
227  *     ------------------------
228  * PCGTB   rd, rs, rt        Parallel Compare for Greater Than Byte
229  * PCEQB   rd, rs, rt        Parallel Compare for Equal Byte
230  * PCGTH   rd, rs, rt        Parallel Compare for Greater Than Halfword
231  * PCEQH   rd, rs, rt        Parallel Compare for Equal Halfword
232  * PCGTW   rd, rs, rt        Parallel Compare for Greater Than Word
233  * PCEQW   rd, rs, rt        Parallel Compare for Equal Word
234  */
235 
236 static bool trans_parallel_compare(DisasContext *ctx, arg_r *a,
237                                    TCGCond cond, unsigned wlen)
238 {
239     TCGv_i64 c0, c1, ax, bx, t0, t1, t2;
240 
241     if (a->rd == 0) {
242         /* nop */
243         return true;
244     }
245 
246     c0 = tcg_constant_tl(0);
247     c1 = tcg_constant_tl(0xffffffff);
248     ax = tcg_temp_new_i64();
249     bx = tcg_temp_new_i64();
250     t0 = tcg_temp_new_i64();
251     t1 = tcg_temp_new_i64();
252     t2 = tcg_temp_new_i64();
253 
254     /* Lower half */
255     gen_load_gpr(ax, a->rs);
256     gen_load_gpr(bx, a->rt);
257     for (int i = 0; i < (64 / wlen); i++) {
258         tcg_gen_sextract_i64(t0, ax, wlen * i, wlen);
259         tcg_gen_sextract_i64(t1, bx, wlen * i, wlen);
260         tcg_gen_movcond_i64(cond, t2, t1, t0, c1, c0);
261         tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], t2, wlen * i, wlen);
262     }
263     /* Upper half */
264     gen_load_gpr_hi(ax, a->rs);
265     gen_load_gpr_hi(bx, a->rt);
266     for (int i = 0; i < (64 / wlen); i++) {
267         tcg_gen_sextract_i64(t0, ax, wlen * i, wlen);
268         tcg_gen_sextract_i64(t1, bx, wlen * i, wlen);
269         tcg_gen_movcond_i64(cond, t2, t1, t0, c1, c0);
270         tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], t2, wlen * i, wlen);
271     }
272     return true;
273 }
274 
275 /* Parallel Compare for Greater Than Byte */
276 static bool trans_PCGTB(DisasContext *ctx, arg_r *a)
277 {
278     return trans_parallel_compare(ctx, a, TCG_COND_GE, 8);
279 }
280 
281 /* Parallel Compare for Equal Byte */
282 static bool trans_PCEQB(DisasContext *ctx, arg_r *a)
283 {
284     return trans_parallel_compare(ctx, a, TCG_COND_EQ, 8);
285 }
286 
287 /* Parallel Compare for Greater Than Halfword */
288 static bool trans_PCGTH(DisasContext *ctx, arg_r *a)
289 {
290     return trans_parallel_compare(ctx, a, TCG_COND_GE, 16);
291 }
292 
293 /* Parallel Compare for Equal Halfword */
294 static bool trans_PCEQH(DisasContext *ctx, arg_r *a)
295 {
296     return trans_parallel_compare(ctx, a, TCG_COND_EQ, 16);
297 }
298 
299 /* Parallel Compare for Greater Than Word */
300 static bool trans_PCGTW(DisasContext *ctx, arg_r *a)
301 {
302     return trans_parallel_compare(ctx, a, TCG_COND_GE, 32);
303 }
304 
305 /* Parallel Compare for Equal Word */
306 static bool trans_PCEQW(DisasContext *ctx, arg_r *a)
307 {
308     return trans_parallel_compare(ctx, a, TCG_COND_EQ, 32);
309 }
310 
311 /*
312  *     LZC (1 instruction)
313  *     -------------------
314  * PLZCW   rd, rs            Parallel Leading Zero or One Count Word
315  */
316 
317 /*
318  *     Quadword Load and Store (2 instructions)
319  *     ----------------------------------------
320  * LQ      rt, offset(base)  Load Quadword
321  * SQ      rt, offset(base)  Store Quadword
322  */
323 
324 static bool trans_LQ(DisasContext *ctx, arg_i *a)
325 {
326     TCGv_i64 t0;
327     TCGv addr;
328 
329     if (a->rt == 0) {
330         /* nop */
331         return true;
332     }
333 
334     t0 = tcg_temp_new_i64();
335     addr = tcg_temp_new();
336 
337     gen_base_offset_addr(ctx, addr, a->base, a->offset);
338     /*
339      * Clear least-significant four bits of the effective
340      * address, effectively creating an aligned address.
341      */
342     tcg_gen_andi_tl(addr, addr, ~0xf);
343 
344     /* Lower half */
345     tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
346     gen_store_gpr(t0, a->rt);
347 
348     /* Upper half */
349     tcg_gen_addi_i64(addr, addr, 8);
350     tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
351     gen_store_gpr_hi(t0, a->rt);
352     return true;
353 }
354 
355 static bool trans_SQ(DisasContext *ctx, arg_i *a)
356 {
357     TCGv_i64 t0 = tcg_temp_new_i64();
358     TCGv addr = tcg_temp_new();
359 
360     gen_base_offset_addr(ctx, addr, a->base, a->offset);
361     /*
362      * Clear least-significant four bits of the effective
363      * address, effectively creating an aligned address.
364      */
365     tcg_gen_andi_tl(addr, addr, ~0xf);
366 
367     /* Lower half */
368     gen_load_gpr(t0, a->rt);
369     tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
370 
371     /* Upper half */
372     tcg_gen_addi_i64(addr, addr, 8);
373     gen_load_gpr_hi(t0, a->rt);
374     tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
375     return true;
376 }
377 
378 /*
379  *     Multiply and Divide (19 instructions)
380  *     -------------------------------------
381  * PMULTW  rd, rs, rt        Parallel Multiply Word
382  * PMULTUW rd, rs, rt        Parallel Multiply Unsigned Word
383  * PDIVW   rs, rt            Parallel Divide Word
384  * PDIVUW  rs, rt            Parallel Divide Unsigned Word
385  * PMADDW  rd, rs, rt        Parallel Multiply-Add Word
386  * PMADDUW rd, rs, rt        Parallel Multiply-Add Unsigned Word
387  * PMSUBW  rd, rs, rt        Parallel Multiply-Subtract Word
388  * PMULTH  rd, rs, rt        Parallel Multiply Halfword
389  * PMADDH  rd, rs, rt        Parallel Multiply-Add Halfword
390  * PMSUBH  rd, rs, rt        Parallel Multiply-Subtract Halfword
391  * PHMADH  rd, rs, rt        Parallel Horizontal Multiply-Add Halfword
392  * PHMSBH  rd, rs, rt        Parallel Horizontal Multiply-Subtract Halfword
393  * PDIVBW  rs, rt            Parallel Divide Broadcast Word
394  * PMFHI   rd                Parallel Move From HI Register
395  * PMFLO   rd                Parallel Move From LO Register
396  * PMTHI   rs                Parallel Move To HI Register
397  * PMTLO   rs                Parallel Move To LO Register
398  * PMFHL   rd                Parallel Move From HI/LO Register
399  * PMTHL   rs                Parallel Move To HI/LO Register
400  */
401 
402 /*
403  *     Pack/Extend (11 instructions)
404  *     -----------------------------
405  * PPAC5   rd, rt            Parallel Pack to 5 bits
406  * PPACB   rd, rs, rt        Parallel Pack to Byte
407  * PPACH   rd, rs, rt        Parallel Pack to Halfword
408  * PPACW   rd, rs, rt        Parallel Pack to Word
409  * PEXT5   rd, rt            Parallel Extend Upper from 5 bits
410  * PEXTUB  rd, rs, rt        Parallel Extend Upper from Byte
411  * PEXTLB  rd, rs, rt        Parallel Extend Lower from Byte
412  * PEXTUH  rd, rs, rt        Parallel Extend Upper from Halfword
413  * PEXTLH  rd, rs, rt        Parallel Extend Lower from Halfword
414  * PEXTUW  rd, rs, rt        Parallel Extend Upper from Word
415  * PEXTLW  rd, rs, rt        Parallel Extend Lower from Word
416  */
417 
418 /* Parallel Pack to Word */
419 static bool trans_PPACW(DisasContext *ctx, arg_r *a)
420 {
421     TCGv_i64 a0, b0, t0;
422 
423     if (a->rd == 0) {
424         /* nop */
425         return true;
426     }
427 
428     a0 = tcg_temp_new_i64();
429     b0 = tcg_temp_new_i64();
430     t0 = tcg_temp_new_i64();
431 
432     gen_load_gpr(a0, a->rs);
433     gen_load_gpr(b0, a->rt);
434 
435     gen_load_gpr_hi(t0, a->rt); /* b1 */
436     tcg_gen_deposit_i64(cpu_gpr[a->rd], b0, t0, 32, 32);
437 
438     gen_load_gpr_hi(t0, a->rs); /* a1 */
439     tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], a0, t0, 32, 32);
440     return true;
441 }
442 
443 static void gen_pextw(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 a, TCGv_i64 b)
444 {
445     tcg_gen_deposit_i64(dl, b, a, 32, 32);
446     tcg_gen_shri_i64(b, b, 32);
447     tcg_gen_deposit_i64(dh, a, b, 0, 32);
448 }
449 
450 static bool trans_PEXTLx(DisasContext *ctx, arg_r *a, unsigned wlen)
451 {
452     TCGv_i64 ax, bx;
453 
454     if (a->rd == 0) {
455         /* nop */
456         return true;
457     }
458 
459     ax = tcg_temp_new_i64();
460     bx = tcg_temp_new_i64();
461 
462     gen_load_gpr(ax, a->rs);
463     gen_load_gpr(bx, a->rt);
464 
465     /* Lower half */
466     for (int i = 0; i < 64 / (2 * wlen); i++) {
467         tcg_gen_deposit_i64(cpu_gpr[a->rd],
468                             cpu_gpr[a->rd], bx, 2 * wlen * i, wlen);
469         tcg_gen_deposit_i64(cpu_gpr[a->rd],
470                             cpu_gpr[a->rd], ax, 2 * wlen * i + wlen, wlen);
471         tcg_gen_shri_i64(bx, bx, wlen);
472         tcg_gen_shri_i64(ax, ax, wlen);
473     }
474     /* Upper half */
475     for (int i = 0; i < 64 / (2 * wlen); i++) {
476         tcg_gen_deposit_i64(cpu_gpr_hi[a->rd],
477                             cpu_gpr_hi[a->rd], bx, 2 * wlen * i, wlen);
478         tcg_gen_deposit_i64(cpu_gpr_hi[a->rd],
479                             cpu_gpr_hi[a->rd], ax, 2 * wlen * i + wlen, wlen);
480         tcg_gen_shri_i64(bx, bx, wlen);
481         tcg_gen_shri_i64(ax, ax, wlen);
482     }
483     return true;
484 }
485 
486 /* Parallel Extend Lower from Byte */
487 static bool trans_PEXTLB(DisasContext *ctx, arg_r *a)
488 {
489     return trans_PEXTLx(ctx, a, 8);
490 }
491 
492 /* Parallel Extend Lower from Halfword */
493 static bool trans_PEXTLH(DisasContext *ctx, arg_r *a)
494 {
495     return trans_PEXTLx(ctx, a, 16);
496 }
497 
498 /* Parallel Extend Lower from Word */
499 static bool trans_PEXTLW(DisasContext *ctx, arg_r *a)
500 {
501     TCGv_i64 ax, bx;
502 
503     if (a->rd == 0) {
504         /* nop */
505         return true;
506     }
507 
508     ax = tcg_temp_new_i64();
509     bx = tcg_temp_new_i64();
510 
511     gen_load_gpr(ax, a->rs);
512     gen_load_gpr(bx, a->rt);
513     gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx);
514     return true;
515 }
516 
517 /* Parallel Extend Upper from Word */
518 static bool trans_PEXTUW(DisasContext *ctx, arg_r *a)
519 {
520     TCGv_i64 ax, bx;
521 
522     if (a->rd == 0) {
523         /* nop */
524         return true;
525     }
526 
527     ax = tcg_temp_new_i64();
528     bx = tcg_temp_new_i64();
529 
530     gen_load_gpr_hi(ax, a->rs);
531     gen_load_gpr_hi(bx, a->rt);
532     gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx);
533     return true;
534 }
535 
536 /*
537  *     Others (16 instructions)
538  *     ------------------------
539  * PCPYH   rd, rt            Parallel Copy Halfword
540  * PCPYLD  rd, rs, rt        Parallel Copy Lower Doubleword
541  * PCPYUD  rd, rs, rt        Parallel Copy Upper Doubleword
542  * PREVH   rd, rt            Parallel Reverse Halfword
543  * PINTH   rd, rs, rt        Parallel Interleave Halfword
544  * PINTEH  rd, rs, rt        Parallel Interleave Even Halfword
545  * PEXEH   rd, rt            Parallel Exchange Even Halfword
546  * PEXCH   rd, rt            Parallel Exchange Center Halfword
547  * PEXEW   rd, rt            Parallel Exchange Even Word
548  * PEXCW   rd, rt            Parallel Exchange Center Word
549  * QFSRV   rd, rs, rt        Quadword Funnel Shift Right Variable
550  * MFSA    rd                Move from Shift Amount Register
551  * MTSA    rs                Move to Shift Amount Register
552  * MTSAB   rs, immediate     Move Byte Count to Shift Amount Register
553  * MTSAH   rs, immediate     Move Halfword Count to Shift Amount Register
554  * PROT3W  rd, rt            Parallel Rotate 3 Words
555  */
556 
557 /* Parallel Copy Halfword */
558 static bool trans_PCPYH(DisasContext *s, arg_r *a)
559 {
560     if (a->rd == 0) {
561         /* nop */
562         return true;
563     }
564 
565     if (a->rt == 0) {
566         tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
567         tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
568         return true;
569     }
570 
571     tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rt], cpu_gpr[a->rt], 16, 16);
572     tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], cpu_gpr[a->rd], 32, 32);
573     tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rt], cpu_gpr_hi[a->rt], 16, 16);
574     tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], 32, 32);
575 
576     return true;
577 }
578 
579 /* Parallel Copy Lower Doubleword */
580 static bool trans_PCPYLD(DisasContext *s, arg_r *a)
581 {
582     if (a->rd == 0) {
583         /* nop */
584         return true;
585     }
586 
587     if (a->rs == 0) {
588         tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
589     } else {
590         tcg_gen_mov_i64(cpu_gpr_hi[a->rd], cpu_gpr[a->rs]);
591     }
592 
593     if (a->rt == 0) {
594         tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
595     } else if (a->rd != a->rt) {
596         tcg_gen_mov_i64(cpu_gpr[a->rd], cpu_gpr[a->rt]);
597     }
598 
599     return true;
600 }
601 
602 /* Parallel Copy Upper Doubleword */
603 static bool trans_PCPYUD(DisasContext *s, arg_r *a)
604 {
605     if (a->rd == 0) {
606         /* nop */
607         return true;
608     }
609 
610     gen_load_gpr_hi(cpu_gpr[a->rd], a->rs);
611 
612     if (a->rt == 0) {
613         tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
614     } else if (a->rd != a->rt) {
615         tcg_gen_mov_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rt]);
616     }
617 
618     return true;
619 }
620 
621 /* Parallel Rotate 3 Words Left */
622 static bool trans_PROT3W(DisasContext *ctx, arg_r *a)
623 {
624     TCGv_i64 ax;
625 
626     if (a->rd == 0) {
627         /* nop */
628         return true;
629     }
630     if (a->rt == 0) {
631         tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
632         tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
633         return true;
634     }
635 
636     ax = tcg_temp_new_i64();
637 
638     tcg_gen_mov_i64(ax, cpu_gpr_hi[a->rt]);
639     tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], ax, cpu_gpr[a->rt], 0, 32);
640 
641     tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rt], ax, 0, 32);
642     tcg_gen_rotri_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], 32);
643     return true;
644 }
645