2 * Toshiba TX79-specific instructions translation routines
4 * Copyright (c) 2018 Fredrik Noring
5 * Copyright (c) 2021 Philippe Mathieu-Daudé
7 * SPDX-License-Identifier: GPL-2.0-or-later
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"
16 /* Include the auto-generated decoder. */
17 #include "decode-tx79.c.inc"
20 * Overview of the TX79-specific instruction set
21 * =============================================
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.
31 * The Toshiba TX System RISC TX79 Core Architecture manual,
32 * https://wiki.qemu.org/File:C790.pdf
35 bool decode_ext_tx79(DisasContext
*ctx
, uint32_t insn
)
37 if (TARGET_LONG_BITS
== 64 && decode_tx79(ctx
, insn
)) {
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)
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
67 static bool trans_MFHI1(DisasContext
*ctx
, arg_r
*a
)
69 gen_store_gpr(cpu_HI
[1], a
->rd
);
74 static bool trans_MFLO1(DisasContext
*ctx
, arg_r
*a
)
76 gen_store_gpr(cpu_LO
[1], a
->rd
);
81 static bool trans_MTHI1(DisasContext
*ctx
, arg_r
*a
)
83 gen_load_gpr(cpu_HI
[1], a
->rs
);
88 static bool trans_MTLO1(DisasContext
*ctx
, arg_r
*a
)
90 gen_load_gpr(cpu_LO
[1], a
->rs
);
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
119 static bool trans_parallel_arith(DisasContext
*ctx
, arg_r
*a
,
120 void (*gen_logic_i64
)(TCGv_i64
, TCGv_i64
, TCGv_i64
))
129 ax
= tcg_temp_new_i64();
130 bx
= tcg_temp_new_i64();
133 gen_load_gpr(ax
, a
->rs
);
134 gen_load_gpr(bx
, a
->rt
);
135 gen_logic_i64(cpu_gpr
[a
->rd
], ax
, bx
);
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
);
144 /* Parallel Subtract Byte */
145 static bool trans_PSUBB(DisasContext
*ctx
, arg_r
*a
)
147 return trans_parallel_arith(ctx
, a
, tcg_gen_vec_sub8_i64
);
150 /* Parallel Subtract Halfword */
151 static bool trans_PSUBH(DisasContext
*ctx
, arg_r
*a
)
153 return trans_parallel_arith(ctx
, a
, tcg_gen_vec_sub16_i64
);
156 /* Parallel Subtract Word */
157 static bool trans_PSUBW(DisasContext
*ctx
, arg_r
*a
)
159 return trans_parallel_arith(ctx
, a
, tcg_gen_vec_sub32_i64
);
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
172 * Absolute (2 instructions)
173 * -------------------------
174 * PABSH rd, rt Parallel Absolute Halfword
175 * PABSW rd, rt Parallel Absolute Word
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
188 static bool trans_PAND(DisasContext
*ctx
, arg_r
*a
)
190 return trans_parallel_arith(ctx
, a
, tcg_gen_and_i64
);
194 static bool trans_POR(DisasContext
*ctx
, arg_r
*a
)
196 return trans_parallel_arith(ctx
, a
, tcg_gen_or_i64
);
199 /* Parallel Exclusive Or */
200 static bool trans_PXOR(DisasContext
*ctx
, arg_r
*a
)
202 return trans_parallel_arith(ctx
, a
, tcg_gen_xor_i64
);
205 /* Parallel Not Or */
206 static bool trans_PNOR(DisasContext
*ctx
, arg_r
*a
)
208 return trans_parallel_arith(ctx
, a
, tcg_gen_nor_i64
);
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
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
236 static bool trans_parallel_compare(DisasContext
*ctx
, arg_r
*a
,
237 TCGCond cond
, unsigned wlen
)
239 TCGv_i64 c0
, c1
, ax
, bx
, t0
, t1
, t2
;
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();
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
);
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
);
275 /* Parallel Compare for Greater Than Byte */
276 static bool trans_PCGTB(DisasContext
*ctx
, arg_r
*a
)
278 return trans_parallel_compare(ctx
, a
, TCG_COND_GE
, 8);
281 /* Parallel Compare for Equal Byte */
282 static bool trans_PCEQB(DisasContext
*ctx
, arg_r
*a
)
284 return trans_parallel_compare(ctx
, a
, TCG_COND_EQ
, 8);
287 /* Parallel Compare for Greater Than Halfword */
288 static bool trans_PCGTH(DisasContext
*ctx
, arg_r
*a
)
290 return trans_parallel_compare(ctx
, a
, TCG_COND_GE
, 16);
293 /* Parallel Compare for Equal Halfword */
294 static bool trans_PCEQH(DisasContext
*ctx
, arg_r
*a
)
296 return trans_parallel_compare(ctx
, a
, TCG_COND_EQ
, 16);
299 /* Parallel Compare for Greater Than Word */
300 static bool trans_PCGTW(DisasContext
*ctx
, arg_r
*a
)
302 return trans_parallel_compare(ctx
, a
, TCG_COND_GE
, 32);
305 /* Parallel Compare for Equal Word */
306 static bool trans_PCEQW(DisasContext
*ctx
, arg_r
*a
)
308 return trans_parallel_compare(ctx
, a
, TCG_COND_EQ
, 32);
312 * LZC (1 instruction)
313 * -------------------
314 * PLZCW rd, rs Parallel Leading Zero or One Count Word
318 * Quadword Load and Store (2 instructions)
319 * ----------------------------------------
320 * LQ rt, offset(base) Load Quadword
321 * SQ rt, offset(base) Store Quadword
324 static bool trans_LQ(DisasContext
*ctx
, arg_i
*a
)
334 t0
= tcg_temp_new_i64();
335 addr
= tcg_temp_new();
337 gen_base_offset_addr(ctx
, addr
, a
->base
, a
->offset
);
339 * Clear least-significant four bits of the effective
340 * address, effectively creating an aligned address.
342 tcg_gen_andi_tl(addr
, addr
, ~0xf);
345 tcg_gen_qemu_ld_i64(t0
, addr
, ctx
->mem_idx
, MO_TEUQ
);
346 gen_store_gpr(t0
, a
->rt
);
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
);
355 static bool trans_SQ(DisasContext
*ctx
, arg_i
*a
)
357 TCGv_i64 t0
= tcg_temp_new_i64();
358 TCGv addr
= tcg_temp_new();
360 gen_base_offset_addr(ctx
, addr
, a
->base
, a
->offset
);
362 * Clear least-significant four bits of the effective
363 * address, effectively creating an aligned address.
365 tcg_gen_andi_tl(addr
, addr
, ~0xf);
368 gen_load_gpr(t0
, a
->rt
);
369 tcg_gen_qemu_st_i64(t0
, addr
, ctx
->mem_idx
, MO_TEUQ
);
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
);
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
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
418 /* Parallel Pack to Word */
419 static bool trans_PPACW(DisasContext
*ctx
, arg_r
*a
)
428 a0
= tcg_temp_new_i64();
429 b0
= tcg_temp_new_i64();
430 t0
= tcg_temp_new_i64();
432 gen_load_gpr(a0
, a
->rs
);
433 gen_load_gpr(b0
, a
->rt
);
435 gen_load_gpr_hi(t0
, a
->rt
); /* b1 */
436 tcg_gen_deposit_i64(cpu_gpr
[a
->rd
], b0
, t0
, 32, 32);
438 gen_load_gpr_hi(t0
, a
->rs
); /* a1 */
439 tcg_gen_deposit_i64(cpu_gpr_hi
[a
->rd
], a0
, t0
, 32, 32);
443 static void gen_pextw(TCGv_i64 dl
, TCGv_i64 dh
, TCGv_i64 a
, TCGv_i64 b
)
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);
450 static bool trans_PEXTLx(DisasContext
*ctx
, arg_r
*a
, unsigned wlen
)
459 ax
= tcg_temp_new_i64();
460 bx
= tcg_temp_new_i64();
462 gen_load_gpr(ax
, a
->rs
);
463 gen_load_gpr(bx
, a
->rt
);
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
);
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
);
486 /* Parallel Extend Lower from Byte */
487 static bool trans_PEXTLB(DisasContext
*ctx
, arg_r
*a
)
489 return trans_PEXTLx(ctx
, a
, 8);
492 /* Parallel Extend Lower from Halfword */
493 static bool trans_PEXTLH(DisasContext
*ctx
, arg_r
*a
)
495 return trans_PEXTLx(ctx
, a
, 16);
498 /* Parallel Extend Lower from Word */
499 static bool trans_PEXTLW(DisasContext
*ctx
, arg_r
*a
)
508 ax
= tcg_temp_new_i64();
509 bx
= tcg_temp_new_i64();
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
);
517 /* Parallel Extend Upper from Word */
518 static bool trans_PEXTUW(DisasContext
*ctx
, arg_r
*a
)
527 ax
= tcg_temp_new_i64();
528 bx
= tcg_temp_new_i64();
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
);
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
557 /* Parallel Copy Halfword */
558 static bool trans_PCPYH(DisasContext
*s
, arg_r
*a
)
566 tcg_gen_movi_i64(cpu_gpr
[a
->rd
], 0);
567 tcg_gen_movi_i64(cpu_gpr_hi
[a
->rd
], 0);
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);
579 /* Parallel Copy Lower Doubleword */
580 static bool trans_PCPYLD(DisasContext
*s
, arg_r
*a
)
588 tcg_gen_movi_i64(cpu_gpr_hi
[a
->rd
], 0);
590 tcg_gen_mov_i64(cpu_gpr_hi
[a
->rd
], cpu_gpr
[a
->rs
]);
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
]);
602 /* Parallel Copy Upper Doubleword */
603 static bool trans_PCPYUD(DisasContext
*s
, arg_r
*a
)
610 gen_load_gpr_hi(cpu_gpr
[a
->rd
], a
->rs
);
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
]);
621 /* Parallel Rotate 3 Words Left */
622 static bool trans_PROT3W(DisasContext
*ctx
, arg_r
*a
)
631 tcg_gen_movi_i64(cpu_gpr
[a
->rd
], 0);
632 tcg_gen_movi_i64(cpu_gpr_hi
[a
->rd
], 0);
636 ax
= tcg_temp_new_i64();
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);
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);