]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/mips/mdmx.c
Update copyright year range in all GDB files
[thirdparty/binutils-gdb.git] / sim / mips / mdmx.c
CommitLineData
f4f1b9f1 1/* Simulation code for the MIPS MDMX ASE.
e2882c85 2 Copyright (C) 2002-2018 Free Software Foundation, Inc.
dd69d292
CD
3 Contributed by Ed Satterthwaite and Chris Demetriou, of Broadcom
4 Corporation (SiByte).
f4f1b9f1
CD
5
6This file is part of GDB, the GNU debugger.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
4744ac1b
JB
10the Free Software Foundation; either version 3 of the License, or
11(at your option) any later version.
f4f1b9f1
CD
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
4744ac1b
JB
18You should have received a copy of the GNU General Public License
19along with this program. If not, see <http://www.gnu.org/licenses/>. */
f4f1b9f1
CD
20
21#include <stdio.h>
22
23#include "sim-main.h"
24
25/* Within mdmx.c we refer to the sim_cpu directly. */
26#define CPU cpu
27#define SD (CPU_STATE(CPU))
a2f8b4f3
CD
28
29/* XXX FIXME: temporary hack while the impact of making unpredictable()
30 a "normal" (non-igen) function is evaluated. */
31#undef Unpredictable
32#define Unpredictable() unpredictable_action (cpu, cia)
f4f1b9f1
CD
33
34/* MDMX Representations
35
36 An 8-bit packed byte element (OB) is always unsigned.
37 The 24-bit accumulators are signed and are represented as 32-bit
38 signed values, which are reduced to 24-bit signed values prior to
39 Round and Clamp operations.
40
41 A 16-bit packed halfword element (QH) is always signed.
42 The 48-bit accumulators are signed and are represented as 64-bit
43 signed values, which are reduced to 48-bit signed values prior to
44 Round and Clamp operations.
45
46 The code below assumes a 2's-complement representation of signed
47 quantities. Care is required to clear extended sign bits when
48 repacking fields.
49
50 The code (and the code for arithmetic shifts in mips.igen) also makes
51 the (not guaranteed portable) assumption that right shifts of signed
52 quantities in C do sign extension. */
53
54typedef unsigned64 unsigned48;
55#define MASK48 (UNSIGNED64 (0xffffffffffff))
56
57typedef unsigned32 unsigned24;
58#define MASK24 (UNSIGNED32 (0xffffff))
59
60typedef enum {
61 mdmx_ob, /* OB (octal byte) */
62 mdmx_qh /* QH (quad half-word) */
63} MX_fmt;
64
65typedef enum {
66 sel_elem, /* element select */
67 sel_vect, /* vector select */
68 sel_imm /* immediate select */
69} VT_select;
70
71#define OB_MAX ((unsigned8)0xFF)
72#define QH_MIN ((signed16)0x8000)
73#define QH_MAX ((signed16)0x7FFF)
74
75#define OB_CLAMP(x) ((unsigned8)((x) > OB_MAX ? OB_MAX : (x)))
76#define QH_CLAMP(x) ((signed16)((x) < QH_MIN ? QH_MIN : \
77 ((x) > QH_MAX ? QH_MAX : (x))))
78
79#define MX_FMT(fmtsel) (((fmtsel) & 0x1) == 0 ? mdmx_ob : mdmx_qh)
80#define MX_VT(fmtsel) (((fmtsel) & 0x10) == 0 ? sel_elem : \
81 (((fmtsel) & 0x18) == 0x10 ? sel_vect : sel_imm))
82
83#define QH_ELEM(v,fmtsel) \
84 ((signed16)(((v) >> (((fmtsel) & 0xC) << 2)) & 0xFFFF))
85#define OB_ELEM(v,fmtsel) \
86 ((unsigned8)(((v) >> (((fmtsel) & 0xE) << 2)) & 0xFF))
87
88
89typedef signed16 (*QH_FUNC)(signed16, signed16);
90typedef unsigned8 (*OB_FUNC)(unsigned8, unsigned8);
91
92/* vectorized logical operators */
93
94static signed16
95AndQH(signed16 ts, signed16 tt)
96{
97 return (signed16)((unsigned16)ts & (unsigned16)tt);
98}
99
100static unsigned8
101AndOB(unsigned8 ts, unsigned8 tt)
102{
103 return ts & tt;
104}
105
106static signed16
107NorQH(signed16 ts, signed16 tt)
108{
109 return (signed16)(((unsigned16)ts | (unsigned16)tt) ^ 0xFFFF);
110}
111
112static unsigned8
113NorOB(unsigned8 ts, unsigned8 tt)
114{
115 return (ts | tt) ^ 0xFF;
116}
117
118static signed16
119OrQH(signed16 ts, signed16 tt)
120{
121 return (signed16)((unsigned16)ts | (unsigned16)tt);
122}
123
124static unsigned8
125OrOB(unsigned8 ts, unsigned8 tt)
126{
127 return ts | tt;
128}
129
130static signed16
131XorQH(signed16 ts, signed16 tt)
132{
133 return (signed16)((unsigned16)ts ^ (unsigned16)tt);
134}
135
136static unsigned8
137XorOB(unsigned8 ts, unsigned8 tt)
138{
139 return ts ^ tt;
140}
141
142static signed16
143SLLQH(signed16 ts, signed16 tt)
144{
145 unsigned32 s = (unsigned32)tt & 0xF;
146 return (signed16)(((unsigned32)ts << s) & 0xFFFF);
147}
148
149static unsigned8
150SLLOB(unsigned8 ts, unsigned8 tt)
151{
152 unsigned32 s = tt & 0x7;
153 return (ts << s) & 0xFF;
154}
155
156static signed16
157SRLQH(signed16 ts, signed16 tt)
158{
159 unsigned32 s = (unsigned32)tt & 0xF;
160 return (signed16)((unsigned16)ts >> s);
161}
162
163static unsigned8
164SRLOB(unsigned8 ts, unsigned8 tt)
165{
166 unsigned32 s = tt & 0x7;
167 return ts >> s;
168}
169
170
171/* Vectorized arithmetic operators. */
172
173static signed16
174AddQH(signed16 ts, signed16 tt)
175{
176 signed32 t = (signed32)ts + (signed32)tt;
177 return QH_CLAMP(t);
178}
179
180static unsigned8
181AddOB(unsigned8 ts, unsigned8 tt)
182{
183 unsigned32 t = (unsigned32)ts + (unsigned32)tt;
184 return OB_CLAMP(t);
185}
186
187static signed16
188SubQH(signed16 ts, signed16 tt)
189{
190 signed32 t = (signed32)ts - (signed32)tt;
191 return QH_CLAMP(t);
192}
193
194static unsigned8
195SubOB(unsigned8 ts, unsigned8 tt)
196{
197 signed32 t;
198 t = (signed32)ts - (signed32)tt;
199 if (t < 0)
200 t = 0;
201 return (unsigned8)t;
202}
203
204static signed16
205MinQH(signed16 ts, signed16 tt)
206{
207 return (ts < tt ? ts : tt);
208}
209
210static unsigned8
211MinOB(unsigned8 ts, unsigned8 tt)
212{
213 return (ts < tt ? ts : tt);
214}
215
216static signed16
217MaxQH(signed16 ts, signed16 tt)
218{
219 return (ts > tt ? ts : tt);
220}
221
222static unsigned8
223MaxOB(unsigned8 ts, unsigned8 tt)
224{
225 return (ts > tt ? ts : tt);
226}
227
228static signed16
229MulQH(signed16 ts, signed16 tt)
230{
231 signed32 t = (signed32)ts * (signed32)tt;
232 return QH_CLAMP(t);
233}
234
235static unsigned8
236MulOB(unsigned8 ts, unsigned8 tt)
237{
238 unsigned32 t = (unsigned32)ts * (unsigned32)tt;
239 return OB_CLAMP(t);
240}
241
242/* "msgn" and "sra" are defined only for QH format. */
243
244static signed16
245MsgnQH(signed16 ts, signed16 tt)
246{
247 signed16 t;
248 if (ts < 0)
249 t = (tt == QH_MIN ? QH_MAX : -tt);
250 else if (ts == 0)
251 t = 0;
252 else
253 t = tt;
254 return t;
255}
256
f4f1b9f1
CD
257static signed16
258SRAQH(signed16 ts, signed16 tt)
259{
260 unsigned32 s = (unsigned32)tt & 0xF;
261 return (signed16)((signed32)ts >> s);
262}
263
264
7cbea089
CD
265/* "pabsdiff" and "pavg" are defined only for OB format. */
266
267static unsigned8
268AbsDiffOB(unsigned8 ts, unsigned8 tt)
269{
270 return (ts >= tt ? ts - tt : tt - ts);
271}
272
273static unsigned8
274AvgOB(unsigned8 ts, unsigned8 tt)
275{
276 return ((unsigned32)ts + (unsigned32)tt + 1) >> 1;
277}
278
279
f4f1b9f1
CD
280/* Dispatch tables for operations that update a CPR. */
281
282static const QH_FUNC qh_func[] = {
283 AndQH, NorQH, OrQH, XorQH, SLLQH, SRLQH,
284 AddQH, SubQH, MinQH, MaxQH,
285 MulQH, MsgnQH, SRAQH, NULL, NULL
286};
287
288static const OB_FUNC ob_func[] = {
289 AndOB, NorOB, OrOB, XorOB, SLLOB, SRLOB,
290 AddOB, SubOB, MinOB, MaxOB,
7cbea089 291 MulOB, NULL, NULL, AbsDiffOB, AvgOB
f4f1b9f1
CD
292};
293
294/* Auxiliary functions for CPR updates. */
295
296/* Vector mapping for QH format. */
297static unsigned64
298qh_vector_op(unsigned64 v1, unsigned64 v2, QH_FUNC func)
299{
300 unsigned64 result = 0;
301 int i;
302 signed16 h, h1, h2;
303
304 for (i = 0; i < 64; i += 16)
305 {
306 h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16;
307 h2 = (signed16)(v2 & 0xFFFF); v2 >>= 16;
308 h = (*func)(h1, h2);
309 result |= ((unsigned64)((unsigned16)h) << i);
310 }
311 return result;
312}
313
314static unsigned64
315qh_map_op(unsigned64 v1, signed16 h2, QH_FUNC func)
316{
317 unsigned64 result = 0;
318 int i;
319 signed16 h, h1;
320
321 for (i = 0; i < 64; i += 16)
322 {
323 h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16;
324 h = (*func)(h1, h2);
325 result |= ((unsigned64)((unsigned16)h) << i);
326 }
327 return result;
328}
329
330
331/* Vector operations for OB format. */
332
333static unsigned64
334ob_vector_op(unsigned64 v1, unsigned64 v2, OB_FUNC func)
335{
336 unsigned64 result = 0;
337 int i;
338 unsigned8 b, b1, b2;
339
340 for (i = 0; i < 64; i += 8)
341 {
342 b1 = v1 & 0xFF; v1 >>= 8;
343 b2 = v2 & 0xFF; v2 >>= 8;
344 b = (*func)(b1, b2);
345 result |= ((unsigned64)b << i);
346 }
347 return result;
348}
349
350static unsigned64
351ob_map_op(unsigned64 v1, unsigned8 b2, OB_FUNC func)
352{
353 unsigned64 result = 0;
354 int i;
355 unsigned8 b, b1;
356
357 for (i = 0; i < 64; i += 8)
358 {
359 b1 = v1 & 0xFF; v1 >>= 8;
360 b = (*func)(b1, b2);
361 result |= ((unsigned64)b << i);
362 }
363 return result;
364}
365
366
367/* Primary entry for operations that update CPRs. */
368unsigned64
369mdmx_cpr_op(sim_cpu *cpu,
370 address_word cia,
371 int op,
372 unsigned64 op1,
373 int vt,
374 MX_fmtsel fmtsel)
375{
376 unsigned64 op2;
377 unsigned64 result = 0;
378
379 switch (MX_FMT (fmtsel))
380 {
381 case mdmx_qh:
382 switch (MX_VT (fmtsel))
383 {
384 case sel_elem:
385 op2 = ValueFPR(vt, fmt_mdmx);
386 result = qh_map_op(op1, QH_ELEM(op2, fmtsel), qh_func[op]);
387 break;
388 case sel_vect:
389 result = qh_vector_op(op1, ValueFPR(vt, fmt_mdmx), qh_func[op]);
390 break;
391 case sel_imm:
392 result = qh_map_op(op1, vt, qh_func[op]);
393 break;
394 }
395 break;
396 case mdmx_ob:
397 switch (MX_VT (fmtsel))
398 {
399 case sel_elem:
400 op2 = ValueFPR(vt, fmt_mdmx);
401 result = ob_map_op(op1, OB_ELEM(op2, fmtsel), ob_func[op]);
402 break;
403 case sel_vect:
404 result = ob_vector_op(op1, ValueFPR(vt, fmt_mdmx), ob_func[op]);
405 break;
406 case sel_imm:
407 result = ob_map_op(op1, vt, ob_func[op]);
408 break;
409 }
410 break;
411 default:
412 Unpredictable ();
413 }
414
415 return result;
416}
417
418
419/* Operations that update CCs */
420
421static void
422qh_vector_test(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int cond)
423{
424 int i;
425 signed16 h1, h2;
426 int boolean;
427
428 for (i = 0; i < 4; i++)
429 {
430 h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16;
431 h2 = (signed16)(v2 & 0xFFFF); v2 >>= 16;
432 boolean = ((cond & MX_C_EQ) && (h1 == h2)) ||
433 ((cond & MX_C_LT) && (h1 < h2));
434 SETFCC(i, boolean);
435 }
436}
437
438static void
439qh_map_test(sim_cpu *cpu, unsigned64 v1, signed16 h2, int cond)
440{
441 int i;
442 signed16 h1;
443 int boolean;
444
445 for (i = 0; i < 4; i++)
446 {
447 h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16;
448 boolean = ((cond & MX_C_EQ) && (h1 == h2)) ||
449 ((cond & MX_C_LT) && (h1 < h2));
450 SETFCC(i, boolean);
451 }
452}
453
454static void
455ob_vector_test(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int cond)
456{
457 int i;
458 unsigned8 b1, b2;
459 int boolean;
460
461 for (i = 0; i < 8; i++)
462 {
463 b1 = v1 & 0xFF; v1 >>= 8;
464 b2 = v2 & 0xFF; v2 >>= 8;
465 boolean = ((cond & MX_C_EQ) && (b1 == b2)) ||
466 ((cond & MX_C_LT) && (b1 < b2));
467 SETFCC(i, boolean);
468 }
469}
470
471static void
472ob_map_test(sim_cpu *cpu, unsigned64 v1, unsigned8 b2, int cond)
473{
474 int i;
475 unsigned8 b1;
476 int boolean;
477
478 for (i = 0; i < 8; i++)
479 {
480 b1 = (unsigned8)(v1 & 0xFF); v1 >>= 8;
481 boolean = ((cond & MX_C_EQ) && (b1 == b2)) ||
482 ((cond & MX_C_LT) && (b1 < b2));
483 SETFCC(i, boolean);
484 }
485}
486
487
488void
489mdmx_cc_op(sim_cpu *cpu,
490 address_word cia,
491 int cond,
492 unsigned64 v1,
493 int vt,
494 MX_fmtsel fmtsel)
495{
496 unsigned64 op2;
497
498 switch (MX_FMT (fmtsel))
499 {
500 case mdmx_qh:
501 switch (MX_VT (fmtsel))
502 {
503 case sel_elem:
504 op2 = ValueFPR(vt, fmt_mdmx);
505 qh_map_test(cpu, v1, QH_ELEM(op2, fmtsel), cond);
506 break;
507 case sel_vect:
508 qh_vector_test(cpu, v1, ValueFPR(vt, fmt_mdmx), cond);
509 break;
510 case sel_imm:
511 qh_map_test(cpu, v1, vt, cond);
512 break;
513 }
514 break;
515 case mdmx_ob:
516 switch (MX_VT (fmtsel))
517 {
518 case sel_elem:
519 op2 = ValueFPR(vt, fmt_mdmx);
520 ob_map_test(cpu, v1, OB_ELEM(op2, fmtsel), cond);
521 break;
522 case sel_vect:
523 ob_vector_test(cpu, v1, ValueFPR(vt, fmt_mdmx), cond);
524 break;
525 case sel_imm:
526 ob_map_test(cpu, v1, vt, cond);
527 break;
528 }
529 break;
530 default:
531 Unpredictable ();
532 }
533}
534
535
536/* Pick operations. */
537
538static unsigned64
539qh_vector_pick(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int tf)
540{
541 unsigned64 result = 0;
542 int i, s;
543 unsigned16 h;
544
545 s = 0;
546 for (i = 0; i < 4; i++)
547 {
548 h = ((GETFCC(i) == tf) ? (v1 & 0xFFFF) : (v2 & 0xFFFF));
549 v1 >>= 16; v2 >>= 16;
550 result |= ((unsigned64)h << s);
551 s += 16;
552 }
553 return result;
554}
555
556static unsigned64
557qh_map_pick(sim_cpu *cpu, unsigned64 v1, signed16 h2, int tf)
558{
559 unsigned64 result = 0;
560 int i, s;
561 unsigned16 h;
562
563 s = 0;
564 for (i = 0; i < 4; i++)
565 {
566 h = (GETFCC(i) == tf) ? (v1 & 0xFFFF) : (unsigned16)h2;
567 v1 >>= 16;
568 result |= ((unsigned64)h << s);
569 s += 16;
570 }
571 return result;
572}
573
574static unsigned64
575ob_vector_pick(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int tf)
576{
577 unsigned64 result = 0;
578 int i, s;
579 unsigned8 b;
580
581 s = 0;
582 for (i = 0; i < 8; i++)
583 {
584 b = (GETFCC(i) == tf) ? (v1 & 0xFF) : (v2 & 0xFF);
585 v1 >>= 8; v2 >>= 8;
586 result |= ((unsigned64)b << s);
587 s += 8;
588 }
589 return result;
590}
591
592static unsigned64
593ob_map_pick(sim_cpu *cpu, unsigned64 v1, unsigned8 b2, int tf)
594{
595 unsigned64 result = 0;
596 int i, s;
597 unsigned8 b;
598
599 s = 0;
600 for (i = 0; i < 8; i++)
601 {
602 b = (GETFCC(i) == tf) ? (v1 & 0xFF) : b2;
603 v1 >>= 8;
604 result |= ((unsigned64)b << s);
605 s += 8;
606 }
607 return result;
608}
609
610
611unsigned64
612mdmx_pick_op(sim_cpu *cpu,
613 address_word cia,
614 int tf,
615 unsigned64 v1,
616 int vt,
617 MX_fmtsel fmtsel)
618{
619 unsigned64 result = 0;
620 unsigned64 op2;
621
622 switch (MX_FMT (fmtsel))
623 {
624 case mdmx_qh:
625 switch (MX_VT (fmtsel))
626 {
627 case sel_elem:
628 op2 = ValueFPR(vt, fmt_mdmx);
629 result = qh_map_pick(cpu, v1, QH_ELEM(op2, fmtsel), tf);
630 break;
631 case sel_vect:
632 result = qh_vector_pick(cpu, v1, ValueFPR(vt, fmt_mdmx), tf);
633 break;
634 case sel_imm:
635 result = qh_map_pick(cpu, v1, vt, tf);
636 break;
637 }
638 break;
639 case mdmx_ob:
640 switch (MX_VT (fmtsel))
641 {
642 case sel_elem:
643 op2 = ValueFPR(vt, fmt_mdmx);
644 result = ob_map_pick(cpu, v1, OB_ELEM(op2, fmtsel), tf);
645 break;
646 case sel_vect:
647 result = ob_vector_pick(cpu, v1, ValueFPR(vt, fmt_mdmx), tf);
648 break;
649 case sel_imm:
650 result = ob_map_pick(cpu, v1, vt, tf);
651 break;
652 }
653 break;
654 default:
655 Unpredictable ();
656 }
657 return result;
658}
659
660
661/* Accumulators. */
662
663typedef void (*QH_ACC)(signed48 *a, signed16 ts, signed16 tt);
664
665static void
666AccAddAQH(signed48 *a, signed16 ts, signed16 tt)
667{
668 *a += (signed48)ts + (signed48)tt;
669}
670
671static void
672AccAddLQH(signed48 *a, signed16 ts, signed16 tt)
673{
674 *a = (signed48)ts + (signed48)tt;
675}
676
677static void
678AccMulAQH(signed48 *a, signed16 ts, signed16 tt)
679{
680 *a += (signed48)ts * (signed48)tt;
681}
682
683static void
684AccMulLQH(signed48 *a, signed16 ts, signed16 tt)
685{
686 *a = (signed48)ts * (signed48)tt;
687}
688
689static void
690SubMulAQH(signed48 *a, signed16 ts, signed16 tt)
691{
692 *a -= (signed48)ts * (signed48)tt;
693}
694
695static void
696SubMulLQH(signed48 *a, signed16 ts, signed16 tt)
697{
698 *a = -((signed48)ts * (signed48)tt);
699}
700
701static void
702AccSubAQH(signed48 *a, signed16 ts, signed16 tt)
703{
704 *a += (signed48)ts - (signed48)tt;
705}
706
707static void
708AccSubLQH(signed48 *a, signed16 ts, signed16 tt)
709{
710 *a = (signed48)ts - (signed48)tt;
711}
712
713
714typedef void (*OB_ACC)(signed24 *acc, unsigned8 ts, unsigned8 tt);
715
716static void
717AccAddAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
718{
719 *a += (signed24)ts + (signed24)tt;
720}
721
722static void
723AccAddLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
724{
725 *a = (signed24)ts + (signed24)tt;
726}
727
728static void
729AccMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
730{
731 *a += (signed24)ts * (signed24)tt;
732}
733
734static void
735AccMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
736{
737 *a = (signed24)ts * (signed24)tt;
738}
739
740static void
741SubMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
742{
743 *a -= (signed24)ts * (signed24)tt;
744}
745
746static void
747SubMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
748{
749 *a = -((signed24)ts * (signed24)tt);
750}
751
752static void
753AccSubAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
754{
755 *a += (signed24)ts - (signed24)tt;
756}
757
758static void
759AccSubLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
760{
761 *a = (signed24)ts - (signed24)tt;
762}
763
7cbea089
CD
764static void
765AccAbsDiffOB(signed24 *a, unsigned8 ts, unsigned8 tt)
766{
767 unsigned8 t = (ts >= tt ? ts - tt : tt - ts);
768 *a += (signed24)t;
769}
770
f4f1b9f1
CD
771
772/* Dispatch tables for operations that update a CPR. */
773
774static const QH_ACC qh_acc[] = {
775 AccAddAQH, AccAddAQH, AccMulAQH, AccMulLQH,
7cbea089
CD
776 SubMulAQH, SubMulLQH, AccSubAQH, AccSubLQH,
777 NULL
f4f1b9f1
CD
778};
779
780static const OB_ACC ob_acc[] = {
781 AccAddAOB, AccAddLOB, AccMulAOB, AccMulLOB,
7cbea089
CD
782 SubMulAOB, SubMulLOB, AccSubAOB, AccSubLOB,
783 AccAbsDiffOB
f4f1b9f1
CD
784};
785
786
787static void
788qh_vector_acc(signed48 a[], unsigned64 v1, unsigned64 v2, QH_ACC acc)
789{
790 int i;
791 signed16 h1, h2;
792
793 for (i = 0; i < 4; i++)
794 {
795 h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16;
796 h2 = (signed16)(v2 & 0xFFFF); v2 >>= 16;
797 (*acc)(&a[i], h1, h2);
798 }
799}
800
801static void
802qh_map_acc(signed48 a[], unsigned64 v1, signed16 h2, QH_ACC acc)
803{
804 int i;
805 signed16 h1;
806
807 for (i = 0; i < 4; i++)
808 {
809 h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16;
810 (*acc)(&a[i], h1, h2);
811 }
812}
813
814static void
815ob_vector_acc(signed24 a[], unsigned64 v1, unsigned64 v2, OB_ACC acc)
816{
817 int i;
818 unsigned8 b1, b2;
819
820 for (i = 0; i < 8; i++)
821 {
822 b1 = v1 & 0xFF; v1 >>= 8;
823 b2 = v2 & 0xFF; v2 >>= 8;
824 (*acc)(&a[i], b1, b2);
825 }
826}
827
828static void
829ob_map_acc(signed24 a[], unsigned64 v1, unsigned8 b2, OB_ACC acc)
830{
831 int i;
832 unsigned8 b1;
833
834 for (i = 0; i < 8; i++)
835 {
836 b1 = v1 & 0xFF; v1 >>= 8;
837 (*acc)(&a[i], b1, b2);
838 }
839}
840
841
842/* Primary entry for operations that accumulate */
843void
844mdmx_acc_op(sim_cpu *cpu,
845 address_word cia,
846 int op,
847 unsigned64 op1,
848 int vt,
849 MX_fmtsel fmtsel)
850{
851 unsigned64 op2;
852
853 switch (MX_FMT (fmtsel))
854 {
855 case mdmx_qh:
856 switch (MX_VT (fmtsel))
857 {
858 case sel_elem:
859 op2 = ValueFPR(vt, fmt_mdmx);
860 qh_map_acc(ACC.qh, op1, QH_ELEM(op2, fmtsel), qh_acc[op]);
861 break;
862 case sel_vect:
863 qh_vector_acc(ACC.qh, op1, ValueFPR(vt, fmt_mdmx), qh_acc[op]);
864 break;
865 case sel_imm:
866 qh_map_acc(ACC.qh, op1, vt, qh_acc[op]);
867 break;
868 }
869 break;
870 case mdmx_ob:
871 switch (MX_VT (fmtsel))
872 {
873 case sel_elem:
874 op2 = ValueFPR(vt, fmt_mdmx);
875 ob_map_acc(ACC.ob, op1, OB_ELEM(op2, fmtsel), ob_acc[op]);
876 break;
877 case sel_vect:
878 ob_vector_acc(ACC.ob, op1, ValueFPR(vt, fmt_mdmx), ob_acc[op]);
879 break;
880 case sel_imm:
a2f8b4f3 881 ob_map_acc(ACC.ob, op1, vt, ob_acc[op]);
f4f1b9f1
CD
882 break;
883 }
884 break;
885 default:
886 Unpredictable ();
887 }
888}
889
890
891/* Reading and writing accumulator (no conversion). */
892
893unsigned64
894mdmx_rac_op(sim_cpu *cpu,
895 address_word cia,
896 int op,
897 int fmt)
898{
899 unsigned64 result;
900 unsigned int shift;
901 int i;
902
903 shift = op; /* L = 00, M = 01, H = 10. */
904 result = 0;
905
906 switch (fmt)
907 {
908 case MX_FMT_QH:
909 shift <<= 4; /* 16 bits per element. */
910 for (i = 3; i >= 0; --i)
911 {
912 result <<= 16;
913 result |= ((ACC.qh[i] >> shift) & 0xFFFF);
914 }
915 break;
916 case MX_FMT_OB:
917 shift <<= 3; /* 8 bits per element. */
918 for (i = 7; i >= 0; --i)
919 {
920 result <<= 8;
921 result |= ((ACC.ob[i] >> shift) & 0xFF);
922 }
923 break;
924 default:
925 Unpredictable ();
926 }
927 return result;
928}
929
930void
931mdmx_wacl(sim_cpu *cpu,
932 address_word cia,
933 int fmt,
934 unsigned64 vs,
935 unsigned64 vt)
936{
937 int i;
938
939 switch (fmt)
940 {
941 case MX_FMT_QH:
942 for (i = 0; i < 4; i++)
943 {
944 signed32 s = (signed16)(vs & 0xFFFF);
945 ACC.qh[i] = ((signed48)s << 16) | (vt & 0xFFFF);
946 vs >>= 16; vt >>= 16;
947 }
948 break;
949 case MX_FMT_OB:
950 for (i = 0; i < 8; i++)
951 {
952 signed16 s = (signed8)(vs & 0xFF);
953 ACC.ob[i] = ((signed24)s << 8) | (vt & 0xFF);
954 vs >>= 8; vt >>= 8;
955 }
956 break;
957 default:
958 Unpredictable ();
959 }
960}
961
962void
963mdmx_wach(sim_cpu *cpu,
964 address_word cia,
965 int fmt,
966 unsigned64 vs)
967{
968 int i;
969
970 switch (fmt)
971 {
972 case MX_FMT_QH:
973 for (i = 0; i < 4; i++)
974 {
975 signed32 s = (signed16)(vs & 0xFFFF);
976 ACC.qh[i] &= ~((signed48)0xFFFF << 32);
977 ACC.qh[i] |= ((signed48)s << 32);
978 vs >>= 16;
979 }
980 break;
981 case MX_FMT_OB:
982 for (i = 0; i < 8; i++)
983 {
984 ACC.ob[i] &= ~((signed24)0xFF << 16);
985 ACC.ob[i] |= ((signed24)(vs & 0xFF) << 16);
986 vs >>= 8;
987 }
988 break;
989 default:
990 Unpredictable ();
991 }
992}
993
994
995/* Reading and writing accumulator (rounding conversions).
996 Enumerating function guarantees s >= 0 for QH ops. */
997
998typedef signed16 (*QH_ROUND)(signed48 a, signed16 s);
999
1000#define QH_BIT(n) ((unsigned48)1 << (n))
1001#define QH_ONES(n) (((unsigned48)1 << (n))-1)
1002
1003static signed16
1004RNASQH(signed48 a, signed16 s)
1005{
1006 signed48 t;
1007 signed16 result = 0;
1008
1009 if (s > 48)
1010 result = 0;
1011 else
1012 {
1013 t = (a >> s);
1014 if ((a & QH_BIT(47)) == 0)
1015 {
1016 if (s > 0 && ((a >> (s-1)) & 1) == 1)
1017 t++;
1018 if (t > QH_MAX)
1019 t = QH_MAX;
1020 }
1021 else
1022 {
1023 if (s > 0 && ((a >> (s-1)) & 1) == 1)
1024 {
1025 if (s > 1 && ((unsigned48)a & QH_ONES(s-1)) != 0)
1026 t++;
1027 }
1028 if (t < QH_MIN)
1029 t = QH_MIN;
1030 }
1031 result = (signed16)t;
1032 }
1033 return result;
1034}
1035
1036static signed16
1037RNAUQH(signed48 a, signed16 s)
1038{
1039 unsigned48 t;
1040 signed16 result;
1041
1042 if (s > 48)
1043 result = 0;
1044 else if (s == 48)
1045 result = ((unsigned48)a & MASK48) >> 47;
1046 else
1047 {
1048 t = ((unsigned48)a & MASK48) >> s;
1049 if (s > 0 && ((a >> (s-1)) & 1) == 1)
1050 t++;
1051 if (t > 0xFFFF)
1052 t = 0xFFFF;
1053 result = (signed16)t;
1054 }
1055 return result;
1056}
1057
1058static signed16
1059RNESQH(signed48 a, signed16 s)
1060{
1061 signed48 t;
1062 signed16 result = 0;
1063
1064 if (s > 47)
1065 result = 0;
1066 else
1067 {
1068 t = (a >> s);
1069 if (s > 0 && ((a >> (s-1)) & 1) == 1)
1070 {
1071 if (s == 1 || (a & QH_ONES(s-1)) == 0)
1072 t += t & 1;
1073 else
1074 t += 1;
1075 }
1076 if ((a & QH_BIT(47)) == 0)
1077 {
1078 if (t > QH_MAX)
1079 t = QH_MAX;
1080 }
1081 else
1082 {
1083 if (t < QH_MIN)
1084 t = QH_MIN;
1085 }
1086 result = (signed16)t;
1087 }
1088 return result;
1089}
1090
1091static signed16
1092RNEUQH(signed48 a, signed16 s)
1093{
1094 unsigned48 t;
1095 signed16 result;
1096
1097 if (s > 48)
1098 result = 0;
1099 else if (s == 48)
1100 result = ((unsigned48)a > QH_BIT(47) ? 1 : 0);
1101 else
1102 {
1103 t = ((unsigned48)a & MASK48) >> s;
1104 if (s > 0 && ((a >> (s-1)) & 1) == 1)
1105 {
1106 if (s > 1 && (a & QH_ONES(s-1)) != 0)
1107 t++;
1108 else
1109 t += t & 1;
1110 }
1111 if (t > 0xFFFF)
1112 t = 0xFFFF;
1113 result = (signed16)t;
1114 }
1115 return result;
1116}
1117
1118static signed16
1119RZSQH(signed48 a, signed16 s)
1120{
1121 signed48 t;
1122 signed16 result = 0;
1123
1124 if (s > 47)
1125 result = 0;
1126 else
1127 {
1128 t = (a >> s);
1129 if ((a & QH_BIT(47)) == 0)
1130 {
1131 if (t > QH_MAX)
1132 t = QH_MAX;
1133 }
1134 else
1135 {
1136 if (t < QH_MIN)
1137 t = QH_MIN;
1138 }
1139 result = (signed16)t;
1140 }
1141 return result;
1142}
1143
1144static signed16
1145RZUQH(signed48 a, signed16 s)
1146{
1147 unsigned48 t;
1148 signed16 result = 0;
1149
1150 if (s > 48)
1151 result = 0;
1152 else if (s == 48)
1153 result = ((unsigned48)a > QH_BIT(47) ? 1 : 0);
1154 else
1155 {
1156 t = ((unsigned48)a & MASK48) >> s;
1157 if (t > 0xFFFF)
1158 t = 0xFFFF;
1159 result = (signed16)t;
1160 }
1161 return result;
1162}
1163
1164
1165typedef unsigned8 (*OB_ROUND)(signed24 a, unsigned8 s);
1166
1167#define OB_BIT(n) ((unsigned24)1 << (n))
1168#define OB_ONES(n) (((unsigned24)1 << (n))-1)
1169
1170static unsigned8
1171RNAUOB(signed24 a, unsigned8 s)
1172{
1173 unsigned8 result;
1174 unsigned24 t;
1175
1176 if (s > 24)
1177 result = 0;
1178 else if (s == 24)
1179 result = ((unsigned24)a & MASK24) >> 23;
1180 else
1181 {
1182 t = ((unsigned24)a & MASK24) >> s;
1183 if (s > 0 && ((a >> (s-1)) & 1) == 1)
1184 t ++;
1185 result = OB_CLAMP(t);
1186 }
1187 return result;
1188}
1189
1190static unsigned8
1191RNEUOB(signed24 a, unsigned8 s)
1192{
1193 unsigned8 result;
1194 unsigned24 t;
1195
1196 if (s > 24)
1197 result = 0;
1198 else if (s == 24)
1199 result = (((unsigned24)a & MASK24) > OB_BIT(23) ? 1 : 0);
1200 else
1201 {
1202 t = ((unsigned24)a & MASK24) >> s;
1203 if (s > 0 && ((a >> (s-1)) & 1) == 1)
1204 {
1205 if (s > 1 && (a & OB_ONES(s-1)) != 0)
1206 t++;
1207 else
1208 t += t & 1;
1209 }
1210 result = OB_CLAMP(t);
1211 }
1212 return result;
1213}
1214
1215static unsigned8
1216RZUOB(signed24 a, unsigned8 s)
1217{
1218 unsigned8 result;
1219 unsigned24 t;
1220
1221 if (s >= 24)
1222 result = 0;
1223 else
1224 {
1225 t = ((unsigned24)a & MASK24) >> s;
1226 result = OB_CLAMP(t);
1227 }
1228 return result;
1229}
1230
1231
1232static const QH_ROUND qh_round[] = {
1233 RNASQH, RNAUQH, RNESQH, RNEUQH, RZSQH, RZUQH
1234};
1235
1236static const OB_ROUND ob_round[] = {
1237 NULL, RNAUOB, NULL, RNEUOB, NULL, RZUOB
1238};
1239
1240
1241static unsigned64
1242qh_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, QH_ROUND round)
1243{
1244 unsigned64 result = 0;
1245 int i, s;
1246 signed16 h, h2;
1247
1248 s = 0;
1249 for (i = 0; i < 4; i++)
1250 {
1251 h2 = (signed16)(v2 & 0xFFFF);
1252 if (h2 >= 0)
1253 h = (*round)(ACC.qh[i], h2);
1254 else
1255 {
1256 UnpredictableResult ();
1257 h = 0xdead;
1258 }
1259 v2 >>= 16;
1260 result |= ((unsigned64)((unsigned16)h) << s);
1261 s += 16;
1262 }
1263 return result;
1264}
1265
1266static unsigned64
1267qh_map_round(sim_cpu *cpu, address_word cia, signed16 h2, QH_ROUND round)
1268{
1269 unsigned64 result = 0;
1270 int i, s;
1271 signed16 h;
1272
1273 s = 0;
1274 for (i = 0; i < 4; i++)
1275 {
1276 if (h2 >= 0)
1277 h = (*round)(ACC.qh[i], h2);
1278 else
1279 {
1280 UnpredictableResult ();
1281 h = 0xdead;
1282 }
1283 result |= ((unsigned64)((unsigned16)h) << s);
1284 s += 16;
1285 }
1286 return result;
1287}
1288
1289static unsigned64
1290ob_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, OB_ROUND round)
1291{
1292 unsigned64 result = 0;
1293 int i, s;
1294 unsigned8 b, b2;
1295
1296 s = 0;
1297 for (i = 0; i < 8; i++)
1298 {
1299 b2 = v2 & 0xFF; v2 >>= 8;
1300 b = (*round)(ACC.ob[i], b2);
1301 result |= ((unsigned64)b << s);
1302 s += 8;
1303 }
1304 return result;
1305}
1306
1307static unsigned64
1308ob_map_round(sim_cpu *cpu, address_word cia, unsigned8 b2, OB_ROUND round)
1309{
1310 unsigned64 result = 0;
1311 int i, s;
1312 unsigned8 b;
1313
1314 s = 0;
1315 for (i = 0; i < 8; i++)
1316 {
1317 b = (*round)(ACC.ob[i], b2);
1318 result |= ((unsigned64)b << s);
1319 s += 8;
1320 }
1321 return result;
1322}
1323
1324
1325unsigned64
1326mdmx_round_op(sim_cpu *cpu,
1327 address_word cia,
1328 int rm,
1329 int vt,
1330 MX_fmtsel fmtsel)
1331{
1332 unsigned64 op2;
1333 unsigned64 result = 0;
1334
1335 switch (MX_FMT (fmtsel))
1336 {
1337 case mdmx_qh:
1338 switch (MX_VT (fmtsel))
1339 {
1340 case sel_elem:
1341 op2 = ValueFPR(vt, fmt_mdmx);
1342 result = qh_map_round(cpu, cia, QH_ELEM(op2, fmtsel), qh_round[rm]);
1343 break;
1344 case sel_vect:
1345 op2 = ValueFPR(vt, fmt_mdmx);
1346 result = qh_vector_round(cpu, cia, op2, qh_round[rm]);
1347 break;
1348 case sel_imm:
1349 result = qh_map_round(cpu, cia, vt, qh_round[rm]);
1350 break;
1351 }
1352 break;
1353 case mdmx_ob:
1354 switch (MX_VT (fmtsel))
1355 {
1356 case sel_elem:
1357 op2 = ValueFPR(vt, fmt_mdmx);
1358 result = ob_map_round(cpu, cia, OB_ELEM(op2, fmtsel), ob_round[rm]);
1359 break;
1360 case sel_vect:
1361 op2 = ValueFPR(vt, fmt_mdmx);
1362 result = ob_vector_round(cpu, cia, op2, ob_round[rm]);
1363 break;
1364 case sel_imm:
1365 result = ob_map_round(cpu, cia, vt, ob_round[rm]);
1366 break;
1367 }
1368 break;
1369 default:
1370 Unpredictable ();
1371 }
1372
1373 return result;
1374}
1375
1376
1377/* Shuffle operation. */
1378
1379typedef struct {
1380 enum {vs, ss, vt} source;
1381 unsigned int index;
1382} sh_map;
1383
1384static const sh_map ob_shuffle[][8] = {
1385 /* MDMX 2.0 encodings (3-4, 6-7). */
1386 /* vr5400 encoding (5), otherwise. */
1387 { }, /* RSVD */
1388 {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* RSVD */
1389 {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}}, /* RSVD */
1390 {{vs,0}, {ss,0}, {vs,1}, {ss,1}, {vs,2}, {ss,2}, {vs,3}, {ss,3}}, /* upsl */
1391 {{vt,1}, {vt,3}, {vt,5}, {vt,7}, {vs,1}, {vs,3}, {vs,5}, {vs,7}}, /* pach */
1392 {{vt,0}, {vt,2}, {vt,4}, {vt,6}, {vs,0}, {vs,2}, {vs,4}, {vs,6}}, /* pacl */
1393 {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* mixh */
1394 {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}} /* mixl */
1395};
1396
1397static const sh_map qh_shuffle[][4] = {
1398 {{vt,2}, {vs,2}, {vt,3}, {vs,3}}, /* mixh */
1399 {{vt,0}, {vs,0}, {vt,1}, {vs,1}}, /* mixl */
1400 {{vt,1}, {vt,3}, {vs,1}, {vs,3}}, /* pach */
1401 { }, /* RSVD */
1402 {{vt,1}, {vs,0}, {vt,3}, {vs,2}}, /* bfla */
1403 { }, /* RSVD */
1404 {{vt,2}, {vt,3}, {vs,2}, {vs,3}}, /* repa */
1405 {{vt,0}, {vt,1}, {vs,0}, {vs,1}} /* repb */
1406};
1407
1408
1409unsigned64
1410mdmx_shuffle(sim_cpu *cpu,
1411 address_word cia,
1412 int shop,
1413 unsigned64 op1,
1414 unsigned64 op2)
1415{
1416 unsigned64 result = 0;
1417 int i, s;
1418 int op;
1419
1420 if ((shop & 0x3) == 0x1) /* QH format. */
1421 {
1422 op = shop >> 2;
1423 s = 0;
1424 for (i = 0; i < 4; i++)
1425 {
1426 unsigned64 v;
1427
1428 switch (qh_shuffle[op][i].source)
1429 {
1430 case vs:
1431 v = op1;
1432 break;
1433 case vt:
1434 v = op2;
1435 break;
1436 default:
1437 Unpredictable ();
1438 v = 0;
1439 }
1440 result |= (((v >> 16*qh_shuffle[op][i].index) & 0xFFFF) << s);
1441 s += 16;
1442 }
1443 }
1444 else if ((shop & 0x1) == 0x0) /* OB format. */
1445 {
1446 op = shop >> 1;
1447 s = 0;
1448 for (i = 0; i < 8; i++)
1449 {
1450 unsigned8 b;
1451 unsigned int ishift = 8*ob_shuffle[op][i].index;
1452
1453 switch (ob_shuffle[op][i].source)
1454 {
1455 case vs:
1456 b = (op1 >> ishift) & 0xFF;
1457 break;
1458 case ss:
1459 b = ((op1 >> ishift) & 0x80) ? 0xFF : 0;
1460 break;
1461 case vt:
1462 b = (op2 >> ishift) & 0xFF;
1463 break;
1464 default:
1465 Unpredictable ();
1466 b = 0;
1467 }
1468 result |= ((unsigned64)b << s);
1469 s += 8;
1470 }
1471 }
1472 else
1473 Unpredictable ();
1474
1475 return result;
1476}