1 /* $NetBSD: fpudispatch.c,v 1.3 2005/12/11 12:17:40 christos Exp $ */
4 * (c) Copyright 1991 HEWLETT-PACKARD COMPANY
6 * To anyone who acknowledges that this file is provided "AS IS"
7 * without any express or implied warranty:
8 * permission to use, copy, modify, and distribute this file
9 * for any purpose is hereby granted without fee, provided that
10 * the above copyright notice and this notice appears in all
11 * copies, and that the name of Hewlett-Packard Company not be
12 * used in advertising or publicity pertaining to distribution
13 * of the software without specific, written prior permission.
14 * Hewlett-Packard Company makes no representations about the
15 * suitability of this software for any purpose.
18 /* Source: /n/schirf/u/baford/CVS/mach4-parisc/kernel/parisc/fpudispatch.c,v
19 * Revision: 1.4 Author: mike
21 * Date: 1994/07/21 17:36:35
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: fpudispatch.c,v 1.3 2005/12/11 12:17:40 christos Exp $");
27 #include <sys/types.h>
28 #include <sys/systm.h>
30 #include "../spmath/float.h"
32 * XXX fredette - hack to glue the bulk of
33 * the spmath library to this dispatcher.
35 #define dbl_integer unsigned
36 #define sgl_floating_point unsigned
37 #define dbl_floating_point unsigned
38 #include "../spmath/sgl_float.h"
39 #include "../spmath/dbl_float.h"
40 #include "../spmath/cnv_float.h"
41 #include "../spmath/md.h"
42 #include "../spmath/fpudispatch.h"
45 * version of EMULATION software for COPR,0,0 instruction
47 #define EMULATION_VERSION 3
48 #define COPR_INST 0x30000000
51 * definition of extru macro. If pos and len are constants, the compiler
52 * will generate an extru instruction when optimized
54 #define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))
55 /* definitions of bit field locations in the instruction */
61 #define fpclass1subpos 16
66 * the following are the extra bits for the 0E major op
74 * the following are for the multi-ops
84 * offset to constant zero in the FP emulation registers
86 #define fpzeroreg (32*sizeof(double)/sizeof(unsigned))
89 * extract the major opcode from the instruction
91 #define get_major(op) extru(op,fpmajorpos,6)
93 * extract the two bit class field from the FP instruction. The class is at bit
96 #define get_class(op) extru(op,fpclasspos,2)
98 * extract the 3 bit subop field. For all but class 1 instructions, it is
99 * located at bit positions 16-18
101 #define get_subop(op) extru(op,fpsubpos,3)
103 * extract the 2 bit subop field from class 1 instructions. It is located
104 * at bit positions 15-16
106 #define get_subop1(op) extru(op,fpclass1subpos,2)
108 /* definitions of unimplemented exceptions */
109 #define MAJOR_0C_EXCP UNIMPLEMENTEDEXCEPTION
110 #define MAJOR_0E_EXCP UNIMPLEMENTEDEXCEPTION
111 #define MAJOR_06_EXCP UNIMPLEMENTEDEXCEPTION
112 #define MAJOR_26_EXCP UNIMPLEMENTEDEXCEPTION
113 #define PA83_UNIMP_EXCP UNIMPLEMENTEDEXCEPTION
116 decode_0c(unsigned ir
,unsigned class,unsigned subop
,unsigned fpregs
[])
118 unsigned r1
,r2
,t
; /* operand register offsets */
119 unsigned fmt
; /* also sf for class 1 conversions */
120 unsigned df
; /* for class 1 conversions */
123 if (ir
== COPR_INST
) {
124 fpregs
[0] = EMULATION_VERSION
<< 11;
127 status
= &fpregs
[0]; /* fp status register */
128 r1
= extru(ir
,fpr1pos
,5) * sizeof(double)/sizeof(unsigned);
129 if (r1
== 0) /* map fr0 source to constant zero */
131 t
= extru(ir
,fptpos
,5) * sizeof(double)/sizeof(unsigned);
132 if (t
== 0 && class != 2) /* don't allow fr0 as a dest */
133 return(MAJOR_0C_EXCP
);
134 fmt
= extru(ir
,fpfmtpos
,2); /* get fmt completer */
139 case 0: /* COPR 0,0 emulated above*/
143 return(MAJOR_0C_EXCP
);
146 case 2: /* illegal */
147 return(MAJOR_0C_EXCP
);
149 fpregs
[t
+3] = fpregs
[r1
+3];
150 fpregs
[t
+2] = fpregs
[r1
+2];
152 fpregs
[t
+1] = fpregs
[r1
+1];
154 fpregs
[t
] = fpregs
[r1
];
159 case 2: /* illegal */
160 return(MAJOR_0C_EXCP
);
162 fpregs
[t
+3] = fpregs
[r1
+3];
163 fpregs
[t
+2] = fpregs
[r1
+2];
165 fpregs
[t
+1] = fpregs
[r1
+1];
167 /* copy and clear sign bit */
168 fpregs
[t
] = fpregs
[r1
] & 0x7fffffff;
174 return(sgl_fsqrt(&fpregs
[r1
],
177 return(dbl_fsqrt(&fpregs
[r1
],
180 case 3: /* quad not implemented */
181 return(MAJOR_0C_EXCP
);
186 return(sgl_frnd(&fpregs
[r1
],
189 return(dbl_frnd(&fpregs
[r1
],
192 case 3: /* quad not implemented */
193 return(MAJOR_0C_EXCP
);
195 } /* end of switch (subop) */
197 case 1: /* class 1 */
198 df
= extru(ir
,fpdfpos
,2); /* get dest format */
199 if ((df
& 2) || (fmt
& 2)) {
201 * fmt's 2 and 3 are illegal of not implemented
204 return(MAJOR_0C_EXCP
);
207 * encode source and dest formats into 2 bits.
208 * high bit is source, low bit is dest.
209 * bit = 1 --> double precision
211 fmt
= (fmt
<< 1) | df
;
215 case 0: /* sgl/sgl */
216 return(MAJOR_0C_EXCP
);
217 case 1: /* sgl/dbl */
218 return(sgl_to_dbl_fcnvff(&fpregs
[r1
],
220 case 2: /* dbl/sgl */
221 return(dbl_to_sgl_fcnvff(&fpregs
[r1
],
223 case 3: /* dbl/dbl */
224 return(MAJOR_0C_EXCP
);
228 case 0: /* sgl/sgl */
229 return(sgl_to_sgl_fcnvxf(&fpregs
[r1
],
231 case 1: /* sgl/dbl */
232 return(sgl_to_dbl_fcnvxf(&fpregs
[r1
],
234 case 2: /* dbl/sgl */
235 return(dbl_to_sgl_fcnvxf(&fpregs
[r1
],
237 case 3: /* dbl/dbl */
238 return(dbl_to_dbl_fcnvxf(&fpregs
[r1
],
243 case 0: /* sgl/sgl */
244 return(sgl_to_sgl_fcnvfx(&fpregs
[r1
],
246 case 1: /* sgl/dbl */
247 return(sgl_to_dbl_fcnvfx(&fpregs
[r1
],
249 case 2: /* dbl/sgl */
250 return(dbl_to_sgl_fcnvfx(&fpregs
[r1
],
252 case 3: /* dbl/dbl */
253 return(dbl_to_dbl_fcnvfx(&fpregs
[r1
],
256 case 3: /* FCNVFXT */
258 case 0: /* sgl/sgl */
259 return(sgl_to_sgl_fcnvfxt(&fpregs
[r1
],
261 case 1: /* sgl/dbl */
262 return(sgl_to_dbl_fcnvfxt(&fpregs
[r1
],
264 case 2: /* dbl/sgl */
265 return(dbl_to_sgl_fcnvfxt(&fpregs
[r1
],
267 case 3: /* dbl/dbl */
268 return(dbl_to_dbl_fcnvfxt(&fpregs
[r1
],
271 } /* end of switch subop */
273 case 2: /* class 2 */
274 r2
= extru(ir
, fpr2pos
, 5) * sizeof(double)/sizeof(unsigned);
284 return(MAJOR_0C_EXCP
);
288 return(sgl_fcmp(&fpregs
[r1
],&fpregs
[r2
],
289 extru(ir
,fptpos
,5),status
));
291 return(dbl_fcmp(&fpregs
[r1
],&fpregs
[r2
],
292 extru(ir
,fptpos
,5),status
));
293 case 2: /* illegal */
294 case 3: /* quad not implemented */
295 return(MAJOR_0C_EXCP
);
302 * second param is the t field used for
303 * ftest,acc and ftest,rej
305 /* XXX fredette - broken */
307 return(ftest(0,extru(ir
,fptpos
,5),
315 return(MAJOR_0C_EXCP
);
317 } /* end if switch for class 2*/
318 case 3: /* class 3 */
319 r2
= extru(ir
,fpr2pos
,5) * sizeof(double)/sizeof(unsigned);
326 return(MAJOR_0C_EXCP
);
331 return(sgl_fadd(&fpregs
[r1
],&fpregs
[r2
],
334 return(dbl_fadd(&fpregs
[r1
],&fpregs
[r2
],
336 case 2: /* illegal */
337 case 3: /* quad not implemented */
338 return(MAJOR_0C_EXCP
);
343 return(sgl_fsub(&fpregs
[r1
],&fpregs
[r2
],
346 return(dbl_fsub(&fpregs
[r1
],&fpregs
[r2
],
348 case 2: /* illegal */
349 case 3: /* quad not implemented */
350 return(MAJOR_0C_EXCP
);
355 return(sgl_fmpy(&fpregs
[r1
],&fpregs
[r2
],
358 return(dbl_fmpy(&fpregs
[r1
],&fpregs
[r2
],
360 case 2: /* illegal */
361 case 3: /* quad not implemented */
362 return(MAJOR_0C_EXCP
);
367 return(sgl_fdiv(&fpregs
[r1
],&fpregs
[r2
],
370 return(dbl_fdiv(&fpregs
[r1
],&fpregs
[r2
],
372 case 2: /* illegal */
373 case 3: /* quad not implemented */
374 return(MAJOR_0C_EXCP
);
379 return(sgl_frem(&fpregs
[r1
],&fpregs
[r2
],
382 return(dbl_frem(&fpregs
[r1
],&fpregs
[r2
],
384 case 2: /* illegal */
385 case 3: /* quad not implemented */
386 return(MAJOR_0C_EXCP
);
388 } /* end of class 3 switch */
389 } /* end of switch(class) */
394 decode_0e(unsigned ir
,unsigned class,unsigned subop
,unsigned fpregs
[])
396 unsigned r1
,r2
,t
; /* operand register offsets */
397 unsigned fmt
; /* also sf for class 1 conversions */
398 unsigned df
; /* dest format for class 1 conversions */
402 r1
= ((extru(ir
,fpr1pos
,5)<<1)|(extru(ir
,fpxr1pos
,1)));
405 t
= ((extru(ir
,fptpos
,5)<<1)|(extru(ir
,fpxtpos
,1)));
406 if (t
== 0 && class != 2)
407 return(MAJOR_0E_EXCP
);
408 if (class < 2) /* class 0 or 1 has 2 bit fmt */
409 fmt
= extru(ir
,fpfmtpos
,2);
410 else /* class 2 and 3 have 1 bit fmt */
411 fmt
= extru(ir
,fp0efmtpos
,1);
416 case 0: /* unimplemented */
420 return(MAJOR_0E_EXCP
);
425 return(MAJOR_0E_EXCP
);
427 fpregs
[t
+1] = fpregs
[r1
+1];
429 fpregs
[t
] = fpregs
[r1
];
436 return(MAJOR_0E_EXCP
);
438 fpregs
[t
+1] = fpregs
[r1
+1];
440 fpregs
[t
] = fpregs
[r1
] & 0x7fffffff;
446 return(sgl_fsqrt(&fpregs
[r1
],
447 &fpregs
[t
], status
));
449 return(dbl_fsqrt(&fpregs
[r1
],
450 &fpregs
[t
], status
));
453 return(MAJOR_0E_EXCP
);
458 return(sgl_frnd(&fpregs
[r1
],
459 &fpregs
[t
], status
));
461 return(dbl_frnd(&fpregs
[r1
],
462 &fpregs
[t
], status
));
465 return(MAJOR_0E_EXCP
);
467 } /* end of switch (subop */
469 case 1: /* class 1 */
470 df
= extru(ir
,fpdfpos
,2); /* get dest format */
471 if ((df
& 2) || (fmt
& 2))
472 return(MAJOR_0E_EXCP
);
474 fmt
= (fmt
<< 1) | df
;
478 case 0: /* sgl/sgl */
479 return(MAJOR_0E_EXCP
);
480 case 1: /* sgl/dbl */
481 return(sgl_to_dbl_fcnvff(&fpregs
[r1
],
483 case 2: /* dbl/sgl */
484 return(dbl_to_sgl_fcnvff(&fpregs
[r1
],
486 case 3: /* dbl/dbl */
487 return(MAJOR_0E_EXCP
);
491 case 0: /* sgl/sgl */
492 return(sgl_to_sgl_fcnvxf(&fpregs
[r1
],
494 case 1: /* sgl/dbl */
495 return(sgl_to_dbl_fcnvxf(&fpregs
[r1
],
497 case 2: /* dbl/sgl */
498 return(dbl_to_sgl_fcnvxf(&fpregs
[r1
],
500 case 3: /* dbl/dbl */
501 return(dbl_to_dbl_fcnvxf(&fpregs
[r1
],
506 case 0: /* sgl/sgl */
507 return(sgl_to_sgl_fcnvfx(&fpregs
[r1
],
509 case 1: /* sgl/dbl */
510 return(sgl_to_dbl_fcnvfx(&fpregs
[r1
],
512 case 2: /* dbl/sgl */
513 return(dbl_to_sgl_fcnvfx(&fpregs
[r1
],
515 case 3: /* dbl/dbl */
516 return(dbl_to_dbl_fcnvfx(&fpregs
[r1
],
519 case 3: /* FCNVFXT */
521 case 0: /* sgl/sgl */
522 return(sgl_to_sgl_fcnvfxt(&fpregs
[r1
],
524 case 1: /* sgl/dbl */
525 return(sgl_to_dbl_fcnvfxt(&fpregs
[r1
],
527 case 2: /* dbl/sgl */
528 return(dbl_to_sgl_fcnvfxt(&fpregs
[r1
],
530 case 3: /* dbl/dbl */
531 return(dbl_to_dbl_fcnvfxt(&fpregs
[r1
],
534 } /* end of switch subop */
535 case 2: /* class 2 */
536 r2
= ((extru(ir
,fpr2pos
,5)<<1)|(extru(ir
,fpxr2pos
,1)));
547 return(MAJOR_0E_EXCP
);
551 * fmt is only 1 bit long
554 return(sgl_fcmp(&fpregs
[r1
],&fpregs
[r2
],
555 extru(ir
,fptpos
,5),status
));
557 return(dbl_fcmp(&fpregs
[r1
],&fpregs
[r2
],
558 extru(ir
,fptpos
,5),status
));
560 } /* end of switch for class 2 */
561 case 3: /* class 3 */
562 r2
= ((extru(ir
,fpr2pos
,5)<<1)|(extru(ir
,fpxr2pos
,1)));
569 return(MAJOR_0E_EXCP
);
572 * Note that fmt is only 1 bit for class 3 */
576 return(sgl_fadd(&fpregs
[r1
],&fpregs
[r2
],
579 return(dbl_fadd(&fpregs
[r1
],&fpregs
[r2
],
585 return(sgl_fsub(&fpregs
[r1
],&fpregs
[r2
],
588 return(dbl_fsub(&fpregs
[r1
],&fpregs
[r2
],
591 case 2: /* FMPY or XMPYU */
593 * check for integer multiply (x bit set)
595 if (extru(ir
,fpxpos
,1)) {
602 * bad instruction if t specifies
603 * the right half of a register
606 return(MAJOR_0E_EXCP
);
607 /* XXX fredette - broken. */
609 impyu(&fpregs
[r1
],&fpregs
[r2
],
616 return(MAJOR_0E_EXCP
);
622 return(sgl_fmpy(&fpregs
[r1
],
623 &fpregs
[r2
],&fpregs
[t
],status
));
625 return(dbl_fmpy(&fpregs
[r1
],
626 &fpregs
[r2
],&fpregs
[t
],status
));
632 return(sgl_fdiv(&fpregs
[r1
],&fpregs
[r2
],
635 return(dbl_fdiv(&fpregs
[r1
],&fpregs
[r2
],
641 return(sgl_frem(&fpregs
[r1
],&fpregs
[r2
],
644 return(dbl_frem(&fpregs
[r1
],&fpregs
[r2
],
647 } /* end of class 3 switch */
648 } /* end of switch(class) */
654 * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction
657 decode_06(unsigned ir
,unsigned fpregs
[])
659 unsigned rm1
, rm2
, tm
, ra
, ta
; /* operands */
666 struct { unsigned i1
; unsigned i2
; } ints
;
670 status
= fpregs
[0]; /* use a local copy of status reg */
671 fmt
= extru(ir
, fpmultifmt
, 1); /* get sgl/dbl flag */
672 if (fmt
== 0) { /* DBL */
673 rm1
= extru(ir
, fprm1pos
, 5) * sizeof(double)/sizeof(unsigned);
676 rm2
= extru(ir
, fprm2pos
, 5) * sizeof(double)/sizeof(unsigned);
679 tm
= extru(ir
, fptmpos
, 5) * sizeof(double)/sizeof(unsigned);
681 return(MAJOR_06_EXCP
);
682 ra
= extru(ir
, fprapos
, 5) * sizeof(double)/sizeof(unsigned);
683 ta
= extru(ir
, fptapos
, 5) * sizeof(double)/sizeof(unsigned);
685 return(MAJOR_06_EXCP
);
689 /* special case FMPYCFXT */
690 if (dbl_fmpy(&fpregs
[rm1
],&fpregs
[rm2
],(unsigned *) &mtmp
,
693 if (dbl_to_sgl_fcnvfxt(&fpregs
[ta
],(unsigned *) &atmp
,
694 (unsigned *) &atmp
,&status
))
703 if (dbl_fmpy(&fpregs
[rm1
],&fpregs
[rm2
],(unsigned *) &mtmp
,
706 if (dbl_fadd(&fpregs
[ta
], &fpregs
[ra
], (unsigned *) &atmp
,
713 return(MAJOR_06_EXCP
);
716 fpregs
[tm
] = mtmp
.ints
.i1
;
717 fpregs
[tm
+1] = mtmp
.ints
.i2
;
718 fpregs
[ta
] = atmp
.ints
.i1
;
719 fpregs
[ta
+1] = atmp
.ints
.i2
;
726 * calculate offsets for single precision numbers
727 * See table 6-14 in PA-89 architecture for mapping
729 rm1
= (extru(ir
,fprm1pos
,4) | 0x10 ) << 1; /* get offset */
730 rm1
|= extru(ir
,fprm1pos
-4,1); /* add right word offset */
732 rm2
= (extru(ir
,fprm2pos
,4) | 0x10 ) << 1; /* get offset */
733 rm2
|= extru(ir
,fprm2pos
-4,1); /* add right word offset */
735 tm
= (extru(ir
,fptmpos
,4) | 0x10 ) << 1; /* get offset */
736 tm
|= extru(ir
,fptmpos
-4,1); /* add right word offset */
738 ra
= (extru(ir
,fprapos
,4) | 0x10 ) << 1; /* get offset */
739 ra
|= extru(ir
,fprapos
-4,1); /* add right word offset */
741 ta
= (extru(ir
,fptapos
,4) | 0x10 ) << 1; /* get offset */
742 ta
|= extru(ir
,fptapos
-4,1); /* add right word offset */
744 if (ra
== 0x20) { /* special case FMPYCFXT (really 0) */
745 if (sgl_fmpy(&fpregs
[rm1
],&fpregs
[rm2
],(unsigned *) &mtmp
,
748 /* XXX fredette - this is broken */
750 if (sgl_to_sgl_fcnvfxt(&fpregs
[ta
],(unsigned *) &atmp
,
751 (unsigned *) &atmp
,&status
))
758 if (sgl_fmpy(&fpregs
[rm1
],&fpregs
[rm2
],(unsigned *) &mtmp
,
761 if (sgl_fadd(&fpregs
[ta
], &fpregs
[ra
], (unsigned *) &atmp
,
766 return(MAJOR_06_EXCP
);
769 fpregs
[tm
] = mtmp
.ints
.i1
;
770 fpregs
[ta
] = atmp
.ints
.i1
;
778 * routine to decode the 26 (FMPYSUB) instruction
781 decode_26(unsigned ir
,unsigned fpregs
[])
783 unsigned rm1
, rm2
, tm
, ra
, ta
; /* operands */
790 struct { unsigned i1
; unsigned i2
; } ints
;
795 fmt
= extru(ir
, fpmultifmt
, 1); /* get sgl/dbl flag */
796 if (fmt
== 0) { /* DBL */
797 rm1
= extru(ir
, fprm1pos
, 5) * sizeof(double)/sizeof(unsigned);
800 rm2
= extru(ir
, fprm2pos
, 5) * sizeof(double)/sizeof(unsigned);
803 tm
= extru(ir
, fptmpos
, 5) * sizeof(double)/sizeof(unsigned);
805 return(MAJOR_26_EXCP
);
806 ra
= extru(ir
, fprapos
, 5) * sizeof(double)/sizeof(unsigned);
808 return(MAJOR_26_EXCP
);
809 ta
= extru(ir
, fptapos
, 5) * sizeof(double)/sizeof(unsigned);
811 return(MAJOR_26_EXCP
);
813 if (dbl_fmpy(&fpregs
[rm1
],&fpregs
[rm2
],(unsigned *) &mtmp
,
816 if (dbl_fsub(&fpregs
[ta
], &fpregs
[ra
], (unsigned *) &atmp
,
820 return(MAJOR_26_EXCP
);
823 fpregs
[tm
] = mtmp
.ints
.i1
;
824 fpregs
[tm
+1] = mtmp
.ints
.i2
;
825 fpregs
[ta
] = atmp
.ints
.i1
;
826 fpregs
[ta
+1] = atmp
.ints
.i2
;
833 * calculate offsets for single precision numbers
834 * See table 6-14 in PA-89 architecture for mapping
836 rm1
= (extru(ir
,fprm1pos
,4) | 0x10 ) << 1; /* get offset */
837 rm1
|= extru(ir
,fprm1pos
-4,1); /* add right word offset */
839 rm2
= (extru(ir
,fprm2pos
,4) | 0x10 ) << 1; /* get offset */
840 rm2
|= extru(ir
,fprm2pos
-4,1); /* add right word offset */
842 tm
= (extru(ir
,fptmpos
,4) | 0x10 ) << 1; /* get offset */
843 tm
|= extru(ir
,fptmpos
-4,1); /* add right word offset */
845 ra
= (extru(ir
,fprapos
,4) | 0x10 ) << 1; /* get offset */
846 ra
|= extru(ir
,fprapos
-4,1); /* add right word offset */
848 ta
= (extru(ir
,fptapos
,4) | 0x10 ) << 1; /* get offset */
849 ta
|= extru(ir
,fptapos
-4,1); /* add right word offset */
851 if (sgl_fmpy(&fpregs
[rm1
],&fpregs
[rm2
],(unsigned *) &mtmp
,
854 if (sgl_fsub(&fpregs
[ta
], &fpregs
[ra
], (unsigned *) &atmp
,
858 return(MAJOR_26_EXCP
);
861 fpregs
[tm
] = mtmp
.ints
.i1
;
862 fpregs
[ta
] = atmp
.ints
.i1
;