xref: /openbmc/qemu/target/mips/tcg/tx79_translate.c (revision 8bd42c00)
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 /*
338  *     Multiply and Divide (19 instructions)
339  *     -------------------------------------
340  * PMULTW  rd, rs, rt        Parallel Multiply Word
341  * PMULTUW rd, rs, rt        Parallel Multiply Unsigned Word
342  * PDIVW   rs, rt            Parallel Divide Word
343  * PDIVUW  rs, rt            Parallel Divide Unsigned Word
344  * PMADDW  rd, rs, rt        Parallel Multiply-Add Word
345  * PMADDUW rd, rs, rt        Parallel Multiply-Add Unsigned Word
346  * PMSUBW  rd, rs, rt        Parallel Multiply-Subtract Word
347  * PMULTH  rd, rs, rt        Parallel Multiply Halfword
348  * PMADDH  rd, rs, rt        Parallel Multiply-Add Halfword
349  * PMSUBH  rd, rs, rt        Parallel Multiply-Subtract Halfword
350  * PHMADH  rd, rs, rt        Parallel Horizontal Multiply-Add Halfword
351  * PHMSBH  rd, rs, rt        Parallel Horizontal Multiply-Subtract Halfword
352  * PDIVBW  rs, rt            Parallel Divide Broadcast Word
353  * PMFHI   rd                Parallel Move From HI Register
354  * PMFLO   rd                Parallel Move From LO Register
355  * PMTHI   rs                Parallel Move To HI Register
356  * PMTLO   rs                Parallel Move To LO Register
357  * PMFHL   rd                Parallel Move From HI/LO Register
358  * PMTHL   rs                Parallel Move To HI/LO Register
359  */
360 
361 /*
362  *     Pack/Extend (11 instructions)
363  *     -----------------------------
364  * PPAC5   rd, rt            Parallel Pack to 5 bits
365  * PPACB   rd, rs, rt        Parallel Pack to Byte
366  * PPACH   rd, rs, rt        Parallel Pack to Halfword
367  * PPACW   rd, rs, rt        Parallel Pack to Word
368  * PEXT5   rd, rt            Parallel Extend Upper from 5 bits
369  * PEXTUB  rd, rs, rt        Parallel Extend Upper from Byte
370  * PEXTLB  rd, rs, rt        Parallel Extend Lower from Byte
371  * PEXTUH  rd, rs, rt        Parallel Extend Upper from Halfword
372  * PEXTLH  rd, rs, rt        Parallel Extend Lower from Halfword
373  * PEXTUW  rd, rs, rt        Parallel Extend Upper from Word
374  * PEXTLW  rd, rs, rt        Parallel Extend Lower from Word
375  */
376 
377 static void gen_pextw(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 a, TCGv_i64 b)
378 {
379     tcg_gen_deposit_i64(dl, b, a, 32, 32);
380     tcg_gen_shri_i64(b, b, 32);
381     tcg_gen_deposit_i64(dh, a, b, 0, 32);
382 }
383 
384 static bool trans_PEXTLx(DisasContext *ctx, arg_rtype *a, unsigned wlen)
385 {
386     TCGv_i64 ax, bx;
387 
388     if (a->rd == 0) {
389         /* nop */
390         return true;
391     }
392 
393     ax = tcg_temp_new_i64();
394     bx = tcg_temp_new_i64();
395 
396     gen_load_gpr(ax, a->rs);
397     gen_load_gpr(bx, a->rt);
398 
399     /* Lower half */
400     for (int i = 0; i < 64 / (2 * wlen); i++) {
401         tcg_gen_deposit_i64(cpu_gpr[a->rd],
402                             cpu_gpr[a->rd], bx, 2 * wlen * i, wlen);
403         tcg_gen_deposit_i64(cpu_gpr[a->rd],
404                             cpu_gpr[a->rd], ax, 2 * wlen * i + wlen, wlen);
405         tcg_gen_shri_i64(bx, bx, wlen);
406         tcg_gen_shri_i64(ax, ax, wlen);
407     }
408     /* Upper half */
409     for (int i = 0; i < 64 / (2 * wlen); i++) {
410         tcg_gen_deposit_i64(cpu_gpr_hi[a->rd],
411                             cpu_gpr_hi[a->rd], bx, 2 * wlen * i, wlen);
412         tcg_gen_deposit_i64(cpu_gpr_hi[a->rd],
413                             cpu_gpr_hi[a->rd], ax, 2 * wlen * i + wlen, wlen);
414         tcg_gen_shri_i64(bx, bx, wlen);
415         tcg_gen_shri_i64(ax, ax, wlen);
416     }
417 
418     tcg_temp_free(bx);
419     tcg_temp_free(ax);
420 
421     return true;
422 }
423 
424 /* Parallel Extend Lower from Byte */
425 static bool trans_PEXTLB(DisasContext *ctx, arg_rtype *a)
426 {
427     return trans_PEXTLx(ctx, a, 8);
428 }
429 
430 /* Parallel Extend Lower from Halfword */
431 static bool trans_PEXTLH(DisasContext *ctx, arg_rtype *a)
432 {
433     return trans_PEXTLx(ctx, a, 16);
434 }
435 
436 /* Parallel Extend Lower from Word */
437 static bool trans_PEXTLW(DisasContext *ctx, arg_rtype *a)
438 {
439     TCGv_i64 ax, bx;
440 
441     if (a->rd == 0) {
442         /* nop */
443         return true;
444     }
445 
446     ax = tcg_temp_new_i64();
447     bx = tcg_temp_new_i64();
448 
449     gen_load_gpr(ax, a->rs);
450     gen_load_gpr(bx, a->rt);
451     gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx);
452 
453     tcg_temp_free(bx);
454     tcg_temp_free(ax);
455 
456     return true;
457 }
458 
459 /* Parallel Extend Upper from Word */
460 static bool trans_PEXTUW(DisasContext *ctx, arg_rtype *a)
461 {
462     TCGv_i64 ax, bx;
463 
464     if (a->rd == 0) {
465         /* nop */
466         return true;
467     }
468 
469     ax = tcg_temp_new_i64();
470     bx = tcg_temp_new_i64();
471 
472     gen_load_gpr_hi(ax, a->rs);
473     gen_load_gpr_hi(bx, a->rt);
474     gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx);
475 
476     tcg_temp_free(bx);
477     tcg_temp_free(ax);
478 
479     return true;
480 }
481 
482 /*
483  *     Others (16 instructions)
484  *     ------------------------
485  * PCPYH   rd, rt            Parallel Copy Halfword
486  * PCPYLD  rd, rs, rt        Parallel Copy Lower Doubleword
487  * PCPYUD  rd, rs, rt        Parallel Copy Upper Doubleword
488  * PREVH   rd, rt            Parallel Reverse Halfword
489  * PINTH   rd, rs, rt        Parallel Interleave Halfword
490  * PINTEH  rd, rs, rt        Parallel Interleave Even Halfword
491  * PEXEH   rd, rt            Parallel Exchange Even Halfword
492  * PEXCH   rd, rt            Parallel Exchange Center Halfword
493  * PEXEW   rd, rt            Parallel Exchange Even Word
494  * PEXCW   rd, rt            Parallel Exchange Center Word
495  * QFSRV   rd, rs, rt        Quadword Funnel Shift Right Variable
496  * MFSA    rd                Move from Shift Amount Register
497  * MTSA    rs                Move to Shift Amount Register
498  * MTSAB   rs, immediate     Move Byte Count to Shift Amount Register
499  * MTSAH   rs, immediate     Move Halfword Count to Shift Amount Register
500  * PROT3W  rd, rt            Parallel Rotate 3 Words
501  */
502 
503 /* Parallel Copy Halfword */
504 static bool trans_PCPYH(DisasContext *s, arg_rtype *a)
505 {
506     if (a->rd == 0) {
507         /* nop */
508         return true;
509     }
510 
511     if (a->rt == 0) {
512         tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
513         tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
514         return true;
515     }
516 
517     tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rt], cpu_gpr[a->rt], 16, 16);
518     tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], cpu_gpr[a->rd], 32, 32);
519     tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rt], cpu_gpr_hi[a->rt], 16, 16);
520     tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], 32, 32);
521 
522     return true;
523 }
524 
525 /* Parallel Copy Lower Doubleword */
526 static bool trans_PCPYLD(DisasContext *s, arg_rtype *a)
527 {
528     if (a->rd == 0) {
529         /* nop */
530         return true;
531     }
532 
533     if (a->rs == 0) {
534         tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
535     } else {
536         tcg_gen_mov_i64(cpu_gpr_hi[a->rd], cpu_gpr[a->rs]);
537     }
538 
539     if (a->rt == 0) {
540         tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
541     } else if (a->rd != a->rt) {
542         tcg_gen_mov_i64(cpu_gpr[a->rd], cpu_gpr[a->rt]);
543     }
544 
545     return true;
546 }
547 
548 /* Parallel Copy Upper Doubleword */
549 static bool trans_PCPYUD(DisasContext *s, arg_rtype *a)
550 {
551     if (a->rd == 0) {
552         /* nop */
553         return true;
554     }
555 
556     gen_load_gpr_hi(cpu_gpr[a->rd], a->rs);
557 
558     if (a->rt == 0) {
559         tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
560     } else if (a->rd != a->rt) {
561         tcg_gen_mov_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rt]);
562     }
563 
564     return true;
565 }
566