xref: /qemu/target/mips/tcg/tx79_translate.c (revision 785ea711)
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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_itype *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_TEQ);
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_TEQ);
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_itype *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_TEQ);
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_TEQ);
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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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_rtype *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