1/*	$NetBSD: fpudispatch.c,v 1.3 2005/12/11 12:17:40 christos Exp $	 */
2
3/*
4 *  (c) Copyright 1991 HEWLETT-PACKARD COMPANY
5 *
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.
16 */
17
18/* Source: /n/schirf/u/baford/CVS/mach4-parisc/kernel/parisc/fpudispatch.c,v
19 * Revision: 1.4 	Author: mike
20 * State: Exp    	Locker:
21 * Date: 1994/07/21 17:36:35
22 */
23
24#include <sys/cdefs.h>
25__KERNEL_RCSID(0, "$NetBSD: fpudispatch.c,v 1.3 2005/12/11 12:17:40 christos Exp $");
26
27#include <sys/types.h>
28#include <sys/systm.h>
29
30#include "../spmath/float.h"
31/*
32 * XXX fredette - hack to glue the bulk of
33 * the spmath library to this dispatcher.
34 */
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"
43
44/*
45 * version of EMULATION software for COPR,0,0 instruction
46 */
47#define EMULATION_VERSION 3
48#define COPR_INST 0x30000000
49
50/*
51 * definition of extru macro.  If pos and len are constants, the compiler
52 * will generate an extru instruction when optimized
53 */
54#define extru(r,pos,len)	(((r) >> (31-(pos))) & (( 1 << (len)) - 1))
55/* definitions of bit field locations in the instruction */
56#define fpmajorpos 5
57#define fpr1pos	10
58#define fpr2pos 15
59#define fptpos	31
60#define fpsubpos 18
61#define fpclass1subpos 16
62#define fpclasspos 22
63#define fpfmtpos 20
64#define fpdfpos 18
65/*
66 * the following are the extra bits for the 0E major op
67 */
68#define fpxr1pos 24
69#define fpxr2pos 19
70#define fpxtpos 25
71#define fpxpos 23
72#define fp0efmtpos 20
73/*
74 * the following are for the multi-ops
75 */
76#define fprm1pos 10
77#define fprm2pos 15
78#define fptmpos 31
79#define fprapos 25
80#define fptapos 20
81#define fpmultifmt 26
82
83/*
84 * offset to constant zero in the FP emulation registers
85 */
86#define fpzeroreg (32*sizeof(double)/sizeof(unsigned))
87
88/*
89 * extract the major opcode from the instruction
90 */
91#define get_major(op) extru(op,fpmajorpos,6)
92/*
93 * extract the two bit class field from the FP instruction. The class is at bit
94 * positions 21-22
95 */
96#define get_class(op) extru(op,fpclasspos,2)
97/*
98 * extract the 3 bit subop field.  For all but class 1 instructions, it is
99 * located at bit positions 16-18
100 */
101#define get_subop(op) extru(op,fpsubpos,3)
102/*
103 * extract the 2 bit subop field from class 1 instructions.  It is located
104 * at bit positions 15-16
105 */
106#define get_subop1(op) extru(op,fpclass1subpos,2)
107
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
114
115int
116decode_0c(unsigned ir,unsigned class,unsigned subop,unsigned fpregs[])
117{
118	unsigned r1,r2,t;	/* operand register offsets */
119	unsigned fmt;		/* also sf for class 1 conversions */
120	unsigned  df;		/* for class 1 conversions */
121	unsigned *status;
122
123	if (ir == COPR_INST) {
124		fpregs[0] = EMULATION_VERSION << 11;
125		return(NOEXCEPTION);
126	}
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 */
130		r1 = fpzeroreg;
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 */
135
136	switch (class) {
137	    case 0:
138		switch (subop) {
139			case 0:	/* COPR 0,0 emulated above*/
140			case 1:
141			case 6:
142			case 7:
143				return(MAJOR_0C_EXCP);
144			case 2:	/* FCPY */
145				switch (fmt) {
146				    case 2: /* illegal */
147					return(MAJOR_0C_EXCP);
148				    case 3: /* quad */
149					fpregs[t+3] = fpregs[r1+3];
150					fpregs[t+2] = fpregs[r1+2];
151				    case 1: /* double */
152					fpregs[t+1] = fpregs[r1+1];
153				    case 0: /* single */
154					fpregs[t] = fpregs[r1];
155					return(NOEXCEPTION);
156				}
157			case 3: /* FABS */
158				switch (fmt) {
159				    case 2: /* illegal */
160					return(MAJOR_0C_EXCP);
161				    case 3: /* quad */
162					fpregs[t+3] = fpregs[r1+3];
163					fpregs[t+2] = fpregs[r1+2];
164				    case 1: /* double */
165					fpregs[t+1] = fpregs[r1+1];
166				    case 0: /* single */
167					/* copy and clear sign bit */
168					fpregs[t] = fpregs[r1] & 0x7fffffff;
169					return(NOEXCEPTION);
170				}
171			case 4: /* FSQRT */
172				switch (fmt) {
173				    case 0:
174					return(sgl_fsqrt(&fpregs[r1],
175						&fpregs[t],status));
176				    case 1:
177					return(dbl_fsqrt(&fpregs[r1],
178						&fpregs[t],status));
179				    case 2:
180				    case 3: /* quad not implemented */
181					return(MAJOR_0C_EXCP);
182				}
183			case 5: /* FRND */
184				switch (fmt) {
185				    case 0:
186					return(sgl_frnd(&fpregs[r1],
187						&fpregs[t],status));
188				    case 1:
189					return(dbl_frnd(&fpregs[r1],
190						&fpregs[t],status));
191				    case 2:
192				    case 3: /* quad not implemented */
193					return(MAJOR_0C_EXCP);
194				}
195		} /* end of switch (subop) */
196
197	case 1: /* class 1 */
198		df = extru(ir,fpdfpos,2); /* get dest format */
199		if ((df & 2) || (fmt & 2)) {
200			/*
201			 * fmt's 2 and 3 are illegal of not implemented
202			 * quad conversions
203			 */
204			return(MAJOR_0C_EXCP);
205		}
206		/*
207		 * encode source and dest formats into 2 bits.
208		 * high bit is source, low bit is dest.
209		 * bit = 1 --> double precision
210		 */
211		fmt = (fmt << 1) | df;
212		switch (subop) {
213			case 0: /* FCNVFF */
214				switch(fmt) {
215				    case 0: /* sgl/sgl */
216					return(MAJOR_0C_EXCP);
217				    case 1: /* sgl/dbl */
218					return(sgl_to_dbl_fcnvff(&fpregs[r1],
219						&fpregs[t],status));
220				    case 2: /* dbl/sgl */
221					return(dbl_to_sgl_fcnvff(&fpregs[r1],
222						&fpregs[t],status));
223				    case 3: /* dbl/dbl */
224					return(MAJOR_0C_EXCP);
225				}
226			case 1: /* FCNVXF */
227				switch(fmt) {
228				    case 0: /* sgl/sgl */
229					return(sgl_to_sgl_fcnvxf(&fpregs[r1],
230						&fpregs[t],status));
231				    case 1: /* sgl/dbl */
232					return(sgl_to_dbl_fcnvxf(&fpregs[r1],
233						&fpregs[t],status));
234				    case 2: /* dbl/sgl */
235					return(dbl_to_sgl_fcnvxf(&fpregs[r1],
236						&fpregs[t],status));
237				    case 3: /* dbl/dbl */
238					return(dbl_to_dbl_fcnvxf(&fpregs[r1],
239						&fpregs[t],status));
240				}
241			case 2: /* FCNVFX */
242				switch(fmt) {
243				    case 0: /* sgl/sgl */
244					return(sgl_to_sgl_fcnvfx(&fpregs[r1],
245						&fpregs[t],status));
246				    case 1: /* sgl/dbl */
247					return(sgl_to_dbl_fcnvfx(&fpregs[r1],
248						&fpregs[t],status));
249				    case 2: /* dbl/sgl */
250					return(dbl_to_sgl_fcnvfx(&fpregs[r1],
251						&fpregs[t],status));
252				    case 3: /* dbl/dbl */
253					return(dbl_to_dbl_fcnvfx(&fpregs[r1],
254						&fpregs[t],status));
255				}
256			case 3: /* FCNVFXT */
257				switch(fmt) {
258				    case 0: /* sgl/sgl */
259					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],
260						&fpregs[t],status));
261				    case 1: /* sgl/dbl */
262					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],
263						&fpregs[t],status));
264				    case 2: /* dbl/sgl */
265					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],
266						&fpregs[t],status));
267				    case 3: /* dbl/dbl */
268					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],
269						&fpregs[t],status));
270				}
271		} /* end of switch subop */
272
273	case 2: /* class 2 */
274		r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(unsigned);
275		if (r2 == 0)
276			r2 = fpzeroreg;
277		switch (subop) {
278			case 2:
279			case 3:
280			case 4:
281			case 5:
282			case 6:
283			case 7:
284				return(MAJOR_0C_EXCP);
285			case 0: /* FCMP */
286				switch (fmt) {
287				    case 0:
288					return(sgl_fcmp(&fpregs[r1],&fpregs[r2],
289						extru(ir,fptpos,5),status));
290				    case 1:
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);
296				}
297			case 1: /* FTEST */
298				switch (fmt) {
299				    case 0:
300					/*
301					 * arg0 is not used
302					 * second param is the t field used for
303					 * ftest,acc and ftest,rej
304					 */
305					/* XXX fredette - broken */
306#if 0
307					return(ftest(0,extru(ir,fptpos,5),
308						&fpregs[0]));
309#else
310					panic("ftest");
311#endif
312				    case 1:
313				    case 2:
314				    case 3:
315					return(MAJOR_0C_EXCP);
316				}
317		} /* end if switch for class 2*/
318	case 3: /* class 3 */
319		r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(unsigned);
320		if (r2 == 0)
321			r2 = fpzeroreg;
322		switch (subop) {
323			case 5:
324			case 6:
325			case 7:
326				return(MAJOR_0C_EXCP);
327
328			case 0: /* FADD */
329				switch (fmt) {
330				    case 0:
331					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
332						&fpregs[t],status));
333				    case 1:
334					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
335						&fpregs[t],status));
336				    case 2: /* illegal */
337				    case 3: /* quad not implemented */
338					return(MAJOR_0C_EXCP);
339				}
340			case 1: /* FSUB */
341				switch (fmt) {
342				    case 0:
343					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
344						&fpregs[t],status));
345				    case 1:
346					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
347						&fpregs[t],status));
348				    case 2: /* illegal */
349				    case 3: /* quad not implemented */
350					return(MAJOR_0C_EXCP);
351				}
352			case 2: /* FMPY */
353				switch (fmt) {
354				    case 0:
355					return(sgl_fmpy(&fpregs[r1],&fpregs[r2],
356						&fpregs[t],status));
357				    case 1:
358					return(dbl_fmpy(&fpregs[r1],&fpregs[r2],
359						&fpregs[t],status));
360				    case 2: /* illegal */
361				    case 3: /* quad not implemented */
362					return(MAJOR_0C_EXCP);
363				}
364			case 3: /* FDIV */
365				switch (fmt) {
366				    case 0:
367					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
368						&fpregs[t],status));
369				    case 1:
370					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
371						&fpregs[t],status));
372				    case 2: /* illegal */
373				    case 3: /* quad not implemented */
374					return(MAJOR_0C_EXCP);
375				}
376			case 4: /* FREM */
377				switch (fmt) {
378				    case 0:
379					return(sgl_frem(&fpregs[r1],&fpregs[r2],
380						&fpregs[t],status));
381				    case 1:
382					return(dbl_frem(&fpregs[r1],&fpregs[r2],
383						&fpregs[t],status));
384				    case 2: /* illegal */
385				    case 3: /* quad not implemented */
386					return(MAJOR_0C_EXCP);
387				}
388		} /* end of class 3 switch */
389	} /* end of switch(class) */
390	panic("decode_0c");
391}
392
393int
394decode_0e(unsigned ir,unsigned class,unsigned subop,unsigned fpregs[])
395{
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 */
399	unsigned *status;
400
401	status = &fpregs[0];
402	r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1)));
403	if (r1 == 0)
404		r1 = fpzeroreg;
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);
412
413	switch (class) {
414	    case 0:
415		switch (subop) {
416			case 0: /* unimplemented */
417			case 1:
418			case 6:
419			case 7:
420				return(MAJOR_0E_EXCP);
421			case 2: /* FCPY */
422				switch (fmt) {
423				    case 2:
424				    case 3:
425					return(MAJOR_0E_EXCP);
426				    case 1: /* double */
427					fpregs[t+1] = fpregs[r1+1];
428				    case 0: /* single */
429					fpregs[t] = fpregs[r1];
430					return(NOEXCEPTION);
431				}
432			case 3: /* FABS */
433				switch (fmt) {
434				    case 2:
435				    case 3:
436					return(MAJOR_0E_EXCP);
437				    case 1: /* double */
438					fpregs[t+1] = fpregs[r1+1];
439				    case 0: /* single */
440					fpregs[t] = fpregs[r1] & 0x7fffffff;
441					return(NOEXCEPTION);
442				}
443			case 4: /* FSQRT */
444				switch (fmt) {
445				    case 0:
446					return(sgl_fsqrt(&fpregs[r1],
447						&fpregs[t], status));
448				    case 1:
449					return(dbl_fsqrt(&fpregs[r1],
450						&fpregs[t], status));
451				    case 2:
452				    case 3:
453					return(MAJOR_0E_EXCP);
454				}
455			case 5: /* FRMD */
456				switch (fmt) {
457				    case 0:
458					return(sgl_frnd(&fpregs[r1],
459						&fpregs[t], status));
460				    case 1:
461					return(dbl_frnd(&fpregs[r1],
462						&fpregs[t], status));
463				    case 2:
464				    case 3:
465					return(MAJOR_0E_EXCP);
466				}
467		} /* end of switch (subop */
468
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);
473
474		fmt = (fmt << 1) | df;
475		switch (subop) {
476			case 0: /* FCNVFF */
477				switch(fmt) {
478				    case 0: /* sgl/sgl */
479					return(MAJOR_0E_EXCP);
480				    case 1: /* sgl/dbl */
481					return(sgl_to_dbl_fcnvff(&fpregs[r1],
482						&fpregs[t],status));
483				    case 2: /* dbl/sgl */
484					return(dbl_to_sgl_fcnvff(&fpregs[r1],
485						&fpregs[t],status));
486				    case 3: /* dbl/dbl */
487					return(MAJOR_0E_EXCP);
488				}
489			case 1: /* FCNVXF */
490				switch(fmt) {
491				    case 0: /* sgl/sgl */
492					return(sgl_to_sgl_fcnvxf(&fpregs[r1],
493						&fpregs[t],status));
494				    case 1: /* sgl/dbl */
495					return(sgl_to_dbl_fcnvxf(&fpregs[r1],
496						&fpregs[t],status));
497				    case 2: /* dbl/sgl */
498					return(dbl_to_sgl_fcnvxf(&fpregs[r1],
499						&fpregs[t],status));
500				    case 3: /* dbl/dbl */
501					return(dbl_to_dbl_fcnvxf(&fpregs[r1],
502						&fpregs[t],status));
503				}
504			case 2: /* FCNVFX */
505				switch(fmt) {
506				    case 0: /* sgl/sgl */
507					return(sgl_to_sgl_fcnvfx(&fpregs[r1],
508						&fpregs[t],status));
509				    case 1: /* sgl/dbl */
510					return(sgl_to_dbl_fcnvfx(&fpregs[r1],
511						&fpregs[t],status));
512				    case 2: /* dbl/sgl */
513					return(dbl_to_sgl_fcnvfx(&fpregs[r1],
514						&fpregs[t],status));
515				    case 3: /* dbl/dbl */
516					return(dbl_to_dbl_fcnvfx(&fpregs[r1],
517						&fpregs[t],status));
518				}
519			case 3: /* FCNVFXT */
520				switch(fmt) {
521				    case 0: /* sgl/sgl */
522					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],
523						&fpregs[t],status));
524				    case 1: /* sgl/dbl */
525					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],
526						&fpregs[t],status));
527				    case 2: /* dbl/sgl */
528					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],
529						&fpregs[t],status));
530				    case 3: /* dbl/dbl */
531					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],
532						&fpregs[t],status));
533				}
534		} /* end of switch subop */
535	case 2: /* class 2 */
536		r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
537		if (r2 == 0)
538			r2 = fpzeroreg;
539		switch (subop) {
540			case 1:
541			case 2:
542			case 3:
543			case 4:
544			case 5:
545			case 6:
546			case 7:
547				return(MAJOR_0E_EXCP);
548			case 0: /* FCMP */
549				switch (fmt) {
550				    /*
551				     * fmt is only 1 bit long
552				     */
553				    case 0:
554					return(sgl_fcmp(&fpregs[r1],&fpregs[r2],
555						extru(ir,fptpos,5),status));
556				    case 1:
557					return(dbl_fcmp(&fpregs[r1],&fpregs[r2],
558						extru(ir,fptpos,5),status));
559				}
560		} /* end of switch for class 2 */
561	case 3: /* class 3 */
562		r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
563		if (r2 == 0)
564			r2 = fpzeroreg;
565		switch (subop) {
566			case 5:
567			case 6:
568			case 7:
569				return(MAJOR_0E_EXCP);
570
571			/*
572			 * Note that fmt is only 1 bit for class 3 */
573			case 0: /* FADD */
574				switch (fmt) {
575				    case 0:
576					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
577						&fpregs[t],status));
578				    case 1:
579					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
580						&fpregs[t],status));
581				}
582			case 1: /* FSUB */
583				switch (fmt) {
584				    case 0:
585					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
586						&fpregs[t],status));
587				    case 1:
588					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
589						&fpregs[t],status));
590				}
591			case 2: /* FMPY or XMPYU */
592				/*
593				 * check for integer multiply (x bit set)
594				 */
595				if (extru(ir,fpxpos,1)) {
596				    /*
597				     * emulate XMPYU
598				     */
599				    switch (fmt) {
600					case 0:
601					    /*
602					     * bad instruction if t specifies
603					     * the right half of a register
604					     */
605					    if (t & 1)
606						return(MAJOR_0E_EXCP);
607					    /* XXX fredette - broken. */
608#if 0
609					    impyu(&fpregs[r1],&fpregs[r2],
610						&fpregs[t]);
611					    return(NOEXCEPTION);
612#else
613					    panic("impyu");
614#endif
615					case 1:
616						return(MAJOR_0E_EXCP);
617				    }
618				}
619				else { /* FMPY */
620				    switch (fmt) {
621				        case 0:
622					    return(sgl_fmpy(&fpregs[r1],
623					       &fpregs[r2],&fpregs[t],status));
624				        case 1:
625					    return(dbl_fmpy(&fpregs[r1],
626					       &fpregs[r2],&fpregs[t],status));
627				    }
628				}
629			case 3: /* FDIV */
630				switch (fmt) {
631				    case 0:
632					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
633						&fpregs[t],status));
634				    case 1:
635					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
636						&fpregs[t],status));
637				}
638			case 4: /* FREM */
639				switch (fmt) {
640				    case 0:
641					return(sgl_frem(&fpregs[r1],&fpregs[r2],
642						&fpregs[t],status));
643				    case 1:
644					return(dbl_frem(&fpregs[r1],&fpregs[r2],
645						&fpregs[t],status));
646				}
647		} /* end of class 3 switch */
648	} /* end of switch(class) */
649	panic("decode_0e");
650}
651
652
653/*
654 * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction
655 */
656int
657decode_06(unsigned ir,unsigned fpregs[])
658{
659	unsigned rm1, rm2, tm, ra, ta; /* operands */
660	unsigned fmt;
661	unsigned error = 0;
662	unsigned status;
663	union {
664		double dbl;
665		float flt;
666		struct { unsigned i1; unsigned i2; } ints;
667	} mtmp, atmp;
668
669
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);
674		if (rm1 == 0)
675			rm1 = fpzeroreg;
676		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(unsigned);
677		if (rm2 == 0)
678			rm2 = fpzeroreg;
679		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(unsigned);
680		if (tm == 0)
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);
684		if (ta == 0)
685			return(MAJOR_06_EXCP);
686
687#ifdef TIMEX
688		if (ra == 0) {
689			 /* special case FMPYCFXT */
690			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
691					&status))
692				error = 1;
693			if (dbl_to_sgl_fcnvfxt(&fpregs[ta],(unsigned *) &atmp,
694				(unsigned *) &atmp,&status))
695				error = 1;
696		}
697		else {
698#else
699		if (ra == 0)
700			ra = fpzeroreg;
701#endif
702
703			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
704					&status))
705				error = 1;
706			if (dbl_fadd(&fpregs[ta], &fpregs[ra], (unsigned *) &atmp,
707					&status))
708				error = 1;
709#ifdef TIMEX
710		}
711#endif
712		if (error)
713			return(MAJOR_06_EXCP);
714		else {
715			/* copy results */
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;
720			fpregs[0] = status;
721			return(NOEXCEPTION);
722		}
723	}
724	else { /* SGL */
725		/*
726		 * calculate offsets for single precision numbers
727		 * See table 6-14 in PA-89 architecture for mapping
728		 */
729		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
730		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
731
732		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
733		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
734
735		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
736		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
737
738		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
739		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
740
741		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
742		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
743
744		if (ra == 0x20) { /* special case FMPYCFXT (really 0) */
745			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
746					&status))
747				error = 1;
748			/* XXX fredette - this is broken */
749#if 0
750			if (sgl_to_sgl_fcnvfxt(&fpregs[ta],(unsigned *) &atmp,
751				(unsigned *) &atmp,&status))
752				error = 1;
753#else
754				panic("FMPYADD");
755#endif
756		}
757		else {
758			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
759					&status))
760				error = 1;
761			if (sgl_fadd(&fpregs[ta], &fpregs[ra], (unsigned *) &atmp,
762					&status))
763				error = 1;
764		}
765		if (error)
766			return(MAJOR_06_EXCP);
767		else {
768			/* copy results */
769			fpregs[tm] = mtmp.ints.i1;
770			fpregs[ta] = atmp.ints.i1;
771			fpregs[0] = status;
772			return(NOEXCEPTION);
773		}
774	}
775}
776
777/*
778 * routine to decode the 26 (FMPYSUB) instruction
779 */
780int
781decode_26(unsigned ir,unsigned fpregs[])
782{
783	unsigned rm1, rm2, tm, ra, ta; /* operands */
784	unsigned fmt;
785	unsigned error = 0;
786	unsigned status;
787	union {
788		double dbl;
789		float flt;
790		struct { unsigned i1; unsigned i2; } ints;
791	} mtmp, atmp;
792
793
794	status = fpregs[0];
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);
798		if (rm1 == 0)
799			rm1 = fpzeroreg;
800		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(unsigned);
801		if (rm2 == 0)
802			rm2 = fpzeroreg;
803		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(unsigned);
804		if (tm == 0)
805			return(MAJOR_26_EXCP);
806		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(unsigned);
807		if (ra == 0)
808			return(MAJOR_26_EXCP);
809		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(unsigned);
810		if (ta == 0)
811			return(MAJOR_26_EXCP);
812
813		if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
814				&status))
815			error = 1;
816		if (dbl_fsub(&fpregs[ta], &fpregs[ra], (unsigned *) &atmp,
817				&status))
818			error = 1;
819		if (error)
820			return(MAJOR_26_EXCP);
821		else {
822			/* copy results */
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;
827			fpregs[0] = status;
828			return(NOEXCEPTION);
829		}
830	}
831	else { /* SGL */
832		/*
833		 * calculate offsets for single precision numbers
834		 * See table 6-14 in PA-89 architecture for mapping
835		 */
836		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
837		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
838
839		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
840		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
841
842		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
843		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
844
845		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
846		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
847
848		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
849		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
850
851		if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
852				&status))
853			error = 1;
854		if (sgl_fsub(&fpregs[ta], &fpregs[ra], (unsigned *) &atmp,
855				&status))
856			error = 1;
857		if (error)
858			return(MAJOR_26_EXCP);
859		else {
860			/* copy results */
861			fpregs[tm] = mtmp.ints.i1;
862			fpregs[ta] = atmp.ints.i1;
863			fpregs[0] = status;
864			return(NOEXCEPTION);
865		}
866	}
867
868}
869