Move MDMX instructions which are public knowledge from vr5400.igen
[external/binutils.git] / sim / mips / mdmx.igen
1 // Media Instructions
2 // ------------------
3
4 // Ref: http://www.sgi.com/MIPS/arch/ISA5/MDMXspec.pdf
5
6 // Note: For OB instructions, the sel field is deduced by special
7 // handling of the "vt" operand.
8 //         If vt is:
9 //             of the form $vt[0],        then sel is 0000
10 //             of the form $vt[1],        then sel is 0001
11 //             of the form $vt[2],        then sel is 0010
12 //             of the form $vt[3],        then sel is 0011
13 //             of the form $vt[4],        then sel is 0100
14 //             of the form $vt[5],        then sel is 0101
15 //             of the form $vt[6],        then sel is 0110
16 //             of the form $vt[7],        then sel is 0111
17 //             Normal register specifier, then sel is 1011
18 //             Constant,                  then sel is 1111
19 //
20 // VecAcc is the Vector Accumulator.
21 //     This accumulator is organized as 8X24 bit (192 bit) register.
22 //     This accumulator holds only signed values.
23
24
25 // Verify that the instruction is valid for the curent Architecture
26 // If valid, return the scale (log nr bits) of a vector element
27 // as determined by SEL.
28
29 :function:::int:get_scale:int sel
30 {
31 #if 0
32   switch (my_index X STATE_ARCHITECTURE)
33     {
34     }
35 #endif
36   switch (sel & 0x7)
37     {
38     case 0:
39     case 2:  
40     case 4:
41     case 6:
42       /* octal byte - ssss0 */
43       return 0;
44     case 1:
45     case 5:
46       /* quad halfword - sss01 */
47       return 1;
48     case 3:
49       /* bi word - ss011 */
50       semantic_illegal (sd, cia);
51       return 2;
52     case 7:
53       /* long - ss111 */
54       semantic_illegal (sd, cia);
55       return 3;
56     default:
57       abort ();
58       return -1;
59     }
60 }
61
62
63 // Fetch/Store VALUE in ELEMENT of vector register FPR.
64 // The the of the element determined by SCALE.
65
66 :function:::signed:value_vr:int scale, int fpr, int el
67 {
68   switch (FPR_STATE[fpr])
69     {
70     case fmt_uninterpreted:
71       FPR_STATE[fpr] = fmt_long;
72       break;
73     case fmt_long:
74     case fmt_unknown:
75       break;
76     default:
77       sim_io_eprintf(sd, "Vector %d format invalid (PC = 0x08lx)\n",
78                      fpr, (long) cia);
79       FPR_STATE[fpr] = fmt_unknown;
80     }
81   switch (scale)
82     {
83     case 0:
84       {
85         signed8 value = *A1_8 (&FGR[fpr], 7 - el);
86         return value;
87       }
88     case 1:
89       {
90         signed16 value = *A2_8 (&FGR[fpr], 3 - el);
91         return value;
92       }
93     default:
94       abort;
95     }
96   return 0;
97 }
98
99 :function:::signed:store_vr:int scale, int fpr, int element, signed value
100 {
101   switch (FPR_STATE[fpr])
102     {
103     case fmt_uninterpreted:
104       FPR_STATE[fpr] = fmt_long;
105       break;
106     case fmt_long:
107     case fmt_unknown:
108       break;
109     default:
110       sim_io_eprintf(sd, "Vector %d format invalid (PC = 0x08lx)\n",
111                      fpr, (long) cia);
112       FPR_STATE[fpr] = fmt_unknown;
113     }
114   switch (scale)
115     {
116     case 0:
117       {
118         *A1_8 (&FGR[fpr], 7 - element) = value;
119         break;
120       }
121     case 1:
122       {
123         *A2_8 (&FGR[fpr], 3 - element) = value;
124         break;
125       }
126     default:
127       abort ();
128     }
129 }
130
131
132 // Select a value from onr of FGR[VT][ELEMENT], VT and GFR[VT][CONST]
133 // according to SEL
134
135 :function:::unsigned:select_vr:int sel, int vt, int element
136 {
137   switch (sel)
138     {
139       /* element select - 0xxxx */
140     case 0x00: /* 0 xxx 0 */
141     case 0x02:
142     case 0x04:
143     case 0x06:
144     case 0x08:
145     case 0x0a:
146     case 0x0c:
147     case 0x0e:
148       return value_vr (SD_, 0, vt, sel >> 1);
149     case 0x01: /* 0 xx 01 */
150     case 0x05:
151     case 0x09:
152     case 0x0d:
153       return value_vr (SD_, 1, vt, sel >> 2);
154     case 0x03: /* 0 x 011 */
155     case 0x0b:
156       return value_vr (SD_, 2, vt, sel >> 3);
157     case 0x07: /* 0 x 111 */
158     case 0x0f:
159       return value_vr (SD_, 3, vt, sel >> 4);
160
161       /* select vector - 10xxx */
162     case 0x16: /* 10 11 0 */
163       return value_vr (SD_, 0, vt, element);
164     case 0x15: /* 10 1 01 */
165       return value_vr (SD_, 1, vt, element);
166     case 0x13: /* 10  011 */
167       return value_vr (SD_, 2, vt, element);
168     case 0x17: /* 10  111 */
169       return value_vr (SD_, 3, vt, element);
170
171       /* select immediate - 11xxx */
172     case 0x1e: /* 11 11 0 */
173     case 0x1d: /* 11 1 01 */
174     case 0x1b: /* 11  011 */
175     case 0x1f: /* 11  111 */
176       return vt;
177
178     }
179   return 0;
180 }
181
182
183 // Saturate (clamp) the signed value to (8 << SCALE) bits.
184
185 :function:::signed:Clamp:int scale, signed value
186 {
187   switch (scale)
188     {
189     case 0:
190       {
191         if (value != (signed8) value)
192           {
193             if (value > 0)
194               return 0x7f;
195             else
196               return 0x80;
197           }
198         return value & 0xff;
199       }
200     case 1:
201       {
202         if (value != (signed16) value)
203           {
204             if (value > 0)
205                return 0x7fff;
206             else
207                return 0x8000;
208           }
209         return value & 0xffff;
210       }
211     default:
212       abort ();
213       return 0;
214     }
215 }
216
217
218 // Access a single bit of the floating point CC register.
219
220 :function:::void:store_cc:int i, int value
221 {
222   abort ();
223 }
224
225 :function:::int:fetch_cc:int i
226 {
227   abort ();
228   return 0;
229 }
230
231
232 //  Read/write the accumulator
233
234 :function:::signed64:value_acc:int scale, int element
235 {
236   signed64 value = 0;
237   switch (scale)
238     {
239     case 0:
240       value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 0];
241       value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 1] << 8;
242       value |= (signed64) (signed8) CPU->acc [element * 3 + 2] << 16;
243       break;
244     case 1:
245       value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 0];
246       value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 1] << 8;
247       value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 2] << 16;
248       value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 3] << 24;
249       value |= (unsigned64) (unsigned8) CPU->acc [element * 3 + 4] << 32;
250       value |= (signed64) (signed8) CPU->acc [element * 3 + 5] << 40;
251       break;
252     }
253   return value;
254 }
255
256 :function:::void:store_acc:int scale, int element, signed64 value
257 {
258   switch (scale)
259     {
260     case 0:
261       CPU->acc [element * 3 + 0] = value >> 0;
262       CPU->acc [element * 3 + 1] = value >> 8;
263       CPU->acc [element * 3 + 2] = value >> 16;
264       break;
265     case 1:
266       CPU->acc [element * 3 + 0] = value >> 0;
267       CPU->acc [element * 3 + 1] = value >> 8;
268       CPU->acc [element * 3 + 2] = value >> 16;
269       CPU->acc [element * 3 + 3] = value >> 24;
270       CPU->acc [element * 3 + 4] = value >> 32;
271       CPU->acc [element * 3 + 5] = value >> 40;
272       break;
273     }
274 }
275
276
277 // Formatting
278
279 :%s::::VT:int sel, int vt
280 {
281   static char buf[20];
282   if (sel < 8)
283     sprintf (buf, "v%d[%d]", vt, sel);
284   else if (sel == 0x13)
285     sprintf (buf, "v%d", vt);
286   else if (sel == 0x1f)
287     sprintf (buf, "%d", vt);
288   else
289     sprintf (buf, "(invalid)");
290   return buf;
291 }
292
293 :%s::::SEL:int sel
294 {
295   switch (sel & 7)
296     {
297     case 0:
298     case 2:
299     case 4:
300     case 6:
301       return "ob";
302     case 1:
303     case 5:
304       return "qh";
305     case 3:
306       return "bw";
307     default:
308       return "l";
309     }
310 }
311
312
313 // Vector Add.
314
315 010010,5.SEL,5.VT,5.VS,5.VD,001011::::ADD.fmt
316 "add.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
317 *mdmx:
318 // start-sanitize-vr5400
319 *vr5400:
320 // end-sanitize-vr5400
321 {
322   int i;
323   int scale = get_scale (SD_, SEL);
324   for (i = 0; i < (8 >> scale); i++)
325     store_vr (SD_, scale, VD, i,
326               Clamp (SD_, scale,
327                      (value_vr (SD_, scale, VS, i)
328                       + select_vr (SD_, SEL, VT, i))));
329 }
330
331
332 // Accumulate Vector Add
333
334 010010,5.SEL,5.VT,5.VS,1,0000,110111::::ADDA.fmt
335 "adda.%s<SEL> v<VD>, v<VS>"
336 *mdmx:
337 {
338   int i;
339   int scale = get_scale (SD_, SEL);
340   for (i = 0; i < (8 >> scale); i++)
341     store_acc (SD_, scale, i,
342                (value_acc (SD_, scale, i)
343                 + (signed64) value_vr (SD_, scale, VS, i)
344                 + (signed64) select_vr (SD_, SEL, VT, i)));
345 }
346
347
348 // Load Vector Add
349
350 010010,5.SEL,5.VT,5.VS,0,0000,110111::::ADDA.fmt
351 "addl.%s<SEL> v<VD>, v<VS>"
352 *mdmx:
353 {
354   int i;
355   int scale = get_scale (SD_, SEL);
356   for (i = 0; i < (8 >> scale); i++)
357     store_acc (SD_, scale, i,
358                ((signed64) value_vr (SD_, scale, VS, i)
359                 + (signed64) select_vr (SD_, SEL, VT, i)));
360 }
361
362
363
364 // Vector align, Constant Alignment
365
366 :function:::void:ByteAlign:int vd, int imm, int vs, int vt
367 {
368   int s = imm * 8;
369   unsigned64 rs = value_fpr (sd, cia, vs, fmt_long);
370   unsigned64 rt = value_fpr (sd, cia, vt, fmt_long);
371   unsigned64 rd;
372   if (BigEndianCPU)
373     {
374       /* (vs || vt) [127 - S .. 64 - S] */
375       if (s == 0)
376         rd = rs;
377       else
378         rd = (MOVED64 (rs, 64 - s, 0, 63, s)
379               | EXTRACTED64 (rt, 63, 64 - s));
380     }
381   else
382     {
383       /* (vs || vt) [63 + S .. S] */
384       if (s == 0)
385         rd = rt;
386       else
387         rd = (MOVED64 (rs, s, 0, 63, 64 - s)
388               | EXTRACTED64 (rt, 63, s));
389     }
390   store_fpr (sd, cia, vd, rd, fmt_long);
391 }
392
393 010010,00,3.IMM,5.VT,5.VS,5.VD,0110,X,0::::ALNI.fmt
394 "alni.%s<FMT#X> v<VD>, v<VS>, v<VT>, <IMM>"
395 *mdmx:
396 // start-sanitize-vr5400
397 *vr5400:
398 // end-sanitize-vr5400
399 {
400   ByteAlign (SD_, VD, IMM, VS, VT);
401 }
402
403
404
405 // Vector align, Variable Alignment
406
407 010010,5.RS,5.VT,5.VS,5.VD,0110,X,1::::ALNV.fmt
408 "alnv.%s<FMT#X> v<VD>, v<VS>, v<VT>, r<RS>"
409 *mdmx:
410 {
411   ByteAlign (SD_, VD, GPR[RS], VS, VT);
412 }
413
414
415
416 // Vector And.
417
418 010010,5.SEL,5.VT,5.VS,5.VD,001100::::AND.fmt
419 "and.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
420 *mdmx:
421 // start-sanitize-vr5400
422 *vr5400:
423 // end-sanitize-vr5400
424 {
425   int i;
426   int scale = get_scale (SD_, SEL);
427   for (i = 0; i < (8 >> scale); i++)
428     store_vr (SD_, scale, VD, i,
429               (value_vr (SD_, scale, VS, i)
430                & select_vr (SD_, SEL, VT, i)));
431 }
432
433
434
435 // Vector Compare Equal.
436
437
438 010010,5.SEL,5.VT,5.VS,00000,000001::::C.EQ.fmt
439 "c.EQ.%s<SEL> v<VS>, %s<VT#SEL,VT>"
440 *mdmx:
441 // start-sanitize-vr5400
442 *vr5400:
443 // end-sanitize-vr5400
444 {
445   int i;
446   int scale = get_scale (SD_, SEL);
447   for (i = 0; i < (8 >> scale); i++)
448     store_cc (SD_, i,
449               (value_vr (SD_, scale, VS, i)
450                == select_vr (SD_, SEL, VT, i)));
451 }
452
453
454
455 // Vector Compare Less Than or Equal.
456
457 010010,5.SEL,5.VT,5.VS,00000,000101::::C.LE.fmt
458 "c.le.%s<SEL> v<VS>, %s<VT#SEL,VT>"
459 *mdmx:
460 // start-sanitize-vr5400
461 *vr5400:
462 // end-sanitize-vr5400
463 {
464   int i;
465   int scale = get_scale (SD_, SEL);
466   for (i = 0; i < (8 >> scale); i++)
467     store_cc (SD_, i,
468               (value_vr (SD_, scale, VS, i)
469                <= select_vr (SD_, SEL, VT, i)));
470 }
471
472
473
474 // Vector Compare Less Than.
475
476 010010,5.SEL,5.VT,5.VS,00000,000100::::C.LT.fmt
477 "c.lt.%s<SEL> v<VS>, %s<VT#SEL,VT>"
478 *mdmx:
479 // start-sanitize-vr5400
480 *vr5400:
481 // end-sanitize-vr5400
482 {
483   int i;
484   int scale = get_scale (SD_, SEL);
485   for (i = 0; i < (8 >> scale); i++)
486     store_cc (SD_, i,
487               (value_vr (SD_, scale, VS, i)
488                < select_vr (SD_, SEL, VT, i)));
489 }
490
491
492
493 // Vector Maximum.
494
495 :function:::signed:Max:int scale, signed l, signed r
496 {
497   if (l < r)
498     return r;
499   else
500     return l;
501 }
502
503 010010,5.SEL,5.VT,5.VS,5.VD,000111::::MAX.fmt
504 "max.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
505 *mdmx:
506 // start-sanitize-vr5400
507 *vr5400:
508 // end-sanitize-vr5400
509 {
510   int i;
511   int scale = get_scale (SD_, SEL);
512   for (i = 0; i < (8 >> scale); i++)
513     store_vr (SD_, scale, VD, i,
514               Max (SD_, scale,
515                    value_vr (SD_, scale, VS, i),
516                    select_vr (SD_, SEL, VT, i)));
517 }
518
519
520
521 // Vector Minimum.
522
523 :function:::signed:Min:int scale, signed l, signed r
524 {
525   if (l < r)
526     return l;
527   else
528     return r;
529 }
530
531 010010,5.SEL,5.VT,5.VS,5.VD,000110::::MIN.fmt
532 "min.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
533 *mdmx:
534 // start-sanitize-vr5400
535 *vr5400:
536 // end-sanitize-vr5400
537 {
538   int i;
539   int scale = get_scale (SD_, SEL);
540   for (i = 0; i < (8 >> scale); i++)
541     store_vr (SD_, scale, VD, i,
542               Min (SD_, scale,
543                    value_vr (SD_, scale, VS, i),
544                    select_vr (SD_, SEL, VT, i)));
545 }
546
547
548
549 // Vector Sign.
550
551 :function:::signed:Sign:int scale, signed l, signed r
552 {
553   if (l >= 0)
554     return r;
555   else if (r >= 0)
556     return -r;
557   else
558     {
559       /* watch for overflow of MIN_INT */
560       switch (scale)
561         {
562         case 0:
563           if ((r & 0xff) == 0x80)
564             return 0x7ff;
565           else
566             return -r;
567         case 1:
568           if ((r & 0xffff) == 0x8000)
569             return 0x7ffff;
570           else
571             return -r;
572         default:
573           abort ();
574         }
575       return -r;
576     }
577 }
578
579 010010,5.SEL,5.VT,5.VS,5.VD,000110::::MSGN.fmt
580 "msgn.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
581 *mdmx:
582 {
583   int i;
584   int scale = get_scale (SD_, SEL);
585   if ((SEL & 1) != 1)
586     /* only QH allowed */
587     semantic_illegal (sd, cia);
588   for (i = 0; i < (8 >> scale); i++)
589     store_vr (SD_, scale, VD, i,
590               Sign (SD_, scale,
591                     value_vr (SD_, scale, VS, i),
592                     select_vr (SD_, SEL, VT, i)));
593 }
594
595
596
597 // Vector Multiply.
598
599 010010,5.SEL,5.VT,5.VS,5.VD,110000::::MUL.fmt
600 "mul.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
601 *mdmx:
602 // start-sanitize-vr5400
603 *vr5400:
604 // end-sanitize-vr5400
605 {
606   int i;
607   int scale = get_scale (SD_, SEL);
608   for (i = 0; i < (8 >> scale); i++)
609     store_vr (SD_, scale, VD, i,
610               Clamp (SD_, scale,
611                      (value_vr (SD_, scale, VS, i)
612                       * select_vr (SD_, SEL, VT, i))));
613 }
614
615
616
617 // Accumulate Vector Multiply
618
619 010010,5.SEL,5.VT,5.VS,00000,110011::::MULA.fmt
620 "mula.%s<SEL> v<VS>, %s<VT#SEL,VT>"
621 *mdmx:
622 // start-sanitize-vr5400
623 *vr5400:
624 // end-sanitize-vr5400
625 {
626   int i;
627   int scale = get_scale (SD_, SEL);
628   for (i = 0; i < (8 >> scale); i++)
629     store_acc (SD_, scale, i,
630                (value_acc (SD_, scale, i)
631                 + ((signed64) value_vr (SD_, scale, VS, i)
632                    * (signed64) select_vr (SD_, SEL, VT, i))));
633 }
634
635
636
637 // Add Vector Multiply to Accumulator.
638
639 010010,5.SEL,5.VT,5.VS,10000,110011::::MULL.fmt
640 "mull.%s<SEL> v<VS>, %s<VT#SEL,VT>"
641 *mdmx:
642 // start-sanitize-vr5400
643 *vr5400:
644 // end-sanitize-vr5400
645 {
646   int i;
647   int scale = get_scale (SD_, SEL);
648   for (i = 0; i < (8 >> scale); i++)
649     store_acc (SD_, scale, i,
650                ((signed64) value_vr (SD_, scale, VS, i)
651                 * (signed64) select_vr (SD_, SEL, VT, i)));
652 }
653
654
655
656 // Subtract Vector Multiply from Accumulator
657
658 010010,5.SEL,5.VT,5.VS,00000,110010::::MULS.fmt
659 "muls.%s<SEL> v<VS>, %s<VT#SEL,VT>"
660 *mdmx:
661 // start-sanitize-vr5400
662 *vr5400:
663 // end-sanitize-vr5400
664 {
665   int i;
666   int scale = get_scale (SD_, SEL);
667   for (i = 0; i < (8 >> scale); i++)
668     store_acc (SD_, scale, i,
669                (value_acc (SD_, scale, i)
670                 - ((signed64) value_vr (SD_, scale, VS, i)
671                    * (signed64) select_vr (SD_, SEL, VT, i))));
672 }
673
674
675
676 // Load Negative Vector Multiply
677
678 010010,5.SEL,5.VT,5.VS,10000,110010::::MULSL.fmt
679 "mulsl.%s<SEL> v<VS>, %s<VT#SEL,VT>"
680 *mdmx:
681 // start-sanitize-vr5400
682 *vr5400:
683 // end-sanitize-vr5400
684 {
685   int i;
686   int scale = get_scale (SD_, SEL);
687   for (i = 0; i < (8 >> scale); i++)
688     store_acc (SD_, scale, i,
689                - ((signed64) value_vr (SD_, scale, VS, i)
690                   * (signed64) select_vr (SD_, SEL, VT, i)));
691 }
692
693
694
695 // Vector Nor.
696
697 010010,5.SEL,5.VT,5.VS,5.VD,001111::::NOR.fmt
698 "nor.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
699 *mdmx:
700 // start-sanitize-vr5400
701 *vr5400:
702 // end-sanitize-vr5400
703 {
704   int i;
705   int scale = get_scale (SD_, SEL);
706   for (i = 0; i < (8 >> scale); i++)
707     store_vr (SD_, scale, VD, i,
708               ~(value_vr (SD_, scale, VS, i)
709                 | select_vr (SD_, SEL, VT, i)));
710 }
711
712
713
714 // Vector Or.
715
716 010010,5.SEL,5.VT,5.VS,5.VD,001110::::OR.fmt
717 "or.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
718 *mdmx:
719 // start-sanitize-vr5400
720 *vr5400:
721 // end-sanitize-vr5400
722 {
723   int i;
724   int scale = get_scale (SD_, SEL);
725   for (i = 0; i < (8 >> scale); i++)
726     store_vr (SD_, scale, VD, i,
727               (value_vr (SD_, scale, VS, i)
728                | select_vr (SD_, SEL, VT, i)));
729 }
730
731
732
733 // Select Vector Elements - False
734
735 010010,5.SEL,5.VT,5.VS,5.VD,000010::::PICKF.fmt
736 "pickf.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
737 *mdmx:
738 // start-sanitize-vr5400
739 *vr5400:
740 // end-sanitize-vr5400
741 {
742   int i;
743   int scale = get_scale (SD_, SEL);
744   for (i = 0; i < (8 >> scale); i++)
745     store_vr (SD_, scale, VD, i,
746               (fetch_cc (SD_, i) == 0
747                ? value_vr (SD_, scale, VS, i)
748                : select_vr (SD_, SEL, VT, i)));
749 }
750
751
752
753 // Select Vector Elements - True
754
755 010010,5.SEL,5.VT,5.VS,5.VD,000011::::PICKT.fmt
756 "pickt.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
757 *mdmx:
758 // start-sanitize-vr5400
759 *vr5400:
760 // end-sanitize-vr5400
761 {
762   int i;
763   int scale = get_scale (SD_, SEL);
764   for (i = 0; i < (8 >> scale); i++)
765     store_vr (SD_, scale, VD, i,
766               (fetch_cc (SD_, i) != 0
767                ? value_vr (SD_, scale, VS, i)
768                : select_vr (SD_, SEL, VT, i)));
769 }
770
771
772
773 // Scale, Round and Clamp Accumulator
774
775 :%s::::RND:int rnd
776 {
777   switch (rnd)
778     {
779     case 0:
780       return "zu";
781     case 1:
782       return "nau";
783     case 2:
784       return "neu";
785     case 4:
786       return "rzs";
787     case 5:
788       return "nas";
789     case 6:
790       return "nes";
791     default:
792       return "(invalid)";
793     }
794 }
795
796 :function:::signed:ScaleRoundClamp:int scale, int rnd, signed val, signed shift
797 {
798   int halfway = (1 << (shift - 1));
799   /* must be positive */
800   if (shift < 0)
801     return 0;
802   /* too much shift? */
803   switch (scale)
804     {
805     case 0:
806       if (shift >= 24)
807         return 0;
808       break;
809     case 1:
810       if (shift >= 48)
811         return 0;
812       break;
813     default:
814       abort ();
815     }
816   /* round */
817   switch (rnd & 3)
818     {
819     case 0: /* round towards zero */
820       break;
821     case 1: /* nearest, halfaway rounds away from zero */
822       if (val >= 0)
823         val += halfway;
824       else
825         val -= halfway;
826       break;
827     case 2: /* nearest, halfway rounds to even! */
828       if (val >= 0)
829         {
830           if (val & (halfway << 1))
831             val += halfway;
832           else
833             val += (halfway - 1);
834         }
835       else
836         {
837           if (val & (halfway << 1))
838             val -= halfway;
839           else
840             val -= (halfway - 1);
841         }
842     default:
843       abort ();
844     }
845   /* shift */
846   val >>= shift;
847   /* clamp */
848   switch (rnd & 4)
849     {
850     case 0:
851       /* unsigned clamp */
852       if (val < 0)
853         val = 0;
854       else
855         switch (scale)
856           {
857           case 0:
858             if (val > 0xff)
859               val = 0xff;
860             break;
861           case 1:
862             if (val > 0xffff)
863               val = 0xffff;
864             break;
865           }
866       break;
867     case 8:
868       /* normal signed clamp */
869       val = Clamp (_SD, scale, val);
870       break;
871     }
872   return val;
873 }
874
875 010010,5.SEL,5.VT,00000,5.VD,100,3.RND::::Rx.fmt
876 "r%s<RND>.%s<SEL> v<VD>, v<VT>"
877 *mdmx:
878 // start-sanitize-vr5400
879 *vr5400:
880 // end-sanitize-vr5400
881 {
882   int i;
883   int scale = get_scale (SD_, SEL);
884   for (i = 0; i < (8 >> scale); i++)
885     store_vr (SD_, scale, VD, i,
886               ScaleRoundClamp (SD_, scale, RND,
887                                value_acc (SD_, scale, i),
888                                select_vr (SD_, SEL, VT, i)));
889 }
890
891
892
893 // Vector Read  Accumulator Low.
894
895 010010,0000,1.SEL,00000,00000,5.VD,111111::::RACL.fmt
896 "racl.%s<SEL> v<VD>"
897 *mdmx:
898 // start-sanitize-vr5400
899 *vr5400:
900 // end-sanitize-vr5400
901 {
902   int i;
903   int scale = get_scale (SD_, SEL);
904   for (i = 0; i < (8 >> scale); i++)
905     store_vr (SD_, scale, VD, i,
906               EXTRACTED (value_acc (SD_, scale, i),
907                          (8 << scale) - 1,
908                          0));
909 }
910
911
912
913 // Vector Read  Accumulator Middle.
914
915 010010,0100,1.SEL,00000,00000,5.VD,111111::::RACM.fmt
916 "racm.%s<SEL> v<VD>"
917 *mdmx:
918 // start-sanitize-vr5400
919 *vr5400:
920 // end-sanitize-vr5400
921 {
922   int i;
923   int scale = get_scale (SD_, SEL);
924   for (i = 0; i < (8 >> scale); i++)
925     store_vr (SD_, scale, VD, i,
926               EXTRACTED (value_acc (SD_, scale, i),
927                          (16 << scale) - 1,
928                          (8 << scale) - 0));
929 }
930
931
932
933 // Vector Read  Accumulator High.
934
935 010010,1000,1.SEL,00000,00000,5.VD,111111::::RACH.fmt
936 "rach.%s<SEL> v<VD>"
937 *mdmx:
938 // start-sanitize-vr5400
939 *vr5400:
940 // end-sanitize-vr5400
941 {
942   int i;
943   int scale = get_scale (SD_, SEL);
944   for (i = 0; i < (8 >> scale); i++)
945     store_vr (SD_, scale, VD, i,
946               EXTRACTED (value_acc (SD_, scale, i),
947                          (24 << scale) - 1,
948                          (16 << scale) - 0));
949 }
950
951
952
953 // Vector Element Shuffle.
954
955 010010,0000,0,5.VT,5.VS,5.VD,011111::::SHFL.UPUH.fmt
956 "shfl.upuh.%s<SEL> v<VD>, v<VS>, <VT>"
957 *mdmx:
958 {
959   int i;
960   int scale = get_scale (SD_, SEL);
961   for (i = 0; i < 4; i++)
962     {
963       store_vr (SD_, 1, VD, i,
964                 value_vr (SD_, 0, VS, i + 4) & 0xff);
965     }
966 }
967
968 010010,0001,0,5.VT,5.VS,5.VD,011111::::SHFL.UPUL.fmt
969 "shfl.upul.%s<SEL> v<VD>, v<VS>, <VT>"
970 *mdmx:
971 {
972   int i;
973   for (i = 0; i < 4; i++)
974     {
975       store_vr (SD_, 1, VD, i,
976                 value_vr (SD_, 0, VS, i) & 0xff);
977     }
978 }
979
980 010010,0000,0,5.VT,5.VS,5.VD,011111::::SHFL.UPSH.fmt
981 "shfl.upsh.%s<SEL> v<VD>, v<VS>, <VT>"
982 *mdmx:
983 {
984   int i;
985   int scale = get_scale (SD_, SEL);
986   for (i = 0; i < 4; i++)
987     {
988       store_vr (SD_, 1, VD, i,
989                 value_vr (SD_, 0, VS, i + 4));
990     }
991 }
992
993 010010,0001,0,5.VT,5.VS,5.VD,011111::::SHFL.UPSL.fmt
994 "shfl.upsl.%s<SEL> v<VD>, v<VS>, <VT>"
995 *mdmx:
996 {
997   int i;
998   for (i = 0; i < 4; i++)
999     {
1000       store_vr (SD_, 1, VD, i,
1001                 value_vr (SD_, 0, VS, i));
1002     }
1003 }
1004
1005 010010,0100,1.SEL,5.VT,5.VS,5.VD,011111::::SHFL.PACH.fmt
1006 "shfl.pach.%s<SEL> v<VD>, v<VS>, <VT>"
1007 *mdmx:
1008 // start-sanitize-vr5400
1009 *vr5400:
1010 // end-sanitize-vr5400
1011 {
1012   int i;
1013   int scale = get_scale (SD_, SEL);
1014   for (i = 0; i < (4 >> scale); i++)
1015     {
1016       store_vr (SD_, scale, VD, i,
1017                 value_vr (SD_, scale, VT, i * 2 + 1));
1018       store_vr (SD_, scale, VD, 1 + (4 >> scale),
1019                 value_vr (SD_, scale, VS, i * 2 + 1));
1020     }
1021 }
1022
1023 010010,0101,1.SEL,5.VT,5.VS,5.VD,011111::::SHFL.PACL.fmt
1024 "shfl.pacl.%s<SEL> v<VD>, v<VS>, <VT>"
1025 *mdmx:
1026 // start-sanitize-vr5400
1027 *vr5400:
1028 // end-sanitize-vr5400
1029 {
1030   int i;
1031   int scale = get_scale (SD_, SEL);
1032   for (i = 0; i < (4 >> scale); i++)
1033     {
1034       store_vr (SD_, scale, VD, i,
1035                 value_vr (SD_, scale, VT, i * 2));
1036       store_vr (SD_, scale, VD, 1 + (4 >> scale),
1037                 value_vr (SD_, scale, VS, i * 2));
1038     }
1039 }
1040
1041 010010,0110,1.SEL,5.VT,5.VS,5.VD,011111::::SHFL.MIXH.fmt
1042 "shfl.mixh.%s<SEL> v<VD>, v<VS>, <VT>"
1043 *mdmx:
1044 // start-sanitize-vr5400
1045 *vr5400:
1046 // end-sanitize-vr5400
1047 {
1048   int i;
1049   int scale = get_scale (SD_, SEL);
1050   for (i = 0; i < (4 >> scale); i++)
1051     {
1052       store_vr (SD_, scale, VD, i * 2,
1053                 value_vr (SD_, scale, VT, i + (4 >> scale)));
1054       store_vr (SD_, scale, VD, i * 2 + 1,
1055                 value_vr (SD_, scale, VS, i + (4 >> scale)));
1056     }
1057 }
1058
1059 010010,0111,1.SEL,5.VT,5.VS,5.VD,011111::::SHFL.MIXL.fmt
1060 "shfl.mixl.%s<SEL> v<VD>, v<VS>, <VT>"
1061 *mdmx:
1062 // start-sanitize-vr5400
1063 *vr5400:
1064 // end-sanitize-vr5400
1065 {
1066   int i;
1067   int scale = get_scale (SD_, SEL);
1068   for (i = 0; i < (4 >> scale); i++)
1069     {
1070       store_vr (SD_, scale, VD, i * 2,
1071                 value_vr (SD_, scale, VT, i));
1072       store_vr (SD_, scale, VD, i * 2 + 1,
1073                 value_vr (SD_, scale, VS, i));
1074     }
1075 }
1076
1077 010010,100,01,5.VT,5.VS,5.VD,011111::::SHFL.BFLA.fmt
1078 "shfl.bfla.qh v<VD>, v<VS>, <VT>"
1079 *mdmx:
1080 {
1081   store_vr (SD_, 1, VD, 0,
1082             value_vr (SD_, 1, VT, 1));
1083   store_vr (SD_, 1, VD, 1,
1084             value_vr (SD_, 1, VS, 0));
1085   store_vr (SD_, 1, VD, 2,
1086             value_vr (SD_, 1, VT, 3));
1087   store_vr (SD_, 1, VD, 3,
1088             value_vr (SD_, 1, VS, 2));
1089 }
1090
1091 010010,101,01,5.VT,5.VS,5.VD,011111::::SHFL.BFLB.fmt
1092 "shfl.bflb.qh v<VD>, v<VS>, <VT>"
1093 *mdmx:
1094 {
1095   store_vr (SD_, 1, VD, 0,
1096             value_vr (SD_, 1, VT, 3));
1097   store_vr (SD_, 1, VD, 1,
1098             value_vr (SD_, 1, VS, 2));
1099   store_vr (SD_, 1, VD, 2,
1100             value_vr (SD_, 1, VT, 1));
1101   store_vr (SD_, 1, VD, 3,
1102             value_vr (SD_, 1, VS, 0));
1103 }
1104
1105 010010,101,01,5.VT,5.VS,5.VD,011111::::SHFL.REPA.fmt
1106 "shfl.repa.qh v<VD>, v<VS>, <VT>"
1107 *mdmx:
1108 {
1109   store_vr (SD_, 1, VD, 0,
1110             value_vr (SD_, 1, VT, 2));
1111   store_vr (SD_, 1, VD, 1,
1112             value_vr (SD_, 1, VT, 3));
1113   store_vr (SD_, 1, VD, 2,
1114             value_vr (SD_, 1, VS, 2));
1115   store_vr (SD_, 1, VD, 3,
1116             value_vr (SD_, 1, VS, 3));
1117 }
1118
1119 010010,101,01,5.VT,5.VS,5.VD,011111::::SHFL.REPB.fmt
1120 "shfl.repb.qh v<VD>, v<VS>, <VT>"
1121 *mdmx:
1122 {
1123   store_vr (SD_, 1, VD, 0,
1124             value_vr (SD_, 1, VT, 0));
1125   store_vr (SD_, 1, VD, 1,
1126             value_vr (SD_, 1, VT, 1));
1127   store_vr (SD_, 1, VD, 2,
1128             value_vr (SD_, 1, VS, 0));
1129   store_vr (SD_, 1, VD, 3,
1130             value_vr (SD_, 1, VS, 1));
1131 }
1132
1133
1134
1135 // Vector Shift Left Logical
1136
1137 010010,5.SEL,5.VT,5.VS,5.VD,010000::::SLL.fmt
1138 "sll.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
1139 *mdmx:
1140 // start-sanitize-vr5400
1141 *vr5400:
1142 // end-sanitize-vr5400
1143 {
1144   int i;
1145   int scale = get_scale (SD_, SEL);
1146   int mask = (4 << scale) - 1;
1147   for (i = 0; i < (8 >> scale); i++)
1148     store_vr (SD_, scale, VD, i,
1149               (value_vr (SD_, scale, VS, i)
1150                << (select_vr (SD_, SEL, VT, i) & mask)));
1151 }
1152
1153
1154
1155 // Vector Shift Right Arithmetic
1156
1157 010010,5.SEL,5.VT,5.VS,5.VD,010011::::SRA.fmt
1158 "sra.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
1159 *mdmx:
1160 {
1161   int i;
1162   int mask = (4 << scale) - 1;
1163   int scale = get_scale (SD_, SEL);
1164   for (i = 0; i < (8 >> scale); i++)
1165     store_vr (SD_, scale, VD, i,
1166               (value_vr (SD_, scale, VS, i)
1167                >> (select_vr (SD_, SEL, VT, i) & mask)));
1168 }
1169
1170
1171
1172 // Vector Shift Right Logical.
1173
1174 010010,5.SEL,5.VT,5.VS,5.VD,010010::::SRL.fmt
1175 "srl.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
1176 *mdmx:
1177 // start-sanitize-vr5400
1178 *vr5400:
1179 // end-sanitize-vr5400
1180 {
1181   int i;
1182   int scale = get_scale (SD_, SEL);
1183   int mask = (4 << scale) - 1;
1184   int zeros = (1 << (8 << scale)) - 1;
1185   for (i = 0; i < (8 >> scale); i++)
1186     store_vr (SD_, scale, VD, i,
1187               ((value_vr (SD_, scale, VS, i) & zeros)
1188                >> (select_vr (SD_, SEL, VT, i) & mask)));
1189 }
1190
1191
1192
1193 // Vector Subtract.
1194
1195 010010,5.SEL,5.VT,5.VS,5.VD,001010::::SUB.fmt
1196 "sub.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
1197 *mdmx:
1198 // start-sanitize-vr5400
1199 *vr5400:
1200 // end-sanitize-vr5400
1201 {
1202   int i;
1203   int scale = get_scale (SD_, SEL);
1204   for (i = 0; i < (8 >> scale); i++)
1205     store_vr (SD_, scale, VD, i,
1206               (value_vr (SD_, scale, VS, i)
1207                - select_vr (SD_, SEL, VT, i)));
1208 }
1209
1210
1211
1212 // Accumulate Vector Difference
1213
1214 010010,5.SEL,5.VT,5.VS,0,0000,110110::::SUBA.fmt
1215 "suba.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
1216 *mdmx:
1217 {
1218   int i;
1219   int scale = get_scale (SD_, SEL);
1220   for (i = 0; i < (8 >> scale); i++)
1221     store_acc (SD_, scale, VD, i,
1222                (value_acc (SD, scale, i)
1223                 + (signed64) value_vr (SD_, scale, VS, i)
1224                 - (signed64) select_vr (SD_, SEL, VT, i)));
1225 }
1226
1227
1228
1229 // Load Vector Difference
1230
1231 010010,5.SEL,5.VT,5.VS,1,0000,110110::::SUBL.fmt
1232 "subl.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
1233 *mdmx:
1234 {
1235   int i;
1236   int scale = get_scale (SD_, SEL);
1237   for (i = 0; i < (8 >> scale); i++)
1238     store_acc (SD_, scale, VD, i,
1239                ((signed64) value_vr (SD_, scale, VS, i)
1240                 - (signed64) select_vr (SD_, SEL, VT, i)));
1241 }
1242
1243
1244
1245 // Write Accumulator High.
1246
1247 010010,1000,1.SEL,00000,5.VS,00000,111110::::WACH.fmt
1248 "wach.%s<SEL> v<VS>"
1249 *mdmx:
1250 // start-sanitize-vr5400
1251 *vr5400:
1252 // end-sanitize-vr5400
1253 {
1254   int i;
1255   int scale = get_scale (SD_, SEL);
1256   for (i = 0; i < (8 >> scale); i++)
1257     store_acc (SD_, scale, i,
1258                (((signed64) value_vr (SD_, scale, VS, i) << (16 << scale))
1259                 | MASKED (value_acc (SD_, scale, i), (16 << scale) - 1, 0)));
1260 }
1261
1262
1263
1264 // Vector Write Accumulator Low.
1265
1266 010010,0000,1.SEL,5.VT,5.VS,00000,111110::::WACL.fmt
1267 "wacl.%s<SEL> v<VS>, <VT>"
1268 *mdmx:
1269 // start-sanitize-vr5400
1270 *vr5400:
1271 // end-sanitize-vr5400
1272 {
1273   int i;
1274   int scale = get_scale (SD_, SEL);
1275   for (i = 0; i < (8 >> scale); i++)
1276     store_acc (SD_, scale, i,
1277                (((signed64) value_vr (SD_, scale, VS, i) << (16 << scale))
1278                 | MASKED (value_vr (SD_, scale, VT, i),
1279                           (16 << scale) - 1, 0)));
1280 }
1281
1282
1283
1284 // Vector Xor.
1285
1286 010010,5.SEL,5.VT,5.VS,5.VD,001101::::XOR.fmt
1287 "xor.%s<SEL> v<VD>, v<VS>, %s<VT#SEL,VT>"
1288 *mdmx:
1289 // start-sanitize-vr5400
1290 *vr5400:
1291 // end-sanitize-vr5400
1292 {
1293   int i;
1294   int scale = get_scale (SD_, SEL);
1295   for (i = 0; i < (8 >> scale); i++)
1296     store_vr (SD_, scale, VD, i,
1297               (value_vr (SD_, scale, VS, i)
1298                ^ select_vr (SD_, SEL, VT, i)));
1299 }