--- /dev/null
+* $NetBSD: README,v 1.4 1995/11/05 04:23:00 briggs Exp $
+* NetBSD/m68k FPE (floating point emulation) README file
+* Created Oct/??/95 by kenn@remus.rutgers.edu (Ken Nakata)
+* Last updated Nov/04/95 by kenn
+
+1. INSTALLATION AND COMPILATION
+
+To compile a kernel with FPE built-in, do the following:
+
+1) Add a line "options FPU_EMULATE" to your config file. If you are
+going to use the resulted kernel on a machine with an FPU for
+debugging purpose, add "options DEBUG_WITH_FPU" as well.
+
+2) Follow the usual procedure to build a new kernel.
+
+NOTE: If you add "options DEBUG_WITH_FPU", FPE will accept cpID=6 as
+emulated FPU. You will need a modified gas that generates cpID=6 for
+floating point instructions, instead of normal cpID=1. Mount unionfs
+or copy the gas source directory and apply the following patch:
+
+*** /usr/src/gnu/usr.bin/gas/config/tc-m68k.c Mon Nov 21 16:30:41 1994
+--- gas/config/tc-m68k.c Fri Sep 29 07:59:06 1995
+***************
+*** 1275,1281 ****
+ /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */
+ memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0]));
+ the_ins.operands[0].mode=MSCR;
+! the_ins.operands[0].reg=COPNUM; /* COP #1 */
+ opsfound++;
+ }
+
+--- 1275,1281 ----
+ /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */
+ memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0]));
+ the_ins.operands[0].mode=MSCR;
+! the_ins.operands[0].reg=COP5; /* COP #6 */
+ opsfound++;
+ }
+
+
+Also, with the DEBUG_WITH_FPU option, you will be able to run only ONE
+process that uses FPE at once to get correct results.
+
+
+2. MISSING PARTS
+
+For missing instructions, refer to the Section 3. Other than that,
+there is one thing that is missing from this version of FPE: packed
+BCD support.
+
+I have no plan to support it since it's rarely used. However, all we
+need to support it is explosion/implosion functions between the
+internal FP representation and the m68k PBCD format, so you are more
+than welcome to write such functions if you wish to.
+
+
+3. IMPLEMENTED INSTRUCTIONS
+
+This is the list of implemented and unimplemented FPU instructions.
+All 040's directly supported type 0 instructions are already
+implemented except FSGLDIV and FSGLMUL.
+
+Type field = bit 8-6 of opcode word
+
+* Implemented Instructions
+
+Type=0: FMOVE (mem->FPr), FINT, FINTRZ, FSQRT, FABS, FNEG, FGETEXP,
+ FGETMAN, FDIV, FADD, FMUL, FSGLDIV(*), FSCALE, FSGLMUL(*), FSUB,
+ FCMP, FTST, FMOVE (FPr->mem), FMOVEM (FPr), FMOVEM (FPcr),
+ FMOVECR, FLOGNP1, FLOGN, FLOG10, FLOG2, FMOD, FREM
+
+Type=1: FDBcc, FScc, FTRAPcc,
+
+Type=2: FBcc (word, incl. FNOP)
+
+Type=3: FBcc (long)
+
+Type=4: none
+
+Type=5: none
+
+ *: currently FSGLMUL and FSGLDIV are just aliases of
+ FMUL and FDIV, respectively
+
+* Unimplemented Instructions
+
+Type=0: FSINH, FETOXM1, FTANH, FATAN, FASIN, FATANH, FSIN, FTAN,
+ FETOX, FTWOTOX, FTENTOX, FCOSH, FACOS, FCOS, FSINCOS
+
+Type=1: none
+
+Type=2: none
+
+Type=3: none
+
+Type=4: FSAVE
+
+Type=5: FRESTORE
+
+
+4. HOW TO ADD A NEW INSTRUCTION SUPPORT
+
+Since we need not support FSAVE and FRESTORE operations, all
+instructions we have to implement are type 0, all of which are
+arithmetic operations. It is particularly easy to add a new
+arithmetic instruction to the existing ones (not that it is easy to
+write a "stable" function to perform floating point operation. That's
+entirely another matter). In "fpu_emulate.c", there's a function
+fpu_emul_arith() which calls emulation functions for all arithmetic
+operations. In it, there's a large switch() { case ... } which
+dispatches each instruction emulator. An emulation function of any
+type 0 arithmetic instruction follows this prototype:
+
+ struct fpn *fpu_op(struct fpemu *fe);
+
+Where fe is a pointer to a struct fpemu in which frame, fpframe, and
+fetched operands are accessible. That's right, you don't have to
+fetch the operands by yourself in your emulation funtion. For
+instance, the parts calling FSQRT, FSUB, FADD and FTST look like:
+
+ switch(word1 & 0x3F) {
+[...]
+ case 0x04: /* fsqrt */
+ res = fpu_sqrt(fe);
+ break;
+[...]
+ case 0x28: /* fsub */
+ fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
+ case 0x22: /* fadd */
+ res = fpu_add(fe);
+ break;
+[...]
+ case 0x3A: /* ftst */
+ res = &fe->fe_f2;
+ no_store = 1;
+ break;
+[...]
+ default:
+ sig = SIGILL;
+ } /* switch */
+
+Here, fe->fe_f1 and fe->fe_f2 are fetched operands. You can use
+fe->fe_f3 for storing the result, or you can return a pointer to
+either operand if you want to. At any rate, you have to follow
+the following rules:
+
+ 1) A dyadic instruction takes two operands fe->fe_f1 and fe->fe_f2.
+ 2) A monadic instruction takes one operands fe->fe_f2 (NOT fe_f1).
+ 3) Must return a pointer to struct fpn where the result is stored,
+ and assign the pointer to the variable "res".
+ 4) If exceptions are detected, set corresponding bits in fe->fe_fpsr.
+ The rest is taken care of in fpu_emul_arith().
+ 5) Condition code need not be calculated. It's taken care of in
+ fpu_emul_arith().
+
+Actually, after above was written, stubs for the missing functions were
+added to the source, so you do not have to change fpu_emul_arith() at
+all. Function names and prototypes are in fpu_arith_proto.h, and all
+except fpu_sincos() follow the rules above. fpu_sincos() is declared
+as
+
+ struct fpn *fpu_sincos(struct fpemu *fe, int cosreg);
+
+where cosreg is the FP register number to which cosine of the argument
+is calculated and assigned. Sine of the argument is stored into the
+destination register in the same manner as the other arithmetic
+functions.
--- /dev/null
+# $NetBSD: files.fpe,v 1.2 1995/11/03 04:51:51 briggs Exp $
+
+# Config(.new) file for m68k floating point emulator.
+# Included by ports that need it.
+
+file arch/m68k/fpe/fpu_add.c fpu_emulate
+file arch/m68k/fpe/fpu_calcea.c fpu_emulate
+file arch/m68k/fpe/fpu_div.c fpu_emulate
+file arch/m68k/fpe/fpu_emulate.c fpu_emulate
+file arch/m68k/fpe/fpu_exp.c fpu_emulate
+file arch/m68k/fpe/fpu_explode.c fpu_emulate
+file arch/m68k/fpe/fpu_fmovecr.c fpu_emulate
+file arch/m68k/fpe/fpu_fscale.c fpu_emulate
+file arch/m68k/fpe/fpu_fstore.c fpu_emulate
+file arch/m68k/fpe/fpu_getexp.c fpu_emulate
+file arch/m68k/fpe/fpu_hyperb.c fpu_emulate
+file arch/m68k/fpe/fpu_implode.c fpu_emulate
+file arch/m68k/fpe/fpu_int.c fpu_emulate
+file arch/m68k/fpe/fpu_log.c fpu_emulate
+file arch/m68k/fpe/fpu_mul.c fpu_emulate
+file arch/m68k/fpe/fpu_rem.c fpu_emulate
+file arch/m68k/fpe/fpu_sqrt.c fpu_emulate
+file arch/m68k/fpe/fpu_subr.c fpu_emulate
+file arch/m68k/fpe/fpu_trig.c fpu_emulate
--- /dev/null
+/* $NetBSD: fpu_add.c,v 1.1 1995/11/03 04:46:58 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_add.c 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Perform an FPU add (return x + y).
+ *
+ * To subtract, negate y and call add.
+ */
+
+#include <sys/types.h>
+
+#include <machine/reg.h>
+
+#include "fpu_arith.h"
+#include "fpu_emulate.h"
+
+struct fpn *
+fpu_add(fe)
+ register struct fpemu *fe;
+{
+ register struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2, *r;
+ register u_int r0, r1, r2, r3;
+ register int rd;
+
+ /*
+ * Put the `heavier' operand on the right (see fpu_emu.h).
+ * Then we will have one of the following cases, taken in the
+ * following order:
+ *
+ * - y = NaN. Implied: if only one is a signalling NaN, y is.
+ * The result is y.
+ * - y = Inf. Implied: x != NaN (is 0, number, or Inf: the NaN
+ * case was taken care of earlier).
+ * If x = -y, the result is NaN. Otherwise the result
+ * is y (an Inf of whichever sign).
+ * - y is 0. Implied: x = 0.
+ * If x and y differ in sign (one positive, one negative),
+ * the result is +0 except when rounding to -Inf. If same:
+ * +0 + +0 = +0; -0 + -0 = -0.
+ * - x is 0. Implied: y != 0.
+ * Result is y.
+ * - other. Implied: both x and y are numbers.
+ * Do addition a la Hennessey & Patterson.
+ */
+ ORDER(x, y);
+ if (ISNAN(y))
+ return (y);
+ if (ISINF(y)) {
+ if (ISINF(x) && x->fp_sign != y->fp_sign)
+ return (fpu_newnan(fe));
+ return (y);
+ }
+ rd = (fe->fe_fpcr & FPCR_ROUND);
+ if (ISZERO(y)) {
+ if (rd != FPCR_MINF) /* only -0 + -0 gives -0 */
+ y->fp_sign &= x->fp_sign;
+ else /* any -0 operand gives -0 */
+ y->fp_sign |= x->fp_sign;
+ return (y);
+ }
+ if (ISZERO(x))
+ return (y);
+ /*
+ * We really have two numbers to add, although their signs may
+ * differ. Make the exponents match, by shifting the smaller
+ * number right (e.g., 1.011 => 0.1011) and increasing its
+ * exponent (2^3 => 2^4). Note that we do not alter the exponents
+ * of x and y here.
+ */
+ r = &fe->fe_f3;
+ r->fp_class = FPC_NUM;
+ if (x->fp_exp == y->fp_exp) {
+ r->fp_exp = x->fp_exp;
+ r->fp_sticky = 0;
+ } else {
+ if (x->fp_exp < y->fp_exp) {
+ /*
+ * Try to avoid subtract case iii (see below).
+ * This also guarantees that x->fp_sticky = 0.
+ */
+ SWAP(x, y);
+ }
+ /* now x->fp_exp > y->fp_exp */
+ r->fp_exp = x->fp_exp;
+ r->fp_sticky = fpu_shr(y, x->fp_exp - y->fp_exp);
+ }
+ r->fp_sign = x->fp_sign;
+ if (x->fp_sign == y->fp_sign) {
+ FPU_DECL_CARRY
+
+ /*
+ * The signs match, so we simply add the numbers. The result
+ * may be `supernormal' (as big as 1.111...1 + 1.111...1, or
+ * 11.111...0). If so, a single bit shift-right will fix it
+ * (but remember to adjust the exponent).
+ */
+ /* r->fp_mant = x->fp_mant + y->fp_mant */
+ FPU_ADDS(r->fp_mant[3], x->fp_mant[3], y->fp_mant[3]);
+ FPU_ADDCS(r->fp_mant[2], x->fp_mant[2], y->fp_mant[2]);
+ FPU_ADDCS(r->fp_mant[1], x->fp_mant[1], y->fp_mant[1]);
+ FPU_ADDC(r0, x->fp_mant[0], y->fp_mant[0]);
+ if ((r->fp_mant[0] = r0) >= FP_2) {
+ (void) fpu_shr(r, 1);
+ r->fp_exp++;
+ }
+ } else {
+ FPU_DECL_CARRY
+
+ /*
+ * The signs differ, so things are rather more difficult.
+ * H&P would have us negate the negative operand and add;
+ * this is the same as subtracting the negative operand.
+ * This is quite a headache. Instead, we will subtract
+ * y from x, regardless of whether y itself is the negative
+ * operand. When this is done one of three conditions will
+ * hold, depending on the magnitudes of x and y:
+ * case i) |x| > |y|. The result is just x - y,
+ * with x's sign, but it may need to be normalized.
+ * case ii) |x| = |y|. The result is 0 (maybe -0)
+ * so must be fixed up.
+ * case iii) |x| < |y|. We goofed; the result should
+ * be (y - x), with the same sign as y.
+ * We could compare |x| and |y| here and avoid case iii,
+ * but that would take just as much work as the subtract.
+ * We can tell case iii has occurred by an overflow.
+ *
+ * N.B.: since x->fp_exp >= y->fp_exp, x->fp_sticky = 0.
+ */
+ /* r->fp_mant = x->fp_mant - y->fp_mant */
+ FPU_SET_CARRY(y->fp_sticky);
+ FPU_SUBCS(r3, x->fp_mant[3], y->fp_mant[3]);
+ FPU_SUBCS(r2, x->fp_mant[2], y->fp_mant[2]);
+ FPU_SUBCS(r1, x->fp_mant[1], y->fp_mant[1]);
+ FPU_SUBC(r0, x->fp_mant[0], y->fp_mant[0]);
+ if (r0 < FP_2) {
+ /* cases i and ii */
+ if ((r0 | r1 | r2 | r3) == 0) {
+ /* case ii */
+ r->fp_class = FPC_ZERO;
+ r->fp_sign = (rd == FPCR_MINF);
+ return (r);
+ }
+ } else {
+ /*
+ * Oops, case iii. This can only occur when the
+ * exponents were equal, in which case neither
+ * x nor y have sticky bits set. Flip the sign
+ * (to y's sign) and negate the result to get y - x.
+ */
+#ifdef DIAGNOSTIC
+ if (x->fp_exp != y->fp_exp || r->fp_sticky)
+ panic("fpu_add");
+#endif
+ r->fp_sign = y->fp_sign;
+ FPU_SUBS(r3, 0, r3);
+ FPU_SUBCS(r2, 0, r2);
+ FPU_SUBCS(r1, 0, r1);
+ FPU_SUBC(r0, 0, r0);
+ }
+ r->fp_mant[3] = r3;
+ r->fp_mant[2] = r2;
+ r->fp_mant[1] = r1;
+ r->fp_mant[0] = r0;
+ if (r0 < FP_1)
+ fpu_norm(r);
+ }
+ return (r);
+}
--- /dev/null
+/* $NetBSD: fpu_arith.h,v 1.1 1995/11/03 04:46:59 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_arith.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Extended-precision arithmetic.
+ *
+ * We hold the notion of a `carry register', which may or may not be a
+ * machine carry bit or register. On the SPARC, it is just the machine's
+ * carry bit.
+ *
+ * In the worst case, you can compute the carry from x+y as
+ * (unsigned)(x + y) < (unsigned)x
+ * and from x+y+c as
+ * ((unsigned)(x + y + c) <= (unsigned)x && (y|c) != 0)
+ * for example.
+ */
+
+#ifdef sparc
+
+/* set up for extended-precision arithemtic */
+#define FPU_DECL_CARRY
+
+/*
+ * We have three kinds of add:
+ * add with carry: r = x + y + c
+ * add (ignoring current carry) and set carry: c'r = x + y + 0
+ * add with carry and set carry: c'r = x + y + c
+ * The macros use `C' for `use carry' and `S' for `set carry'.
+ * Note that the state of the carry is undefined after ADDC and SUBC,
+ * so if all you have for these is `add with carry and set carry',
+ * that is OK.
+ *
+ * The same goes for subtract, except that we compute x - y - c.
+ *
+ * Finally, we have a way to get the carry into a `regular' variable,
+ * or set it from a value. SET_CARRY turns 0 into no-carry, nonzero
+ * into carry; GET_CARRY sets its argument to 0 or 1.
+ */
+#define FPU_ADDC(r, x, y) \
+ asm volatile("addx %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_ADDS(r, x, y) \
+ asm volatile("addcc %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_ADDCS(r, x, y) \
+ asm volatile("addxcc %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_SUBC(r, x, y) \
+ asm volatile("subx %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_SUBS(r, x, y) \
+ asm volatile("subcc %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_SUBCS(r, x, y) \
+ asm volatile("subxcc %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+
+#define FPU_GET_CARRY(r) asm volatile("addx %%g0,%%g0,%0" : "=r"(r))
+#define FPU_SET_CARRY(v) asm volatile("addcc %0,-1,%%g0" : : "r"(v))
+
+#define FPU_SHL1_BY_ADD /* shift left 1 faster by ADDC than (a<<1)|(b>>31) */
+
+#else /* non sparc */
+
+/* set up for extended-precision arithemtic */
+#define FPU_DECL_CARRY quad_t fpu_carry, fpu_tmp;
+
+/*
+ * We have three kinds of add:
+ * add with carry: r = x + y + c
+ * add (ignoring current carry) and set carry: c'r = x + y + 0
+ * add with carry and set carry: c'r = x + y + c
+ * The macros use `C' for `use carry' and `S' for `set carry'.
+ * Note that the state of the carry is undefined after ADDC and SUBC,
+ * so if all you have for these is `add with carry and set carry',
+ * that is OK.
+ *
+ * The same goes for subtract, except that we compute x - y - c.
+ *
+ * Finally, we have a way to get the carry into a `regular' variable,
+ * or set it from a value. SET_CARRY turns 0 into no-carry, nonzero
+ * into carry; GET_CARRY sets its argument to 0 or 1.
+ */
+#define FPU_ADDC(r, x, y) \
+ (r) = (x) + (y) + (!!fpu_carry)
+#define FPU_ADDS(r, x, y) \
+ { \
+ fpu_tmp = (quad_t)(x) + (quad_t)(y); \
+ (r) = (u_int)fpu_tmp; \
+ fpu_carry = ((fpu_tmp & 0xffffffff00000000LL) != 0); \
+ }
+#define FPU_ADDCS(r, x, y) \
+ { \
+ fpu_tmp = (quad_t)(x) + (quad_t)(y) + (!!fpu_carry); \
+ (r) = (u_int)fpu_tmp; \
+ fpu_carry = ((fpu_tmp & 0xffffffff00000000LL) != 0); \
+ }
+#define FPU_SUBC(r, x, y) \
+ (r) = (x) - (y) - (!!fpu_carry)
+#define FPU_SUBS(r, x, y) \
+ { \
+ fpu_tmp = (quad_t)(x) - (quad_t)(y); \
+ (r) = (u_int)fpu_tmp; \
+ fpu_carry = ((fpu_tmp & 0xffffffff00000000LL) != 0); \
+ }
+#define FPU_SUBCS(r, x, y) \
+ { \
+ fpu_tmp = (quad_t)(x) - (quad_t)(y) - (!!fpu_carry); \
+ (r) = (u_int)fpu_tmp; \
+ fpu_carry = ((fpu_tmp & 0xffffffff00000000LL) != 0); \
+ }
+
+#define FPU_GET_CARRY(r) (r) = (!!fpu_carry)
+#define FPU_SET_CARRY(v) fpu_carry = ((v) != 0)
+
+#endif
--- /dev/null
+/* $NetBSD: fpu_arith_proto.h,v 1.1 1995/11/03 04:47:00 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_arith_proto.c 10/24/95
+ */
+
+#ifndef _FPU_ARITH_PROTO_H_
+#define _FPU_ARITH_PROTO_H_
+
+/*
+ * Arithmetic functions - called from fpu_emul_arith().
+ * Each of these may modify its inputs (f1,f2) and/or the temporary.
+ * Each returns a pointer to the result and/or sets exceptions.
+ */
+
+/* fpu_add.c */
+struct fpn * fpu_add __P((struct fpemu *fe));
+
+/* fpu_div.c */
+struct fpn * fpu_div __P((struct fpemu *fe));
+
+/* fpu_exp.c */
+struct fpn * fpu_etox __P((struct fpemu *fe));
+struct fpn * fpu_etoxm1 __P((struct fpemu *fe));
+struct fpn * fpu_tentox __P((struct fpemu *fe));
+struct fpn * fpu_twotox __P((struct fpemu *fe));
+
+/* fpu_getexp.c */
+struct fpn * fpu_getexp __P((struct fpemu *fe));
+struct fpn * fpu_getman __P((struct fpemu *fe));
+
+/* fpu_hyperb.c */
+struct fpn * fpu_atanh __P((struct fpemu *fe));
+struct fpn * fpu_cosh __P((struct fpemu *fe));
+struct fpn * fpu_sinh __P((struct fpemu *fe));
+struct fpn * fpu_tanh __P((struct fpemu *fe));
+
+/* fpu_int.c */
+struct fpn * fpu_intrz __P((struct fpemu *fe));
+struct fpn * fpu_int __P((struct fpemu *fe));
+
+/* fpu_log.c */
+struct fpn * fpu_log10 __P((struct fpemu *fe));
+struct fpn * fpu_log2 __P((struct fpemu *fe));
+struct fpn * fpu_logn __P((struct fpemu *fe));
+struct fpn * fpu_lognp1 __P((struct fpemu *fe));
+
+/* fpu_mulc */
+struct fpn * fpu_mul __P((struct fpemu *fe));
+
+/* fpu_rem.c */
+struct fpn * fpu_rem __P((struct fpemu *fe));
+struct fpn * fpu_mod __P((struct fpemu *fe));
+
+/* fpu_sqrt.c */
+struct fpn * fpu_sqrt __P((struct fpemu *fe));
+
+/* fpu_trig.c */
+struct fpn * fpu_acos __P((struct fpemu *fe));
+struct fpn * fpu_asin __P((struct fpemu *fe));
+struct fpn * fpu_atan __P((struct fpemu *fe));
+struct fpn * fpu_cos __P((struct fpemu *fe));
+struct fpn * fpu_sin __P((struct fpemu *fe));
+struct fpn * fpu_tan __P((struct fpemu *fe));
+struct fpn * fpu_sincos __P((struct fpemu *fe, int regc));
+
+#endif /* _FPU_ARITH_PROTO_H_ */
--- /dev/null
+/* $NetBSD: fpu_calcea.c,v 1.2 1995/11/05 00:35:15 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Gordon W. Ross
+ * portion Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gordon Ross
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <machine/frame.h>
+
+#include "fpu_emulate.h"
+
+/*
+ * Prototypes of static functions
+ */
+static int decode_ea6 __P((struct frame *frame, struct instruction *insn,
+ struct insn_ea *ea, int modreg));
+static int fetch_immed __P((struct frame *frame, struct instruction *insn,
+ int *dst));
+static int fetch_disp __P((struct frame *frame, struct instruction *insn,
+ int size, int *res));
+static int calc_ea __P((struct insn_ea *ea, char *ptr, char **eaddr));
+
+/*
+ * Helper routines for dealing with "effective address" values.
+ */
+
+/*
+ * Decode an effective address into internal form.
+ * Returns zero on success, else signal number.
+ */
+int
+fpu_decode_ea(frame, insn, ea, modreg)
+ struct frame *frame;
+ struct instruction *insn;
+ struct insn_ea *ea;
+ int modreg;
+{
+ int data, sig;
+
+#ifdef DEBUG
+ if (insn->is_datasize < 0) {
+ panic("decode_ea: called with uninitialized datasize\n");
+ }
+#endif
+
+ sig = 0;
+
+ /* Set the most common value here. */
+ ea->ea_regnum = 8 + (modreg & 7);
+
+ switch (modreg & 070) {
+ case 0: /* Dn */
+ ea->ea_regnum &= 7;
+ case 010: /* An */
+ ea->ea_flags = EA_DIRECT;
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: register direct reg=%d\n", ea->ea_regnum);
+ }
+ break;
+
+ case 020: /* (An) */
+ ea->ea_flags = 0;
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: register indirect reg=%d\n", ea->ea_regnum);
+ }
+ break;
+
+ case 030: /* (An)+ */
+ ea->ea_flags = EA_POSTINCR;
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: reg indirect postincrement reg=%d\n",
+ ea->ea_regnum);
+ }
+ break;
+
+ case 040: /* -(An) */
+ ea->ea_flags = EA_PREDECR;
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: reg indirect predecrement reg=%d\n",
+ ea->ea_regnum);
+ }
+ break;
+
+ case 050: /* (d16,An) */
+ ea->ea_flags = EA_OFFSET;
+ sig = fetch_disp(frame, insn, 1, &ea->ea_offset);
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: reg indirect with displacement reg=%d\n",
+ ea->ea_regnum);
+ }
+ break;
+
+ case 060: /* (d8,An,Xn) */
+ ea->ea_flags = EA_INDEXED;
+ sig = decode_ea6(frame, insn, ea, modreg);
+ break;
+
+ case 070: /* misc. */
+ ea->ea_regnum = (modreg & 7);
+ switch (modreg & 7) {
+
+ case 0: /* (xxxx).W */
+ ea->ea_flags = EA_ABS;
+ sig = fetch_disp(frame, insn, 1, &ea->ea_absaddr);
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: absolute address (word)\n");
+ }
+ break;
+
+ case 1: /* (xxxxxxxx).L */
+ ea->ea_flags = EA_ABS;
+ sig = fetch_disp(frame, insn, 2, &ea->ea_absaddr);
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: absolute address (long)\n");
+ }
+ break;
+
+ case 2: /* (d16,PC) */
+ ea->ea_flags = EA_PC_REL | EA_OFFSET;
+ sig = fetch_disp(frame, insn, 1, &ea->ea_absaddr);
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: pc relative word displacement\n");
+ }
+ break;
+
+ case 3: /* (d8,PC,Xn) */
+ ea->ea_flags = EA_PC_REL | EA_INDEXED;
+ sig = decode_ea6(frame, insn, ea, modreg);
+ break;
+
+ case 4: /* #data */
+ ea->ea_flags = EA_IMMED;
+ sig = fetch_immed(frame, insn, &ea->ea_immed[0]);
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: immediate size=%d\n", insn->is_datasize);
+ }
+ break;
+
+ default:
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea: invalid addr mode (7,%d)\n", modreg & 7);
+ }
+ return SIGILL;
+ } /* switch for mode 7 */
+ break;
+ } /* switch mode */
+
+ ea->ea_tdisp = 0;
+
+ return sig;
+}
+
+/*
+ * Decode Mode=6 address modes
+ */
+static int
+decode_ea6(frame, insn, ea, modreg)
+ struct frame *frame;
+ struct instruction *insn;
+ struct insn_ea *ea;
+ int modreg;
+{
+ int word, extword, idx;
+ int basedisp, outerdisp;
+ int bd_size, od_size;
+ int sig;
+
+ extword = fusword(frame->f_pc + insn->is_advance);
+ if (extword < 0) {
+ return SIGSEGV;
+ }
+ insn->is_advance += 2;
+
+ /* get register index */
+ ea->ea_idxreg = (extword >> 12) & 0xf;
+ idx = frame->f_regs[ea->ea_idxreg];
+ if ((extword & 0x0800) == 0) {
+ /* if word sized index, sign-extend */
+ idx &= 0xffff;
+ if (idx & 0x8000) {
+ idx |= 0xffff0000;
+ }
+ }
+ /* scale register index */
+ idx <<= ((extword >>9) & 3);
+
+ if ((extword & 0x100) == 0) {
+ /* brief extention word - sign-extend the displacement */
+ basedisp = (extword & 0xff);
+ if (basedisp & 0x80) {
+ basedisp |= 0xffffff00;
+ }
+
+ ea->ea_basedisp = idx + basedisp;
+ ea->ea_outerdisp = 0;
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea6: brief ext word idxreg=%d, basedisp=%08x\n",
+ ea->ea_idxreg, ea->ea_basedisp);
+ }
+ } else {
+ /* full extention word */
+ if (extword & 0x80) {
+ ea->ea_flags |= EA_BASE_SUPPRSS;
+ }
+ bd_size = ((extword >> 4) & 3) - 1;
+ od_size = (extword & 3) - 1;
+ sig = fetch_disp(frame, insn, bd_size, &basedisp);
+ if (sig) {
+ return sig;
+ }
+ if (od_size >= 0) {
+ ea->ea_flags |= EA_MEM_INDIR;
+ }
+ sig = fetch_disp(frame, insn, od_size, &outerdisp);
+ if (sig) {
+ return sig;
+ }
+
+ switch (extword & 0x44) {
+ case 0: /* preindexed */
+ ea->ea_basedisp = basedisp + idx;
+ ea->ea_outerdisp = outerdisp;
+ break;
+ case 4: /* postindexed */
+ ea->ea_basedisp = basedisp;
+ ea->ea_outerdisp = outerdisp + idx;
+ break;
+ case 0x40: /* no index */
+ ea->ea_basedisp = basedisp;
+ ea->ea_outerdisp = outerdisp;
+ break;
+ default:
+#ifdef DEBUG
+ printf(" decode_ea6: invalid indirect mode: ext word %04x\n",
+ extword);
+#endif
+ return SIGILL;
+ break;
+ }
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea6: full ext idxreg=%d, basedisp=%x, outerdisp=%x\n",
+ ea->ea_idxreg, ea->ea_basedisp, ea->ea_outerdisp);
+ }
+ }
+ if (fpu_debug_level & DL_DECODEEA) {
+ printf(" decode_ea6: regnum=%d, flags=%x\n",
+ ea->ea_regnum, ea->ea_flags);
+ }
+ return 0;
+}
+
+/*
+ * Load a value from an effective address.
+ * Returns zero on success, else signal number.
+ */
+int
+fpu_load_ea(frame, insn, ea, dst)
+ struct frame *frame;
+ struct instruction *insn;
+ struct insn_ea *ea;
+ char *dst;
+{
+ int *reg;
+ char *src;
+ int len, step;
+ int data, word, sig;
+
+#ifdef DIAGNOSTIC
+ if (ea->ea_regnum & ~0xF) {
+ panic(" load_ea: bad regnum");
+ }
+#endif
+
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: frame at %08x\n", frame);
+ }
+ /* The dst is always int or larger. */
+ len = insn->is_datasize;
+ if (len < 4) {
+ dst += (4 - len);
+ }
+ step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
+
+ if (ea->ea_flags & EA_DIRECT) {
+ if (len > 4) {
+#ifdef DEBUG
+ printf(" load_ea: operand doesn't fit cpu reg\n");
+#endif
+ return SIGILL;
+ }
+ if (ea->ea_tdisp > 0) {
+#ifdef DEBUG
+ printf(" load_ea: more than one move from cpu reg\n");
+#endif
+ return SIGILL;
+ }
+ src = (char *)&frame->f_regs[ea->ea_regnum];
+ /* The source is an int. */
+ if (len < 4) {
+ src += (4 - len);
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: short/byte opr - addr adjusted\n");
+ }
+ }
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: src 0x%08x\n", src);
+ }
+ bcopy(src, dst, len);
+ } else if (ea->ea_flags & EA_IMMED) {
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: immed %08x%08x%08x size %d\n",
+ ea->ea_immed[0], ea->ea_immed[1], ea->ea_immed[2], len);
+ }
+ src = (char *)&ea->ea_immed[0];
+ if (len < 4) {
+ src += (4 - len);
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: short/byte immed opr - addr adjusted\n");
+ }
+ }
+ bcopy(src, dst, len);
+ } else if (ea->ea_flags & EA_ABS) {
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: abs addr %08x\n", ea->ea_absaddr);
+ }
+ src = (char *)ea->ea_absaddr;
+ copyin(src, dst, len);
+ } else /* register indirect */ {
+ if (ea->ea_flags & EA_PC_REL) {
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: using PC\n");
+ }
+ reg = NULL;
+ /* Grab the register contents. 4 is offset to the first
+ extention word from the opcode */
+ src = (char *)frame->f_pc + 4;
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: pc relative pc+4 = 0x%08x\n", src);
+ }
+ } else /* not PC relative */ {
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: using register %c%d\n",
+ (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7);
+ }
+ /* point to the register */
+ reg = &frame->f_regs[ea->ea_regnum];
+
+ if (ea->ea_flags & EA_PREDECR) {
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: predecr mode - reg decremented\n");
+ }
+ *reg -= step;
+ ea->ea_tdisp = 0;
+ }
+
+ /* Grab the register contents. */
+ src = (char *)*reg;
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: reg indirect reg = 0x%08x\n", src);
+ }
+ }
+
+ sig = calc_ea(ea, src, &src);
+ if (sig)
+ return sig;
+
+ copyin(src + ea->ea_tdisp, dst, len);
+
+ /* do post-increment */
+ if (ea->ea_flags & EA_POSTINCR) {
+ if (ea->ea_flags & EA_PC_REL) {
+#ifdef DEBUG
+ printf(" load_ea: tried to postincrement PC\n");
+#endif
+ return SIGILL;
+ }
+ *reg += step;
+ ea->ea_tdisp = 0;
+ if (fpu_debug_level & DL_LOADEA) {
+ printf(" load_ea: postinc mode - reg incremented\n");
+ }
+ } else {
+ ea->ea_tdisp += len;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Store a value at the effective address.
+ * Returns zero on success, else signal number.
+ */
+int
+fpu_store_ea(frame, insn, ea, src)
+ struct frame *frame;
+ struct instruction *insn;
+ struct insn_ea *ea;
+ char *src;
+{
+ int *reg;
+ char *dst;
+ int len, step;
+ int data, word, sig;
+
+#ifdef DIAGNOSTIC
+ if (ea->ea_regnum & ~0xF) {
+ panic(" store_ea: bad regnum");
+ }
+#endif
+
+ if (ea->ea_flags & (EA_IMMED|EA_PC_REL)) {
+ /* not alterable address mode */
+#ifdef DEBUG
+ printf(" store_ea: not alterable address mode\n");
+#endif
+ return SIGILL;
+ }
+
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" store_ea: frame at %08x\n", frame);
+ }
+ /* The src is always int or larger. */
+ len = insn->is_datasize;
+ if (len < 4) {
+ src += (4 - len);
+ }
+ step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
+
+ if (ea->ea_flags & EA_ABS) {
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" store_ea: abs addr %08x\n", ea->ea_absaddr);
+ }
+ dst = (char *)ea->ea_absaddr;
+ copyout(src, dst + ea->ea_tdisp, len);
+ ea->ea_tdisp += len;
+ } else if (ea->ea_flags & EA_DIRECT) {
+ if (len > 4) {
+#ifdef DEBUG
+ printf(" store_ea: operand doesn't fit cpu reg\n");
+#endif
+ return SIGILL;
+ }
+ if (ea->ea_tdisp > 0) {
+#ifdef DEBUG
+ printf(" store_ea: more than one move to cpu reg\n");
+#endif
+ return SIGILL;
+ }
+ dst = (char*)&frame->f_regs[ea->ea_regnum];
+ /* The destination is an int. */
+ if (len < 4) {
+ dst += (4 - len);
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" store_ea: short/byte opr - dst addr adjusted\n");
+ }
+ }
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" store_ea: dst 0x%08x\n", dst);
+ }
+ bcopy(src, dst, len);
+ } else /* One of MANY indirect forms... */ {
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" store_ea: using register %c%d\n",
+ (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7);
+ }
+ /* point to the register */
+ reg = &(frame->f_regs[ea->ea_regnum]);
+
+ /* do pre-decrement */
+ if (ea->ea_flags & EA_PREDECR) {
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" store_ea: predecr mode - reg decremented\n");
+ }
+ *reg -= step;
+ ea->ea_tdisp = 0;
+ }
+
+ /* calculate the effective address */
+ sig = calc_ea(ea, (char *)*reg, &dst);
+ if (sig)
+ return sig;
+
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" store_ea: dst addr=0x%08x+%d\n", dst, ea->ea_tdisp);
+ }
+ copyout(src, dst + ea->ea_tdisp, len);
+
+ /* do post-increment */
+ if (ea->ea_flags & EA_POSTINCR) {
+ *reg += step;
+ ea->ea_tdisp = 0;
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" store_ea: postinc mode - reg incremented\n");
+ }
+ } else {
+ ea->ea_tdisp += len;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * fetch_immed: fetch immediate operand
+ */
+static int
+fetch_immed(frame, insn, dst)
+ struct frame *frame;
+ struct instruction *insn;
+ int *dst;
+{
+ int data, ext_bytes;
+
+ ext_bytes = insn->is_datasize;
+
+ if (0 < ext_bytes) {
+ data = fusword(frame->f_pc + insn->is_advance);
+ if (data < 0) {
+ return SIGSEGV;
+ }
+ if (ext_bytes == 1) {
+ /* sign-extend byte to long */
+ data &= 0xff;
+ if (data & 0x80) {
+ data |= 0xffffff00;
+ }
+ } else if (ext_bytes == 2) {
+ /* sign-extend word to long */
+ data &= 0xffff;
+ if (data & 0x8000) {
+ data |= 0xffff0000;
+ }
+ }
+ insn->is_advance += 2;
+ dst[0] = data;
+ }
+ if (2 < ext_bytes) {
+ data = fusword(frame->f_pc + insn->is_advance);
+ if (data < 0) {
+ return SIGSEGV;
+ }
+ insn->is_advance += 2;
+ dst[0] <<= 16;
+ dst[0] |= data;
+ }
+ if (4 < ext_bytes) {
+ data = fusword(frame->f_pc + insn->is_advance);
+ if (data < 0) {
+ return SIGSEGV;
+ }
+ dst[1] = data << 16;
+ data = fusword(frame->f_pc + insn->is_advance + 2);
+ if (data < 0) {
+ return SIGSEGV;
+ }
+ insn->is_advance += 4;
+ dst[1] |= data;
+ }
+ if (8 < ext_bytes) {
+ data = fusword(frame->f_pc + insn->is_advance);
+ if (data < 0) {
+ return SIGSEGV;
+ }
+ dst[2] = data << 16;
+ data = fusword(frame->f_pc + insn->is_advance + 2);
+ if (data < 0) {
+ return SIGSEGV;
+ }
+ insn->is_advance += 4;
+ dst[2] |= data;
+ }
+
+ return 0;
+}
+
+/*
+ * fetch_disp: fetch displacement in full extention words
+ */
+static int
+fetch_disp(frame, insn, size, res)
+ struct frame *frame;
+ struct instruction *insn;
+ int size, *res;
+{
+ int disp, word;
+
+ if (size == 1) {
+ word = fusword(frame->f_pc + insn->is_advance);
+ if (word < 0) {
+ return SIGSEGV;
+ }
+ disp = word & 0xffff;
+ if (disp & 0x8000) {
+ /* sign-extend */
+ disp |= 0xffff0000;
+ }
+ insn->is_advance += 2;
+ } else if (size == 2) {
+ word = fusword(frame->f_pc + insn->is_advance);
+ if (word < 0) {
+ return SIGSEGV;
+ }
+ disp = word << 16;
+ word = fusword(frame->f_pc + insn->is_advance + 2);
+ if (word < 0) {
+ return SIGSEGV;
+ }
+ disp |= (word & 0xffff);
+ insn->is_advance += 4;
+ } else {
+ disp = 0;
+ }
+ *res = disp;
+ return 0;
+}
+
+/*
+ * Calculates an effective address for all address modes except for
+ * register direct, absolute, and immediate modes. However, it does
+ * not take care of predecrement/postincrement of register content.
+ * Returns a signal value (0 == no error).
+ */
+static int
+calc_ea(ea, ptr, eaddr)
+ struct insn_ea *ea;
+ char *ptr; /* base address (usually a register content) */
+ char **eaddr; /* pointer to result pointer */
+{
+ int data, word, sig;
+
+ if (fpu_debug_level & DL_EA) {
+ printf(" calc_ea: reg indirect (reg) = 0x%08x\n", ptr);
+ }
+
+ if (ea->ea_flags & EA_OFFSET) {
+ /* apply the signed offset */
+ if (fpu_debug_level & DL_EA) {
+ printf(" calc_ea: offset %d\n", ea->ea_offset);
+ }
+ ptr += ea->ea_offset;
+ } else if (ea->ea_flags & EA_INDEXED) {
+ if (fpu_debug_level & DL_EA) {
+ printf(" calc_ea: indexed mode\n");
+ }
+
+ if (ea->ea_flags & EA_BASE_SUPPRSS) {
+ /* base register is suppressed */
+ ptr = (char *)ea->ea_basedisp;
+ } else {
+ ptr += ea->ea_basedisp;
+ }
+
+ if (ea->ea_flags & EA_MEM_INDIR) {
+ if (fpu_debug_level & DL_EA) {
+ printf(" calc_ea: mem indir mode: basedisp=%08x, outerdisp=%08x\n",
+ ea->ea_basedisp, ea->ea_outerdisp);
+ printf(" calc_ea: addr fetched from 0x%08x\n", ptr);
+ }
+ /* memory indirect modes */
+ word = fusword(ptr);
+ if (word < 0) {
+ return SIGSEGV;
+ }
+ word <<= 16;
+ data = fusword(ptr + 2);
+ if (data < 0) {
+ return SIGSEGV;
+ }
+ word |= data;
+ if (fpu_debug_level & DL_STOREEA) {
+ printf(" calc_ea: fetched ptr 0x%08x\n", word);
+ }
+ ptr = (char *)word + ea->ea_outerdisp;
+ }
+ }
+
+ *eaddr = ptr;
+
+ return 0;
+}
--- /dev/null
+/* $NetBSD: fpu_div.c,v 1.1 1995/11/03 04:47:02 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_div.c 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Perform an FPU divide (return x / y).
+ */
+
+#include <sys/types.h>
+
+#include <machine/reg.h>
+
+#include "fpu_arith.h"
+#include "fpu_emulate.h"
+
+/*
+ * Division of normal numbers is done as follows:
+ *
+ * x and y are floating point numbers, i.e., in the form 1.bbbb * 2^e.
+ * If X and Y are the mantissas (1.bbbb's), the quotient is then:
+ *
+ * q = (X / Y) * 2^((x exponent) - (y exponent))
+ *
+ * Since X and Y are both in [1.0,2.0), the quotient's mantissa (X / Y)
+ * will be in [0.5,2.0). Moreover, it will be less than 1.0 if and only
+ * if X < Y. In that case, it will have to be shifted left one bit to
+ * become a normal number, and the exponent decremented. Thus, the
+ * desired exponent is:
+ *
+ * left_shift = x->fp_mant < y->fp_mant;
+ * result_exp = x->fp_exp - y->fp_exp - left_shift;
+ *
+ * The quotient mantissa X/Y can then be computed one bit at a time
+ * using the following algorithm:
+ *
+ * Q = 0; -- Initial quotient.
+ * R = X; -- Initial remainder,
+ * if (left_shift) -- but fixed up in advance.
+ * R *= 2;
+ * for (bit = FP_NMANT; --bit >= 0; R *= 2) {
+ * if (R >= Y) {
+ * Q |= 1 << bit;
+ * R -= Y;
+ * }
+ * }
+ *
+ * The subtraction R -= Y always removes the uppermost bit from R (and
+ * can sometimes remove additional lower-order 1 bits); this proof is
+ * left to the reader.
+ *
+ * This loop correctly calculates the guard and round bits since they are
+ * included in the expanded internal representation. The sticky bit
+ * is to be set if and only if any other bits beyond guard and round
+ * would be set. From the above it is obvious that this is true if and
+ * only if the remainder R is nonzero when the loop terminates.
+ *
+ * Examining the loop above, we can see that the quotient Q is built
+ * one bit at a time ``from the top down''. This means that we can
+ * dispense with the multi-word arithmetic and just build it one word
+ * at a time, writing each result word when it is done.
+ *
+ * Furthermore, since X and Y are both in [1.0,2.0), we know that,
+ * initially, R >= Y. (Recall that, if X < Y, R is set to X * 2 and
+ * is therefore at in [2.0,4.0).) Thus Q is sure to have bit FP_NMANT-1
+ * set, and R can be set initially to either X - Y (when X >= Y) or
+ * 2X - Y (when X < Y). In addition, comparing R and Y is difficult,
+ * so we will simply calculate R - Y and see if that underflows.
+ * This leads to the following revised version of the algorithm:
+ *
+ * R = X;
+ * bit = FP_1;
+ * D = R - Y;
+ * if (D >= 0) {
+ * result_exp = x->fp_exp - y->fp_exp;
+ * R = D;
+ * q = bit;
+ * bit >>= 1;
+ * } else {
+ * result_exp = x->fp_exp - y->fp_exp - 1;
+ * q = 0;
+ * }
+ * R <<= 1;
+ * do {
+ * D = R - Y;
+ * if (D >= 0) {
+ * q |= bit;
+ * R = D;
+ * }
+ * R <<= 1;
+ * } while ((bit >>= 1) != 0);
+ * Q[0] = q;
+ * for (i = 1; i < 4; i++) {
+ * q = 0, bit = 1 << 31;
+ * do {
+ * D = R - Y;
+ * if (D >= 0) {
+ * q |= bit;
+ * R = D;
+ * }
+ * R <<= 1;
+ * } while ((bit >>= 1) != 0);
+ * Q[i] = q;
+ * }
+ *
+ * This can be refined just a bit further by moving the `R <<= 1'
+ * calculations to the front of the do-loops and eliding the first one.
+ * The process can be terminated immediately whenever R becomes 0, but
+ * this is relatively rare, and we do not bother.
+ */
+
+struct fpn *
+fpu_div(fe)
+ register struct fpemu *fe;
+{
+ register struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;
+ register u_int q, bit;
+ register u_int r0, r1, r2, r3, d0, d1, d2, d3, y0, y1, y2, y3;
+ FPU_DECL_CARRY
+
+ fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+ /*
+ * Since divide is not commutative, we cannot just use ORDER.
+ * Check either operand for NaN first; if there is at least one,
+ * order the signalling one (if only one) onto the right, then
+ * return it. Otherwise we have the following cases:
+ *
+ * Inf / Inf = NaN, plus NV exception
+ * Inf / num = Inf [i.e., return x]
+ * Inf / 0 = Inf [i.e., return x]
+ * 0 / Inf = 0 [i.e., return x]
+ * 0 / num = 0 [i.e., return x]
+ * 0 / 0 = NaN, plus NV exception
+ * num / Inf = 0
+ * num / num = num (do the divide)
+ * num / 0 = Inf, plus DZ exception
+ */
+ if (ISNAN(x) || ISNAN(y)) {
+ ORDER(x, y);
+ return (y);
+ }
+ if (ISINF(x) || ISZERO(x)) {
+ if (x->fp_class == y->fp_class)
+ return (fpu_newnan(fe));
+ return (x);
+ }
+
+ /* all results at this point use XOR of operand signs */
+ x->fp_sign ^= y->fp_sign;
+ if (ISINF(y)) {
+ x->fp_class = FPC_ZERO;
+ return (x);
+ }
+ if (ISZERO(y)) {
+ fe->fe_fpsr |= FPSR_DZ;
+ x->fp_class = FPC_INF;
+ return (x);
+ }
+
+ /*
+ * Macros for the divide. See comments at top for algorithm.
+ * Note that we expand R, D, and Y here.
+ */
+
+#define SUBTRACT /* D = R - Y */ \
+ FPU_SUBS(d3, r3, y3); FPU_SUBCS(d2, r2, y2); \
+ FPU_SUBCS(d1, r1, y1); FPU_SUBC(d0, r0, y0)
+
+#define NONNEGATIVE /* D >= 0 */ \
+ ((int)d0 >= 0)
+
+#ifdef FPU_SHL1_BY_ADD
+#define SHL1 /* R <<= 1 */ \
+ FPU_ADDS(r3, r3, r3); FPU_ADDCS(r2, r2, r2); \
+ FPU_ADDCS(r1, r1, r1); FPU_ADDC(r0, r0, r0)
+#else
+#define SHL1 \
+ r0 = (r0 << 1) | (r1 >> 31), r1 = (r1 << 1) | (r2 >> 31), \
+ r2 = (r2 << 1) | (r3 >> 31), r3 <<= 1
+#endif
+
+#define LOOP /* do ... while (bit >>= 1) */ \
+ do { \
+ SHL1; \
+ SUBTRACT; \
+ if (NONNEGATIVE) { \
+ q |= bit; \
+ r0 = d0, r1 = d1, r2 = d2, r3 = d3; \
+ } \
+ } while ((bit >>= 1) != 0)
+
+#define WORD(r, i) /* calculate r->fp_mant[i] */ \
+ q = 0; \
+ bit = 1 << 31; \
+ LOOP; \
+ (x)->fp_mant[i] = q
+
+ /* Setup. Note that we put our result in x. */
+ r0 = x->fp_mant[0];
+ r1 = x->fp_mant[1];
+ r2 = x->fp_mant[2];
+ r3 = x->fp_mant[3];
+ y0 = y->fp_mant[0];
+ y1 = y->fp_mant[1];
+ y2 = y->fp_mant[2];
+ y3 = y->fp_mant[3];
+
+ bit = FP_1;
+ SUBTRACT;
+ if (NONNEGATIVE) {
+ x->fp_exp -= y->fp_exp;
+ r0 = d0, r1 = d1, r2 = d2, r3 = d3;
+ q = bit;
+ bit >>= 1;
+ } else {
+ x->fp_exp -= y->fp_exp + 1;
+ q = 0;
+ }
+ LOOP;
+ x->fp_mant[0] = q;
+ WORD(x, 1);
+ WORD(x, 2);
+ WORD(x, 3);
+ x->fp_sticky = r0 | r1 | r2 | r3;
+
+ return (x);
+}
-/* $NetBSD: fpu_emulate.c,v 1.2 1995/03/10 01:43:05 gwr Exp $ */
+/* $NetBSD: fpu_emulate.c,v 1.4 1995/11/05 00:35:17 briggs Exp $ */
/*
* Copyright (c) 1995 Gordon W. Ross
+ * some portion Copyright (c) 1995 Ken Nakata
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include <sys/signal.h>
#include <machine/frame.h>
-#define DEBUG 1 /* XXX */
+#include "fpu_emulate.h"
+
+static int fpu_emul_fmovmcr __P((struct fpemu *fe, struct instruction *insn));
+static int fpu_emul_fmovm __P((struct fpemu *fe, struct instruction *insn));
+static int fpu_emul_arith __P((struct fpemu *fe, struct instruction *insn));
+static int fpu_emul_type1 __P((struct fpemu *fe, struct instruction *insn));
+static int fpu_emul_brcc __P((struct fpemu *fe, struct instruction *insn));
+static int test_cc __P((struct fpemu *fe, int pred));
+static struct fpn *fpu_cmp __P((struct fpemu *fe));
+
+#if !defined(DL_DEFAULT)
+# if defined(DEBUG_WITH_FPU)
+# define DL_DEFAULT DL_ALL
+# else
+# define DL_DEFAULT 0
+# endif
+#endif
-/*
- * Internal info about a decoded effective address.
- */
-struct insn_ea {
- int regnum;
- int immed;
- int flags;
-#define EA_DIRECT 0x01
-#define EA_PREDECR 0x02
-#define EA_POSTINCR 0x04
-#define EA_OFFSET 0x08 /* mode 5: base+offset */
-#define EA_INDEXED 0x10 /* mode 6: complicated */
-#define EA_ABS 0x20 /* mode 7: reg 0 or 1 */
-#define EA_PC_REL 0x40 /* mode 7: reg 2 or 3 */
-#define EA_IMMED 0x80 /* mode 7: reg 4 */
-};
-
-struct instruction {
- int advance; /* length of instruction */
- int datasize; /* byte, word, long, float, double, ... */
- int opcode;
- int word1;
- struct insn_ea ea0;
- struct insn_ea ea1;
-};
-
-int fpu_emul_fmovm(struct frame *frame,
- struct fpframe *fpf,
- struct instruction *insn);
-int fpu_emul_type0(struct frame *frame,
- struct fpframe *fpf,
- struct instruction *insn);
-int fpu_emul_type1(struct frame *frame,
- struct fpframe *fpf,
- struct instruction *insn);
-int fpu_emul_brcc(struct frame *frame,
- struct fpframe *fpf,
- struct instruction *insn);
-
-static int decode_ea(struct frame *frame,
- struct instruction *insn,
- struct insn_ea *ea,
- int modreg);
-static int load_ea(struct frame *frame,
- struct instruction *insn,
- struct insn_ea *ea,
- char *cpureg);
-static int store_ea(struct frame *frame,
- struct instruction *insn,
- struct insn_ea *ea,
- char *cpureg);
+int fpu_debug_level;
+static int global_debug_level = DL_DEFAULT;
+#define DUMP_INSN(insn) \
+if (fpu_debug_level & DL_DUMPINSN) { \
+ printf(" fpu_emulate: insn={adv=%d,siz=%d,op=%04x,w1=%04x}\n", \
+ (insn)->is_advance, (insn)->is_datasize, \
+ (insn)->is_opcode, (insn)->is_word1); \
+}
+
+#ifdef DEBUG_WITH_FPU
+/* mock fpframe for FPE - it's never overwritten by the real fpframe */
+struct fpframe mockfpf;
+#endif
/*
* Emulate a floating-point instruction.
* Return zero for success, else signal number.
* (Typically: zero, SIGFPE, SIGILL, SIGSEGV)
*/
-int fpu_emulate(struct frame *frame, struct fpframe *fpf)
+int
+fpu_emulate(frame, fpf)
+ struct frame *frame;
+ struct fpframe *fpf;
{
- struct instruction insn;
- int word, optype, sig;
-
- word = fusword(frame->f_pc);
- if (word < 0) {
-#ifdef DEBUG
- printf("fpu_emulate: fault reading opcode\n");
+ static struct instruction insn;
+ static struct fpemu fe;
+ int word, optype, sig;
+ int i;
+ u_int *pt;
+
+#ifdef DEBUG
+ /* initialize insn.is_datasize to tell it is *not* initialized */
+ insn.is_datasize = -1;
+#endif
+ fe.fe_frame = frame;
+#ifdef DEBUG_WITH_FPU
+ fe.fe_fpframe = &mockfpf;
+ fe.fe_fpsr = mockfpf.fpf_fpsr;
+ fe.fe_fpcr = mockfpf.fpf_fpcr;
+#else
+ fe.fe_fpframe = fpf;
+ fe.fe_fpsr = fpf->fpf_fpsr;
+ fe.fe_fpcr = fpf->fpf_fpcr;
#endif
- return SIGSEGV;
- }
- if ((word & 0xF000) != 0xF000) {
-#ifdef DEBUG
- printf("fpu_emulate: not coproc. insn.: opcode=0x%x\n", word);
+#ifdef DEBUG
+ if ((fpu_debug_level = (fe.fe_fpcr >> 16) & 0x0000ffff) == 0) {
+ /* set the default */
+ fpu_debug_level = global_debug_level;
+ }
#endif
- return SIGILL;
- }
- if ((word & 0x0E00) != 0x0200) {
-#ifdef DEBUG
- printf("fpu_emulate: bad coproc. id: opcode=0x%x\n", word);
+ if (fpu_debug_level & DL_VERBOSE) {
+ printf("ENTERING fpu_emulate: FPSR=%08x, FPCR=%08x\n",
+ fe.fe_fpsr, fe.fe_fpcr);
+ }
+ word = fusword(frame->f_pc);
+ if (word < 0) {
+#ifdef DEBUG
+ printf(" fpu_emulate: fault reading opcode\n");
#endif
- return SIGILL;
- }
+ return SIGSEGV;
+ }
- insn.opcode = word;
- optype = (word & 0x01C0);
+ if ((word & 0xf000) != 0xf000) {
+#ifdef DEBUG
+ printf(" fpu_emulate: not coproc. insn.: opcode=0x%x\n", word);
+#endif
+ return SIGILL;
+ }
- word = fusword(frame->f_pc + 2);
- if (word < 0) {
-#ifdef DEBUG
- printf("fpu_emulate: fault reading word1\n");
+ if (
+#ifdef DEBUG_WITH_FPU
+ (word & 0x0E00) != 0x0c00 /* accept fake ID == 6 */
+#else
+ (word & 0x0E00) != 0x0200
#endif
- return SIGSEGV;
- }
- insn.word1 = word;
+ ) {
+#ifdef DEBUG
+ printf(" fpu_emulate: bad coproc. id: opcode=0x%x\n", word);
+#endif
+ return SIGILL;
+ }
- /*
- * Which family (or type) of opcode is it?
- * Tests ordered by likelihood (hopefully).
- * Certainly, type 0 is the most common.
- */
- if (optype == 0x0000) {
- /* type=0: generic */
- if (insn.word1 & 0x8000) {
- sig = fpu_emul_fmovm(frame, fpf, &insn);
- } else {
- sig = fpu_emul_type0(frame, fpf, &insn);
- }
- }
- else if (optype == 0x0080) {
- /* type=2: fbcc, short disp. */
- sig = fpu_emul_brcc(frame, fpf, &insn);
- }
- else if (optype == 0x00C0) {
- /* type=3: fbcc, long disp. */
- sig = fpu_emul_brcc(frame, fpf, &insn);
- }
- else if (optype == 0x0040) {
- /* type=1: fdbcc, fscc, ftrapcc */
- sig = fpu_emul_type1(frame, fpf, &insn);
- }
- else {
- /* type=4: fsave (privileged) */
- /* type=5: frestore (privileged) */
- /* type=6: reserved */
- /* type=7: reserved */
-#ifdef DEBUG
- printf("fpu_emulate: bad opcode type: opcode=0x%x\n", insn.opcode);
+ insn.is_opcode = word;
+ optype = (word & 0x01C0);
+
+ word = fusword(frame->f_pc + 2);
+ if (word < 0) {
+#ifdef DEBUG
+ printf(" fpu_emulate: fault reading word1\n");
#endif
- sig = SIGILL;
+ return SIGSEGV;
+ }
+ insn.is_word1 = word;
+ /* all FPU instructions are at least 4-byte long */
+ insn.is_advance = 4;
+
+ DUMP_INSN(&insn);
+
+ /*
+ * Which family (or type) of opcode is it?
+ * Tests ordered by likelihood (hopefully).
+ * Certainly, type 0 is the most common.
+ */
+ if (optype == 0x0000) {
+ /* type=0: generic */
+ if ((word & 0xc000) == 0xc000) {
+ if (fpu_debug_level & DL_INSN)
+ printf(" fpu_emulate: fmovm FPr\n");
+ sig = fpu_emul_fmovm(&fe, &insn);
+ } else if ((word & 0xc000) == 0x8000) {
+ if (fpu_debug_level & DL_INSN)
+ printf(" fpu_emulate: fmovm FPcr\n");
+ sig = fpu_emul_fmovmcr(&fe, &insn);
+ } else if ((word & 0xe000) == 0x6000) {
+ /* fstore = fmove FPn,mem */
+ if (fpu_debug_level & DL_INSN)
+ printf(" fpu_emulate: fmove to mem\n");
+ sig = fpu_emul_fstore(&fe, &insn);
+ } else if ((word & 0xfc00) == 0x5c00) {
+ /* fmovecr */
+ if (fpu_debug_level & DL_INSN)
+ printf(" fpu_emulate: fmovecr\n");
+ sig = fpu_emul_fmovecr(&fe, &insn);
+ } else if ((word & 0xa07f) == 0x26) {
+ /* fscale */
+ if (fpu_debug_level & DL_INSN)
+ printf(" fpu_emulate: fscale\n");
+ sig = fpu_emul_fscale(&fe, &insn);
+ } else {
+ if (fpu_debug_level & DL_INSN)
+ printf(" fpu_emulte: other type0\n");
+ /* all other type0 insns are arithmetic */
+ sig = fpu_emul_arith(&fe, &insn);
}
-
if (sig == 0) {
- frame->f_pc += insn.advance;
+ if (fpu_debug_level & DL_VERBOSE)
+ printf(" fpu_emulate: type 0 returned 0\n");
+ sig = fpu_upd_excp(&fe);
}
+ } else if (optype == 0x0080 || optype == 0x00C0) {
+ /* type=2 or 3: fbcc, short or long disp. */
+ if (fpu_debug_level & DL_INSN)
+ printf(" fpu_emulate: fbcc %s\n",
+ (optype & 0x40) ? "long" : "short");
+ sig = fpu_emul_brcc(&fe, &insn);
+ } else if (optype == 0x0040) {
+ /* type=1: fdbcc, fscc, ftrapcc */
+ if (fpu_debug_level & DL_INSN)
+ printf(" fpu_emulate: type1\n");
+ sig = fpu_emul_type1(&fe, &insn);
+ } else {
+ /* type=4: fsave (privileged) */
+ /* type=5: frestore (privileged) */
+ /* type=6: reserved */
+ /* type=7: reserved */
+#ifdef DEBUG
+ printf(" fpu_emulate: bad opcode type: opcode=0x%x\n", insn.is_opcode);
+#endif
+ sig = SIGILL;
+ }
+
+ DUMP_INSN(&insn);
+
+ if (sig == 0) {
+ frame->f_pc += insn.is_advance;
+ }
#if defined(DDB) && defined(DEBUG)
- else kdb_trap(-1, frame);
+ else {
+ printf(" fpu_emulate: sig=%d, opcode=%x, word1=%x\n",
+ sig, insn.is_opcode, insn.is_word1);
+ kdb_trap(-1, frame);
+ }
#endif
- return (sig);
+ if (fpu_debug_level & DL_VERBOSE)
+ printf("EXITING fpu_emulate: w/FPSR=%08x, FPCR=%08x\n",
+ fe.fe_fpsr, fe.fe_fpcr);
+
+ return (sig);
+}
+
+/* update accrued exception bits and see if there's an FP exception */
+int
+fpu_upd_excp(fe)
+ struct fpemu *fe;
+{
+ u_int fpsr;
+ u_int fpcr;
+
+ fpsr = fe->fe_fpsr;
+ fpcr = fe->fe_fpcr;
+ /* update fpsr accrued exception bits; each insn doesn't have to
+ update this */
+ if (fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR)) {
+ fpsr |= FPSR_AIOP;
+ }
+ if (fpsr & FPSR_OVFL) {
+ fpsr |= FPSR_AOVFL;
+ }
+ if ((fpsr & FPSR_UNFL) && (fpsr & FPSR_INEX2)) {
+ fpsr |= FPSR_AUNFL;
+ }
+ if (fpsr & FPSR_DZ) {
+ fpsr |= FPSR_ADZ;
+ }
+ if (fpsr & (FPSR_INEX1 | FPSR_INEX2 | FPSR_OVFL)) {
+ fpsr |= FPSR_AINEX;
+ }
+
+ fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
+
+ return (fpsr & fpcr & FPSR_EXCP) ? SIGFPE : 0;
+}
+
+/* update fpsr according to fp (= result of an fp op) */
+u_int
+fpu_upd_fpsr(fe, fp)
+ struct fpemu *fe;
+ struct fpn *fp;
+{
+ u_int fpsr;
+
+ if (fpu_debug_level & DL_RESULT)
+ printf(" fpu_upd_fpsr: previous fpsr=%08x\n", fe->fe_fpsr);
+
+ /* clear all condition code */
+ fpsr = fe->fe_fpsr & ~FPSR_CCB;
+
+ if (fpu_debug_level & DL_RESULT)
+ printf(" fpu_upd_fpsr: result is a ");
+
+ if (fp->fp_sign) {
+ if (fpu_debug_level & DL_RESULT)
+ printf("negative ");
+ fpsr |= FPSR_NEG;
+ } else {
+ if (fpu_debug_level & DL_RESULT)
+ printf("positive ");
+ }
+
+ switch (fp->fp_class) {
+ case FPC_SNAN:
+ if (fpu_debug_level & DL_RESULT)
+ printf("signaling NAN\n");
+ fpsr |= (FPSR_NAN | FPSR_SNAN);
+ break;
+ case FPC_QNAN:
+ if (fpu_debug_level & DL_RESULT)
+ printf("quiet NAN\n");
+ fpsr |= FPSR_NAN;
+ break;
+ case FPC_ZERO:
+ if (fpu_debug_level & DL_RESULT)
+ printf("Zero\n");
+ fpsr |= FPSR_ZERO;
+ break;
+ case FPC_INF:
+ if (fpu_debug_level & DL_RESULT)
+ printf("Inf\n");
+ fpsr |= FPSR_INF;
+ break;
+ default:
+ if (fpu_debug_level & DL_RESULT)
+ printf("Number\n");
+ /* anything else is treated as if it is a number */
+ break;
+ }
+
+ fe->fe_fpsr = fe->fe_fpframe->fpf_fpsr = fpsr;
+
+ if (fpu_debug_level & DL_RESULT)
+ printf(" fpu_upd_fpsr: new fpsr=%08x\n", fe->fe_fpframe->fpf_fpsr);
+
+ return fpsr;
+}
+
+static int
+fpu_emul_fmovmcr(fe, insn)
+ struct fpemu *fe;
+ struct instruction *insn;
+{
+ struct frame *frame = fe->fe_frame;
+ struct fpframe *fpf = fe->fe_fpframe;
+ int word1, sig;
+ int reglist, regmask, regnum;
+ int fpu_to_mem;
+
+ /* move to/from control registers */
+ reglist = (insn->is_word1 & 0x1c00) >> 10;
+ /* Bit 13 selects direction (FPU to/from Mem) */
+ fpu_to_mem = insn->is_word1 & 0x2000;
+
+ insn->is_datasize = 4;
+ insn->is_advance = 4;
+ sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
+ if (sig) { return sig; }
+
+ if (reglist != 1 && reglist != 2 && reglist != 4 &&
+ (insn->is_ea0.ea_flags & EA_DIRECT)) {
+ /* attempted to copy more than one FPcr to CPU regs */
+#ifdef DEBUG
+ printf(" fpu_emul_fmovmcr: tried to copy too many FPcr\n");
+#endif
+ return SIGILL;
+ }
+
+ if (reglist & 4) {
+ /* fpcr */
+ if ((insn->is_ea0.ea_flags & EA_DIRECT) &&
+ insn->is_ea0.ea_regnum >= 8 /* address reg */) {
+ /* attempted to copy FPCR to An */
+#ifdef DEBUG
+ printf(" fpu_emul_fmovmcr: tried to copy FPCR from/to A%d\n",
+ insn->is_ea0.ea_regnum & 7);
+#endif
+ return SIGILL;
+ }
+ if (fpu_to_mem) {
+ sig = fpu_store_ea(frame, insn, &insn->is_ea0,
+ (char *)&fpf->fpf_fpcr);
+ } else {
+ sig = fpu_load_ea(frame, insn, &insn->is_ea0,
+ (char *)&fpf->fpf_fpcr);
+ }
+ }
+ if (sig) { return sig; }
+
+ if (reglist & 2) {
+ /* fpsr */
+ if ((insn->is_ea0.ea_flags & EA_DIRECT) &&
+ insn->is_ea0.ea_regnum >= 8 /* address reg */) {
+ /* attempted to copy FPSR to An */
+#ifdef DEBUG
+ printf(" fpu_emul_fmovmcr: tried to copy FPSR from/to A%d\n",
+ insn->is_ea0.ea_regnum & 7);
+#endif
+ return SIGILL;
+ }
+ if (fpu_to_mem) {
+ sig = fpu_store_ea(frame, insn, &insn->is_ea0,
+ (char *)&fpf->fpf_fpsr);
+ } else {
+ sig = fpu_load_ea(frame, insn, &insn->is_ea0,
+ (char *)&fpf->fpf_fpsr);
+ }
+ }
+ if (sig) { return sig; }
+
+ if (reglist & 1) {
+ /* fpiar - can be moved to/from An */
+ if (fpu_to_mem) {
+ sig = fpu_store_ea(frame, insn, &insn->is_ea0,
+ (char *)&fpf->fpf_fpiar);
+ } else {
+ sig = fpu_load_ea(frame, insn, &insn->is_ea0,
+ (char *)&fpf->fpf_fpiar);
+ }
+ }
+ return sig;
}
/*
- * type 0: fmovem, fmove <cr>
+ * type 0: fmovem
* Separated out of fpu_emul_type0 for efficiency.
* In this function, we know:
* (opcode & 0x01C0) == 0
* No conversion or rounding is done by this instruction,
* and the FPSR is not affected.
*/
-int fpu_emul_fmovm(struct frame *frame,
- struct fpframe *fpf,
- struct instruction *insn)
+static int
+fpu_emul_fmovm(fe, insn)
+ struct fpemu *fe;
+ struct instruction *insn;
{
- int word1, sig;
- int reglist, regmask, regnum;
- int fpu_to_mem, order;
- int w1_post_incr; /* XXX - FP regs order? */
- int *fpregs;
-
- insn->advance = 4;
- insn->datasize = 12;
- word1 = insn->word1;
-
- /* Bit 14 selects FPn or FP control regs. */
- if (word1 & 0x4000) {
- /*
- * Bits 12,11 select register list mode:
- * 0,0: Static reg list, pre-decr.
- * 0,1: Dynamic reg list, pre-decr.
- * 1,0: Static reg list, post-incr.
- * 1,1: Dynamic reg list, post-incr
- */
- w1_post_incr = word1 & 0x1000;
- if (word1 & 0x0800) {
- /* dynamic reg list */
- reglist = frame->f_regs[(word1 & 0x70) >> 4];
- } else
- reglist = word1;
- reglist &= 0xFF;
- } else {
- /* XXX: move to/from control registers */
- reglist = word1 & 0x1C00;
- return SIGILL;
+ struct frame *frame = fe->fe_frame;
+ struct fpframe *fpf = fe->fe_fpframe;
+ int word1, sig;
+ int reglist, regmask, regnum;
+ int fpu_to_mem, order;
+ int w1_post_incr; /* XXX - FP regs order? */
+ int *fpregs;
+
+ insn->is_advance = 4;
+ insn->is_datasize = 12;
+ word1 = insn->is_word1;
+
+ /* Bit 13 selects direction (FPU to/from Mem) */
+ fpu_to_mem = word1 & 0x2000;
+
+ /*
+ * Bits 12,11 select register list mode:
+ * 0,0: Static reg list, pre-decr.
+ * 0,1: Dynamic reg list, pre-decr.
+ * 1,0: Static reg list, post-incr.
+ * 1,1: Dynamic reg list, post-incr
+ */
+ w1_post_incr = word1 & 0x1000;
+ if (word1 & 0x0800) {
+ /* dynamic reg list */
+ reglist = frame->f_regs[(word1 & 0x70) >> 4];
+ } else {
+ reglist = word1;
+ }
+ reglist &= 0xFF;
+
+ /* Get effective address. (modreg=opcode&077) */
+ sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
+ if (sig) { return sig; }
+
+ /* Get address of soft coprocessor regs. */
+ fpregs = &fpf->fpf_regs[0];
+
+ if (insn->is_ea0.ea_flags & EA_PREDECR) {
+ regnum = 7;
+ order = -1;
+ } else {
+ regnum = 0;
+ order = 1;
+ }
+
+ while ((0 <= regnum) && (regnum < 8)) {
+ regmask = 1 << regnum;
+ if (regmask & reglist) {
+ if (fpu_to_mem) {
+ sig = fpu_store_ea(frame, insn, &insn->is_ea0,
+ (char*)&fpregs[regnum * 3]);
+ if (fpu_debug_level & DL_RESULT)
+ printf(" fpu_emul_fmovm: FP%d (%08x,%08x,%08x) saved\n",
+ regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
+ fpregs[regnum * 3 + 2]);
+ } else { /* mem to fpu */
+ sig = fpu_load_ea(frame, insn, &insn->is_ea0,
+ (char*)&fpregs[regnum * 3]);
+ if (fpu_debug_level & DL_RESULT)
+ printf(" fpu_emul_fmovm: FP%d (%08x,%08x,%08x) loaded\n",
+ regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
+ fpregs[regnum * 3 + 2]);
+ }
+ if (sig) { break; }
}
+ regnum += order;
+ }
- /* Bit 13 selects direction (FPU to/from Mem) */
- fpu_to_mem = word1 & 0x2000;
-
- /* Get effective address. (modreg=opcode&077) */
- sig = decode_ea(frame, insn, &insn->ea0, insn->opcode);
- if (sig) return sig;
-
- /* Get address of soft coprocessor regs. */
- fpregs = &fpf->fpf_regs[0];
+ return sig;
+}
- if (insn->ea0.flags & EA_PREDECR) {
- regnum = 7;
- order = -1;
+static struct fpn *
+fpu_cmp(fe)
+ struct fpemu *fe;
+{
+ struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;
+
+ /* take care of special cases */
+ if (x->fp_class < 0 || y->fp_class < 0) {
+ /* if either of two is a SNAN, result is SNAN */
+ x->fp_class = (y->fp_class < x->fp_class) ? y->fp_class : x->fp_class;
+ } else if (x->fp_class == FPC_INF) {
+ if (y->fp_class == FPC_INF) {
+ /* both infinities */
+ if (x->fp_sign == y->fp_sign) {
+ x->fp_class = FPC_ZERO; /* return a signed zero */
+ } else {
+ x->fp_class = FPC_NUM; /* return a faked number w/x's sign */
+ x->fp_exp = 16383;
+ x->fp_mant[0] = FP_1;
+ }
} else {
- regnum = 0;
- order = 1;
+ /* y is a number */
+ x->fp_class = FPC_NUM; /* return a forged number w/x's sign */
+ x->fp_exp = 16383;
+ x->fp_mant[0] = FP_1;
}
-
- while ((0 <= regnum) && (regnum < 8)) {
- regmask = 1 << regnum;
- if (regmask & reglist) {
- if (fpu_to_mem)
- sig = store_ea(frame, insn, &insn->ea0,
- (char*) &fpregs[regnum]);
- else /* mem to fpu */
- sig = load_ea(frame, insn, &insn->ea0,
- (char*) &fpregs[regnum]);
- if (sig) break;
- }
- regnum += order;
+ } else if (y->fp_class == FPC_INF) {
+ /* x is a Num but y is an Inf */
+ /* return a forged number w/y's sign inverted */
+ x->fp_class = FPC_NUM;
+ x->fp_sign = !y->fp_sign;
+ x->fp_exp = 16383;
+ x->fp_mant[0] = FP_1;
+ } else {
+ /* x and y are both numbers or zeros, or pair of a number and a zero */
+ y->fp_sign = !y->fp_sign;
+ x = fpu_add(fe); /* (x - y) */
+ /*
+ * FCMP does not set Inf bit in CC, so return a forged number
+ * (value doesn't matter) if Inf is the result of fsub.
+ */
+ if (x->fp_class == FPC_INF) {
+ x->fp_class = FPC_NUM;
+ x->fp_exp = 16383;
+ x->fp_mant[0] = FP_1;
}
-
- return 0;
-}
-
-int fpu_emul_type0(struct frame *frame,
- struct fpframe *fpf,
- struct instruction *insn)
-{
- int sig;
-
- /* Get effective address */
- /* XXX */
-
- switch(insn->word1 & 0x3F) {
-
- case 0x00: /* fmove */
-
- case 0x01: /* fint */
- case 0x02: /* fsinh */
- case 0x03: /* fintrz */
- case 0x04: /* fsqrt */
- case 0x06: /* flognp1 */
-
- case 0x09: /* ftanh */
- case 0x0A: /* fatan */
- case 0x0C: /* fasin */
- case 0x0D: /* fatanh */
- case 0x0E: /* fsin */
- case 0x0F: /* ftan */
-
- case 0x10: /* fetox */
- case 0x11: /* ftwotox */
- case 0x12: /* ftentox */
- case 0x14: /* flogn */
- case 0x15: /* flog10 */
- case 0x16: /* flog2 */
-
- case 0x18: /* fabs */
- case 0x19: /* fcosh */
- case 0x1A: /* fneg */
- case 0x1C: /* facos */
- case 0x1D: /* fcos */
- case 0x1E: /* fgetexp */
- case 0x1F: /* fgetman */
-
- case 0x20: /* fdiv */
- case 0x21: /* fmod */
- case 0x22: /* fadd */
- case 0x23: /* fmul */
- case 0x24: /* fsgldiv */
- case 0x25: /* frem */
- case 0x26: /* fscale */
- case 0x27: /* fsglmul */
-
- case 0x28: /* fsub */
- case 0x38: /* fcmp */
- case 0x3A: /* ftst */
-
- default:
-#ifdef DEBUG
- printf("fpu_emul_type0: unknown: opcode=0x%x, word1=0x%x\n",
- insn->opcode, insn->word1);
-#endif
- sig = SIGILL;
-
- } /* switch */
- return (sig);
+ }
+ return x;
}
/*
- * type 1: fdbcc, fscc, ftrapcc
- * In this function, we know:
- * (opcode & 0x01C0) == 0x0040
+ * arithmetic oprations
*/
-int fpu_emul_type1(struct frame *frame,
- struct fpframe *fpf,
- struct instruction *insn)
+static int
+fpu_emul_arith(fe, insn)
+ struct fpemu *fe;
+ struct instruction *insn;
{
- int sig;
-
- /* Get effective address */
- /* XXX */
-
- switch (insn->opcode & 070) {
+ struct frame *frame = fe->fe_frame;
+ u_int *fpregs = &(fe->fe_fpframe->fpf_regs[0]);
+ struct fpn *res;
+ int word1, sig = 0;
+ int regnum, format;
+ int discard_result = 0;
+ u_int buf[3];
+ int flags;
+ char regname;
+
+ DUMP_INSN(insn);
+
+ if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: FPSR = %08x, FPCR = %08x\n",
+ fe->fe_fpsr, fe->fe_fpcr);
+ }
+
+ word1 = insn->is_word1;
+ format = (word1 >> 10) & 7;
+ regnum = (word1 >> 7) & 7;
+
+ /* fetch a source operand : may not be used */
+ if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: dst/src FP%d=%08x,%08x,%08x\n",
+ regnum, fpregs[regnum*3], fpregs[regnum*3+1],
+ fpregs[regnum*3+2]);
+ }
+ fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &fpregs[regnum * 3]);
+
+ DUMP_INSN(insn);
+
+ /* get the other operand which is always the source */
+ if ((word1 & 0x4000) == 0) {
+ if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: FP%d op FP%d => FP%d\n",
+ format, regnum, regnum);
+ printf(" fpu_emul_arith: src opr FP%d=%08x,%08x,%08x\n",
+ format, fpregs[format*3], fpregs[format*3+1],
+ fpregs[format*3+2]);
+ }
+ fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
+ } else {
+ /* the operand is in memory */
+ if (format == FTYPE_DBL) {
+ insn->is_datasize = 8;
+ } else if (format == FTYPE_SNG || format == FTYPE_LNG) {
+ insn->is_datasize = 4;
+ } else if (format == FTYPE_WRD) {
+ insn->is_datasize = 2;
+ } else if (format == FTYPE_BYT) {
+ insn->is_datasize = 1;
+ } else if (format == FTYPE_EXT) {
+ insn->is_datasize = 12;
+ } else {
+ /* invalid or unsupported operand format */
+ sig = SIGFPE;
+ return sig;
+ }
- case 010: /* fdbcc */
- /* XXX: If not CC { Decrement Dn; if (Dn >= 0) branch; } */
+ /* Get effective address. (modreg=opcode&077) */
+ sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
+ if (sig) {
+ if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: error in fpu_decode_ea\n");
+ }
+ return sig;
+ }
- case 070: /* fscc or ftrapcc */
- if ((insn->opcode & 07) > 1) {
- /* ftrapcc */
- /* XXX: If CC, advance and return SIGFPE */
- break;
+ DUMP_INSN(insn);
+
+ if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: addr mode = ");
+ flags = insn->is_ea0.ea_flags;
+ regname = (insn->is_ea0.ea_regnum & 8) ? 'a' : 'd';
+
+ if (flags & EA_DIRECT) {
+ printf("%c%d\n",
+ regname, insn->is_ea0.ea_regnum & 7);
+ } else if (flags & EA_PC_REL) {
+ if (flags & EA_OFFSET) {
+ printf("pc@(%d)\n", insn->is_ea0.ea_offset);
+ } else if (flags & EA_INDEXED) {
+ printf("pc@(...)\n");
}
- /* fallthrough */
- default: /* fscc */
- /* XXX: If CC, store ones, else store zero */
- sig = SIGILL;
- break;
-
+ } else if (flags & EA_PREDECR) {
+ printf("%c%d@-\n",
+ regname, insn->is_ea0.ea_regnum & 7);
+ } else if (flags & EA_POSTINCR) {
+ printf("%c%d@+\n", regname, insn->is_ea0.ea_regnum & 7);
+ } else if (flags & EA_OFFSET) {
+ printf("%c%d@(%d)\n", regname, insn->is_ea0.ea_regnum & 7,
+ insn->is_ea0.ea_offset);
+ } else if (flags & EA_INDEXED) {
+ printf("%c%d@(...)\n", regname, insn->is_ea0.ea_regnum & 7);
+ } else if (flags & EA_ABS) {
+ printf("0x%08x\n", insn->is_ea0.ea_absaddr);
+ } else if (flags & EA_IMMED) {
+
+ printf("#0x%08x,%08x,%08x\n", insn->is_ea0.ea_immed[0],
+ insn->is_ea0.ea_immed[1], insn->is_ea0.ea_immed[2]);
+ } else {
+ printf("%c%d@\n", regname, insn->is_ea0.ea_regnum & 7);
+ }
+ } /* if (fpu_debug_level & DL_ARITH) */
+
+ fpu_load_ea(frame, insn, &insn->is_ea0, (char*)buf);
+ if (format == FTYPE_WRD) {
+ /* sign-extend */
+ buf[0] &= 0xffff;
+ if (buf[0] & 0x8000) {
+ buf[0] |= 0xffff0000;
+ }
+ format = FTYPE_LNG;
+ } else if (format == FTYPE_BYT) {
+ /* sign-extend */
+ buf[0] &= 0xff;
+ if (buf[0] & 0x80) {
+ buf[0] |= 0xffffff00;
+ }
+ format = FTYPE_LNG;
}
- return (sig);
-}
-
-/*
- * Type 2 or 3: fbcc (also fnop)
- * In this function, we know:
- * (opcode & 0x0180) == 0x0080
- */
-int fpu_emul_brcc(struct frame *frame,
- struct fpframe *fpf,
- struct instruction *insn)
-{
- int displ, word2;
- int sig, advance;
-
- /*
- * Get branch displacement.
- */
- advance = 4;
- displ = insn->word1;
- if (displ & 0x8000)
- displ |= 0xFFFF0000;
-
- if (insn->opcode & 0x40) {
- word2 = fusword(frame->f_pc + 4);
- if (word2 < 0) {
-#ifdef DEBUG
- printf("fpu_emul_brcc: fault reading word2\n");
+ if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: src = %08x %08x %08x, siz = %d\n",
+ buf[0], buf[1], buf[2], insn->is_datasize);
+ }
+ fpu_explode(fe, &fe->fe_f2, format, buf);
+ }
+
+ DUMP_INSN(insn);
+
+ /* An arithmetic instruction emulate function has a prototype of
+ * struct fpn *fpu_op(struct fpemu *);
+
+ * 1) If the instruction is monadic, then fpu_op() must use
+ * fe->fe_f2 as its operand, and return a pointer to the
+ * result.
+
+ * 2) If the instruction is diadic, then fpu_op() must use
+ * fe->fe_f1 and fe->fe_f2 as its two operands, and return a
+ * pointer to the result.
+
+ */
+ switch (word1 & 0x3f) {
+ case 0x00: /* fmove */
+ res = &fe->fe_f2;
+ break;
+
+ case 0x01: /* fint */
+ res = fpu_int(fe);
+ break;
+
+ case 0x02: /* fsinh */
+ res = fpu_sinh(fe);
+ break;
+
+ case 0x03: /* fintrz */
+ res = fpu_intrz(fe);
+ break;
+
+ case 0x04: /* fsqrt */
+ res = fpu_sqrt(fe);
+ break;
+
+ case 0x06: /* flognp1 */
+ res = fpu_lognp1(fe);
+ break;
+
+ case 0x08: /* fetoxm1 */
+ res = fpu_etoxm1(fe);
+ break;
+
+ case 0x09: /* ftanh */
+ res = fpu_tanh(fe);
+ break;
+
+ case 0x0A: /* fatan */
+ res = fpu_atan(fe);
+ break;
+
+ case 0x0C: /* fasin */
+ res = fpu_asin(fe);
+ break;
+
+ case 0x0D: /* fatanh */
+ res = fpu_atanh(fe);
+ break;
+
+ case 0x0E: /* fsin */
+ res = fpu_sin(fe);
+ break;
+
+ case 0x0F: /* ftan */
+ res = fpu_tan(fe);
+ break;
+
+ case 0x10: /* fetox */
+ res = fpu_etox(fe);
+ break;
+
+ case 0x11: /* ftwotox */
+ res = fpu_twotox(fe);
+ break;
+
+ case 0x12: /* ftentox */
+ res = fpu_tentox(fe);
+ break;
+
+ case 0x14: /* flogn */
+ res = fpu_logn(fe);
+ break;
+
+ case 0x15: /* flog10 */
+ res = fpu_log10(fe);
+ break;
+
+ case 0x16: /* flog2 */
+ res = fpu_log2(fe);
+ break;
+
+ case 0x18: /* fabs */
+ fe->fe_f2.fp_sign = 0;
+ res = &fe->fe_f2;
+ break;
+
+ case 0x19: /* fcosh */
+ res = fpu_cosh(fe);
+ break;
+
+ case 0x1A: /* fneg */
+ fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
+ res = &fe->fe_f2;
+ break;
+
+ case 0x1C: /* facos */
+ res = fpu_acos(fe);
+ break;
+
+ case 0x1D: /* fcos */
+ res = fpu_cos(fe);
+ break;
+
+ case 0x1E: /* fgetexp */
+ res = fpu_getexp(fe);
+ break;
+
+ case 0x1F: /* fgetman */
+ res = fpu_getman(fe);
+ break;
+
+ case 0x20: /* fdiv */
+ case 0x24: /* fsgldiv: cheating - better than nothing */
+ res = fpu_div(fe);
+ break;
+
+ case 0x21: /* fmod */
+ res = fpu_mod(fe);
+ break;
+
+ case 0x28: /* fsub */
+ fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
+ case 0x22: /* fadd */
+ res = fpu_add(fe);
+ break;
+
+ case 0x23: /* fmul */
+ case 0x27: /* fsglmul: cheating - better than nothing */
+ res = fpu_mul(fe);
+ break;
+
+ case 0x25: /* frem */
+ res = fpu_rem(fe);
+ break;
+
+ case 0x26:
+ /* fscale is handled by a separate function */
+ break;
+
+ case 0x30:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37: /* fsincos */
+ res = fpu_sincos(fe, word1 & 7);
+ break;
+
+ case 0x38: /* fcmp */
+ res = fpu_cmp(fe);
+ discard_result = 1;
+ break;
+
+ case 0x3A: /* ftst */
+ res = &fe->fe_f2;
+ discard_result = 1;
+ break;
+
+ default:
+#ifdef DEBUG
+ printf(" fpu_emul_arith: bad opcode=0x%x, word1=0x%x\n",
+ insn->is_opcode, insn->is_word1);
#endif
- return SIGSEGV;
- }
- displ << 16;
- displ |= word2;
- advance += 2;
+ sig = SIGILL;
+ } /* switch (word1 & 0x3f) */
+
+ if (!discard_result && sig == 0) {
+ fpu_implode(fe, res, FTYPE_EXT, &fpregs[regnum * 3]);
+ if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: %08x,%08x,%08x stored in FP%d\n",
+ fpregs[regnum*3], fpregs[regnum*3+1],
+ fpregs[regnum*3+2], regnum);
}
-
- /* XXX: If CC, frame->f_pc += displ */
- return SIGILL;
+ } else if (sig == 0 && fpu_debug_level & DL_ARITH) {
+ static char *class_name[] = { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
+ printf(" fpu_emul_arith: result(%s,%c,%d,%08x,%08x,%08x,%08x) discarded\n",
+ class_name[res->fp_class + 2],
+ res->fp_sign ? '-' : '+', res->fp_exp,
+ res->fp_mant[0], res->fp_mant[1],
+ res->fp_mant[2], res->fp_mant[3]);
+ } else if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: received signal %d\n", sig);
+ }
+
+ /* update fpsr according to the result of operation */
+ fpu_upd_fpsr(fe, res);
+
+ if (fpu_debug_level & DL_ARITH) {
+ printf(" fpu_emul_arith: FPSR = %08x, FPCR = %08x\n",
+ fe->fe_fpsr, fe->fe_fpcr);
+ }
+
+ DUMP_INSN(insn);
+
+ return sig;
}
-/*
- * Helper routines for dealing with "effective address" values.
- */
-
-/*
- * Decode an effective address into internal form.
- * Returns zero on success, else signal number.
+/* test condition code according to the predicate in the opcode.
+ * returns -1 when the predicate evaluates to true, 0 when false.
+ * signal numbers are returned when an error is detected.
*/
-static int decode_ea(struct frame *frame,
- struct instruction *insn,
- struct insn_ea *ea,
- int modreg)
+static int
+test_cc(fe, pred)
+ struct fpemu *fe;
+ int pred;
{
- int immed_bytes = 0;
- int data;
-
- /* Set the most common value here. */
- ea->regnum = 8 + (modreg & 7);
-
- switch (modreg & 070) {
-
- case 0: /* Dn */
- ea->regnum = (modreg & 7);
- ea->flags = EA_DIRECT;
- break;
-
- case 010: /* An */
- ea->flags = EA_DIRECT;
- break;
-
- case 020: /* (An) */
- ea->flags = 0;
- break;
-
- case 030: /* (An)+ */
- ea->flags = EA_POSTINCR;
- break;
-
- case 040: /* -(An) */
- ea->flags = EA_PREDECR;
- break;
-
- case 050: /* (d16,An) */
- ea->flags = EA_OFFSET;
- immed_bytes = 2;
- break;
-
- case 060: /* (d8,An,Xn) */
- ea->flags = EA_INDEXED;
- immed_bytes = 2;
- break;
+ int result, sig_bsun, invert;
+ int fpsr;
+
+ fpsr = fe->fe_fpsr;
+ invert = 0;
+ fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf(" test_cc: fpsr=0x%08x\n", fpsr);
+ }
+ pred &= 0x3f; /* lowest 6 bits */
+
+ if (fpu_debug_level & DL_TESTCC) {
+ printf(" test_cc: ");
+ }
+
+ if (pred >= 040) {
+ return SIGILL;
+ } else if (pred & 0x10) {
+ /* IEEE nonaware tests */
+ sig_bsun = 1;
+ pred &= 017; /* lower 4 bits */
+ } else {
+ /* IEEE aware tests */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("IEEE ");
+ }
+ sig_bsun = 0;
+ }
- case 070: /* misc. */
- ea->regnum = (modreg & 7);
- switch (modreg & 7) {
-
- case 0: /* (xxxx).W */
- ea->flags = EA_ABS;
- immed_bytes = 2;
- break;
-
- case 1: /* (xxxxxxxx).L */
- ea->flags = EA_ABS;
- immed_bytes = 4;
- break;
-
- case 2: /* (d16,PC) */
- ea->flags = EA_PC_REL | EA_OFFSET;
- immed_bytes = 2;
- break;
-
- case 3: /* (d8,PC,Xn) */
- ea->flags = EA_PC_REL | EA_INDEXED;
- immed_bytes = 2;
- break;
-
- case 4: /* #data */
- ea->flags = EA_IMMED;
- immed_bytes = insn->datasize;
- break;
-
- default:
- return SIGILL;
- } /* switch for mode 7 */
- break;
- } /* switch mode */
-
- /* Now fetch any immediate data and advance. */
- if (immed_bytes > 0) {
- data = fusword(frame->f_pc + insn->advance);
- if (data < 0)
- return SIGSEGV;
- insn->advance += 2;
- if (data & 0x8000)
- data |= 0xFFFF0000;
- ea->immed = data;
+ if (pred >= 010) {
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("Not ");
+ }
+ /* predicate is "NOT ..." */
+ pred ^= 0xf; /* invert */
+ invert = -1;
+ }
+ switch (pred) {
+ case 0: /* (Signaling) False */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("False");
+ }
+ result = 0;
+ break;
+ case 1: /* (Signaling) Equal */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("Equal");
+ }
+ result = -((fpsr & FPSR_ZERO) == FPSR_ZERO);
+ break;
+ case 2: /* Greater Than */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("GT");
+ }
+ result = -((fpsr & (FPSR_NAN|FPSR_ZERO|FPSR_NEG)) == 0);
+ break;
+ case 3: /* Greater or Equal */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("GE");
+ }
+ result = -((fpsr & FPSR_ZERO) ||
+ (fpsr & (FPSR_NAN|FPSR_NEG)) == 0);
+ break;
+ case 4: /* Less Than */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("LT");
}
- if (immed_bytes > 2) {
- data = fusword(frame->f_pc + insn->advance);
- if (data < 0)
- return SIGSEGV;
- insn->advance += 2;
- ea->immed <<= 16;
- ea->immed |= data;
+ result = -((fpsr & (FPSR_NAN|FPSR_ZERO|FPSR_NEG)) == FPSR_NEG);
+ break;
+ case 5: /* Less or Equal */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("LE");
}
- return 0;
+ result = -((fpsr & FPSR_ZERO) ||
+ ((fpsr & (FPSR_NAN|FPSR_NEG)) == FPSR_NEG));
+ break;
+ case 6: /* Greater or Less than */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("GLT");
+ }
+ result = -((fpsr & (FPSR_NAN|FPSR_ZERO)) == 0);
+ break;
+ case 7: /* Greater, Less or Equal */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf("GLE");
+ }
+ result = -((fpsr & FPSR_NAN) == 0);
+ break;
+ default:
+ /* invalid predicate */
+ return SIGILL;
+ }
+ result ^= invert; /* if the predicate is "NOT ...", then
+ invert the result */
+ if (fpu_debug_level & DL_TESTCC) {
+ printf(" => %s (%d)\n", result ? "true" : "false", result);
+ }
+ /* if it's an IEEE unaware test and NAN is set, BSUN is set */
+ if (sig_bsun && (fpsr & FPSR_NAN)) {
+ fpsr |= FPSR_BSUN;
+ }
+
+ /* put fpsr back */
+ fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
+
+ return result;
}
-
/*
- * Load a value from an effective address.
- * Returns zero on success, else signal number.
+ * type 1: fdbcc, fscc, ftrapcc
+ * In this function, we know:
+ * (opcode & 0x01C0) == 0x0040
*/
-static int load_ea(struct frame *frame,
- struct instruction *insn,
- struct insn_ea *ea,
- char *dst)
+static int
+fpu_emul_type1(fe, insn)
+ struct fpemu *fe;
+ struct instruction *insn;
{
- int *reg;
- char *src;
- int len;
-
-#ifdef DIAGNOSTIC
- if (ea->regnum & ~0xF)
- panic("load_ea: bad regnum");
+ struct frame *frame = fe->fe_frame;
+ struct fpframe *fpf = fe->fe_fpframe;
+ int advance, sig, branch, displ;
+
+ branch = test_cc(fe, insn->is_word1);
+ fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
+
+ insn->is_advance = 4;
+ sig = 0;
+
+ switch (insn->is_opcode & 070) {
+ case 010: /* fdbcc */
+ if (branch == -1) {
+ /* advance */
+ insn->is_advance = 6;
+ } else if (!branch) {
+ /* decrement Dn and if (Dn != -1) branch */
+ u_int16_t count = frame->f_regs[insn->is_opcode & 7];
+
+ if (count-- != 0) {
+ displ = fusword(frame->f_pc + insn->is_advance);
+ if (displ < 0) {
+#ifdef DEBUG
+ printf(" fpu_emul_type1: fault reading displacement\n");
#endif
+ return SIGSEGV;
+ }
+ /* sign-extend the displacement */
+ displ &= 0xffff;
+ if (displ & 0x8000) {
+ displ |= 0xffff0000;
+ }
+ insn->is_advance += displ;
+ } else {
+ insn->is_advance = 6;
+ }
+ /* write it back */
+ frame->f_regs[insn->is_opcode & 7] &= 0xffff0000;
+ frame->f_regs[insn->is_opcode & 7] |= (u_int32_t)count;
+ } else { /* got a signal */
+ sig = SIGFPE;
+ }
+ break;
- /* The dst is always int or larger. */
- len = insn->datasize;
- if (len < 4)
- dst += (4 - len);
-
- /* point to the register */
- if (ea->flags & EA_PC_REL)
- reg = &frame->f_pc;
- else
- reg = &frame->f_regs[ea->regnum];
-
- if (ea->flags & (EA_DIRECT | EA_IMMED)) {
- if (ea->flags & EA_DIRECT)
- src = (char*) reg;
- if (ea->flags & EA_IMMED)
- src = (char*) &ea->immed;
- if (len > 4)
- return SIGILL;
- /* The source is an int. */
- if (len < 4)
- src += (4 - len);
- bcopy(src, dst, len);
+ case 070: /* ftrapcc or fscc */
+ advance = 4;
+ if ((insn->is_opcode & 07) >= 2) {
+ switch (insn->is_opcode & 07) {
+ case 3: /* long opr */
+ advance += 2;
+ case 2: /* word opr */
+ advance += 2;
+ case 4: /* no opr */
+ break;
+ default:
+ return SIGILL;
+ break;
+ }
+
+ if (branch == 0) {
+ /* no trap */
+ insn->is_advance = advance;
+ sig = 0;
+ } else {
+ /* trap */
+ sig = SIGFPE;
+ }
+ break;
+ } /* if ((insn->is_opcode & 7) < 2), fall through to FScc */
+
+ default: /* fscc */
+ insn->is_advance = 4;
+ insn->is_datasize = 1; /* always byte */
+ sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
+ if (sig) {
+ break;
+ }
+ if (branch == -1 || branch == 0) {
+ /* set result */
+ sig = fpu_store_ea(frame, insn, &insn->is_ea0, (char *)&branch);
} else {
- /* One of MANY indirect forms... */
-
- /* do pre-decrement */
- if (ea->flags & EA_PREDECR)
- *reg -= len;
-
- /* Grab the register contents. */
- src = (char*) *reg;
-
- /* apply the signed offset */
- if (ea->flags & EA_OFFSET)
- src += ea->immed;
-
- /* XXX - Don't know how to handle this yet. */
- if (ea->flags & EA_INDEXED)
- return SIGILL;
-
- copyin(src, dst, len);
-
- /* do post-increment */
- if (ea->flags & EA_POSTINCR)
- *reg += len;
+ /* got an exception */
+ sig = branch;
}
-
- return 0;
+ break;
+ }
+ return sig;
}
/*
- * Store a value at the effective address.
- * Returns zero on success, else signal number.
+ * Type 2 or 3: fbcc (also fnop)
+ * In this function, we know:
+ * (opcode & 0x0180) == 0x0080
*/
-static int store_ea(struct frame *frame,
- struct instruction *insn,
- struct insn_ea *ea,
- char *src)
+static int
+fpu_emul_brcc(fe, insn)
+ struct fpemu *fe;
+ struct instruction *insn;
{
- int *reg;
- char *dst;
- int len;
-
-#ifdef DIAGNOSTIC
- if (ea->regnum & ~0xF)
- panic("load_ea: bad regnum");
+ struct frame *frame = fe->fe_frame;
+ struct fpframe *fpf = fe->fe_fpframe;
+ int displ, word2;
+ int sig, advance;
+
+ /*
+ * Get branch displacement.
+ */
+ insn->is_advance = 4;
+ displ = insn->is_word1;
+
+ if (insn->is_opcode & 0x40) {
+ word2 = fusword(frame->f_pc + insn->is_advance);
+ if (word2 < 0) {
+#ifdef DEBUG
+ printf(" fpu_emul_brcc: fault reading word2\n");
#endif
-
- /* The src is always int or larger. */
- len = insn->datasize;
- if (len < 4)
- src += (4 - len);
-
- /* point to the register */
- if (ea->flags & EA_PC_REL)
- reg = &frame->f_pc;
- else
- reg = &frame->f_regs[ea->regnum];
-
- if (ea->flags & EA_IMMED)
- return SIGILL;
-
- if (ea->flags & EA_DIRECT) {
- dst = (char*) reg;
- if (len > 4)
- return SIGILL;
- /* The destination is an int. */
- if (len < 4)
- dst += (4 - len);
- bcopy(src, dst, len);
- } else {
- /* One of MANY indirect forms... */
-
- /* do pre-decrement */
- if (ea->flags & EA_PREDECR)
- *reg -= len;
-
- /* Grab the register contents. */
- dst = (char*) *reg;
-
- /* apply the signed offset */
- if (ea->flags & EA_OFFSET)
- dst += ea->immed;
-
- /* XXX - Don't know how to handle this yet. */
- if (ea->flags & EA_INDEXED)
- return SIGILL;
-
- copyout(src, dst, len);
-
- /* do post-increment */
- if (ea->flags & EA_POSTINCR)
- *reg += len;
+ return SIGSEGV;
}
-
- return 0;
+ displ <<= 16;
+ displ |= word2;
+ insn->is_advance += 2;
+ } else /* displacement is word sized */
+ if (displ & 0x8000)
+ displ |= 0xFFFF0000;
+
+ /* XXX: If CC, frame->f_pc += displ */
+ sig = test_cc(fe, insn->is_opcode);
+ fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
+
+ if (fe->fe_fpsr & fe->fe_fpcr & FPSR_EXCP) {
+ return SIGFPE; /* caught an exception */
+ }
+ if (sig == -1) {
+ /* branch does take place; 2 is the offset to the 1st disp word */
+ insn->is_advance = displ + 2;
+ } else if (sig) {
+ return SIGILL; /* got a signal */
+ }
+ if (fpu_debug_level & DL_BRANCH) {
+ printf(" fpu_emul_brcc: %s insn @ %x (%x+%x) (disp=%x)\n",
+ (sig == -1) ? "BRANCH to" : "NEXT",
+ frame->f_pc + insn->is_advance, frame->f_pc, insn->is_advance,
+ displ);
+ }
+ return 0;
}
--- /dev/null
+/* $NetBSD: fpu_emulate.h,v 1.2 1995/11/05 00:35:20 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Gordon Ross
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gordon Ross
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FPU_EMULATE_H_
+#define _FPU_EMULATE_H_
+
+#include <sys/types.h>
+
+/*
+ * Floating point emulator (tailored for SPARC/modified for m68k, but
+ * structurally machine-independent).
+ *
+ * Floating point numbers are carried around internally in an `expanded'
+ * or `unpacked' form consisting of:
+ * - sign
+ * - unbiased exponent
+ * - mantissa (`1.' + 112-bit fraction + guard + round)
+ * - sticky bit
+ * Any implied `1' bit is inserted, giving a 113-bit mantissa that is
+ * always nonzero. Additional low-order `guard' and `round' bits are
+ * scrunched in, making the entire mantissa 115 bits long. This is divided
+ * into four 32-bit words, with `spare' bits left over in the upper part
+ * of the top word (the high bits of fp_mant[0]). An internal `exploded'
+ * number is thus kept within the half-open interval [1.0,2.0) (but see
+ * the `number classes' below). This holds even for denormalized numbers:
+ * when we explode an external denorm, we normalize it, introducing low-order
+ * zero bits, so that the rest of the code always sees normalized values.
+ *
+ * Note that a number of our algorithms use the `spare' bits at the top.
+ * The most demanding algorithm---the one for sqrt---depends on two such
+ * bits, so that it can represent values up to (but not including) 8.0,
+ * and then it needs a carry on top of that, so that we need three `spares'.
+ *
+ * The sticky-word is 32 bits so that we can use `OR' operators to goosh
+ * whole words from the mantissa into it.
+ *
+ * All operations are done in this internal extended precision. According
+ * to Hennesey & Patterson, Appendix A, rounding can be repeated---that is,
+ * it is OK to do a+b in extended precision and then round the result to
+ * single precision---provided single, double, and extended precisions are
+ * `far enough apart' (they always are), but we will try to avoid any such
+ * extra work where possible.
+ */
+struct fpn {
+ int fp_class; /* see below */
+ int fp_sign; /* 0 => positive, 1 => negative */
+ int fp_exp; /* exponent (unbiased) */
+ int fp_sticky; /* nonzero bits lost at right end */
+ u_int fp_mant[4]; /* 115-bit mantissa */
+};
+
+#define FP_NMANT 115 /* total bits in mantissa (incl g,r) */
+#define FP_NG 2 /* number of low-order guard bits */
+#define FP_LG ((FP_NMANT - 1) & 31) /* log2(1.0) for fp_mant[0] */
+#define FP_QUIETBIT (1 << (FP_LG - 1)) /* Quiet bit in NaNs (0.5) */
+#define FP_1 (1 << FP_LG) /* 1.0 in fp_mant[0] */
+#define FP_2 (1 << (FP_LG + 1)) /* 2.0 in fp_mant[0] */
+
+#define CPYFPN(dst, src) \
+if ((dst) != (src)) { \
+ (dst)->fp_class = (src)->fp_class; \
+ (dst)->fp_sign = (src)->fp_sign; \
+ (dst)->fp_exp = (src)->fp_exp; \
+ (dst)->fp_sticky = (src)->fp_sticky; \
+ (dst)->fp_mant[0] = (src)->fp_mant[0]; \
+ (dst)->fp_mant[1] = (src)->fp_mant[1]; \
+ (dst)->fp_mant[2] = (src)->fp_mant[2]; \
+ (dst)->fp_mant[3] = (src)->fp_mant[3]; \
+}
+
+/*
+ * Number classes. Since zero, Inf, and NaN cannot be represented using
+ * the above layout, we distinguish these from other numbers via a class.
+ */
+#define FPC_SNAN -2 /* signalling NaN (sign irrelevant) */
+#define FPC_QNAN -1 /* quiet NaN (sign irrelevant) */
+#define FPC_ZERO 0 /* zero (sign matters) */
+#define FPC_NUM 1 /* number (sign matters) */
+#define FPC_INF 2 /* infinity (sign matters) */
+
+#define ISNAN(fp) ((fp)->fp_class < 0)
+#define ISZERO(fp) ((fp)->fp_class == 0)
+#define ISINF(fp) ((fp)->fp_class == FPC_INF)
+
+/*
+ * ORDER(x,y) `sorts' a pair of `fpn *'s so that the right operand (y) points
+ * to the `more significant' operand for our purposes. Appendix N says that
+ * the result of a computation involving two numbers are:
+ *
+ * If both are SNaN: operand 2, converted to Quiet
+ * If only one is SNaN: the SNaN operand, converted to Quiet
+ * If both are QNaN: operand 2
+ * If only one is QNaN: the QNaN operand
+ *
+ * In addition, in operations with an Inf operand, the result is usually
+ * Inf. The class numbers are carefully arranged so that if
+ * (unsigned)class(op1) > (unsigned)class(op2)
+ * then op1 is the one we want; otherwise op2 is the one we want.
+ */
+#define ORDER(x, y) { \
+ if ((u_int)(x)->fp_class > (u_int)(y)->fp_class) \
+ SWAP(x, y); \
+}
+#define SWAP(x, y) { \
+ register struct fpn *swap; \
+ swap = (x), (x) = (y), (y) = swap; \
+}
+
+/*
+ * Emulator state.
+ */
+struct fpemu {
+ struct frame *fe_frame; /* integer regs, etc */
+ struct fpframe *fe_fpframe; /* FP registers, etc */
+ u_int fe_fpsr; /* fpsr copy (modified during op) */
+ u_int fe_fpcr; /* fpcr copy */
+ struct fpn fe_f1; /* operand 1 */
+ struct fpn fe_f2; /* operand 2, if required */
+ struct fpn fe_f3; /* available storage for result */
+};
+
+/*****************************************************************************
+ * End of definitions derived from Sparc FPE
+ *****************************************************************************/
+
+/*
+ * Internal info about a decoded effective address.
+ */
+struct insn_ea {
+ int ea_regnum;
+ int ea_ext[3]; /* extention words if any */
+ int ea_flags; /* flags == 0 means mode 2: An@ */
+#define EA_DIRECT 0x001 /* mode [01]: Dn or An */
+#define EA_PREDECR 0x002 /* mode 4: An@- */
+#define EA_POSTINCR 0x004 /* mode 3: An@+ */
+#define EA_OFFSET 0x008 /* mode 5 or (7,2): APC@(d16) */
+#define EA_INDEXED 0x010 /* mode 6 or (7,3): APC@(Xn:*:*,d8) etc */
+#define EA_ABS 0x020 /* mode (7,[01]): abs */
+#define EA_PC_REL 0x040 /* mode (7,[23]): PC@(d16) etc */
+#define EA_IMMED 0x080 /* mode (7,4): #immed */
+#define EA_MEM_INDIR 0x100 /* mode 6 or (7,3): APC@(Xn:*:*,*)@(*) etc */
+#define EA_BASE_SUPPRSS 0x200 /* mode 6 or (7,3): base register suppressed */
+ int ea_tdisp; /* temp. displ. used to xfer many words */
+};
+
+#define ea_offset ea_ext[0] /* mode 5: offset word */
+#define ea_absaddr ea_ext[0] /* mode (7,[01]): absolute address */
+#define ea_immed ea_ext /* mode (7,4): immediate value */
+#define ea_basedisp ea_ext[0] /* mode 6: base displacement */
+#define ea_outerdisp ea_ext[1] /* mode 6: outer displacement */
+#define ea_idxreg ea_ext[2] /* mode 6: index register number */
+
+struct instruction {
+ int is_advance; /* length of instruction */
+ int is_datasize; /* byte, word, long, float, double, ... */
+ int is_opcode; /* opcode word */
+ int is_word1; /* second word */
+ struct insn_ea is_ea0; /* decoded effective address mode */
+};
+
+/*
+ * FP data types
+ */
+#define FTYPE_LNG 0 /* Long Word Integer */
+#define FTYPE_SNG 1 /* Single Prec */
+#define FTYPE_EXT 2 /* Extended Prec */
+#define FTYPE_BCD 3 /* Packed BCD */
+#define FTYPE_WRD 4 /* Word Integer */
+#define FTYPE_DBL 5 /* Double Prec */
+#define FTYPE_BYT 6 /* Byte Integer */
+
+/*
+ * MC68881/68882 FPcr bit definitions (should these go to <m68k/reg.h>
+ * or <m68k/fpu.h> or something?)
+ */
+
+/* fpsr */
+#define FPSR_CCB 0xff000000
+# define FPSR_NEG 0x08000000
+# define FPSR_ZERO 0x04000000
+# define FPSR_INF 0x02000000
+# define FPSR_NAN 0x01000000
+#define FPSR_QTT 0x00ff0000
+# define FPSR_QSG 0x00800000
+# define FPSR_QUO 0x007f0000
+#define FPSR_EXCP 0x0000ff00
+# define FPSR_BSUN 0x00008000
+# define FPSR_SNAN 0x00004000
+# define FPSR_OPERR 0x00002000
+# define FPSR_OVFL 0x00001000
+# define FPSR_UNFL 0x00000800
+# define FPSR_DZ 0x00000400
+# define FPSR_INEX2 0x00000200
+# define FPSR_INEX1 0x00000100
+#define FPSR_AEX 0x000000ff
+# define FPSR_AIOP 0x00000080
+# define FPSR_AOVFL 0x00000040
+# define FPSR_AUNFL 0x00000020
+# define FPSR_ADZ 0x00000010
+# define FPSR_AINEX 0x00000008
+
+/* fpcr */
+#define FPCR_EXCP FPSR_EXCP
+# define FPCR_BSUN FPSR_BSUN
+# define FPCR_SNAN FPSR_SNAN
+# define FPCR_OPERR FPSR_OPERR
+# define FPCR_OVFL FPSR_OVFL
+# define FPCR_UNFL FPSR_UNFL
+# define FPCR_DZ FPSR_DZ
+# define FPCR_INEX2 FPSR_INEX2
+# define FPCR_INEX1 FPSR_INEX1
+#define FPCR_MODE 0x000000ff
+# define FPCR_PREC 0x000000c0
+# define FPCR_EXTD 0x00000000
+# define FPCR_SNGL 0x00000040
+# define FPCR_DBL 0x00000080
+# define FPCR_ROUND 0x00000030
+# define FPCR_NEAR 0x00000000
+# define FPCR_ZERO 0x00000010
+# define FPCR_MINF 0x00000020
+# define FPCR_PINF 0x00000030
+
+/*
+ * Other functions.
+ */
+
+/* Build a new Quiet NaN (sign=0, frac=all 1's). */
+struct fpn *fpu_newnan __P((struct fpemu *fe));
+
+/*
+ * Shift a number right some number of bits, taking care of round/sticky.
+ * Note that the result is probably not a well-formed number (it will lack
+ * the normal 1-bit mant[0]&FP_1).
+ */
+int fpu_shr __P((struct fpn * fp, int shr));
+/*
+ * Round a number according to the round mode in FPCR
+ */
+int round __P((register struct fpemu *fe, register struct fpn *fp));
+
+/* type conversion */
+void fpu_explode __P((struct fpemu *fe, struct fpn *fp, int t, u_int *src));
+void fpu_implode __P((struct fpemu *fe, struct fpn *fp, int t, u_int *dst));
+
+/*
+ * non-static emulation functions
+ */
+/* type 0 */
+int fpu_emul_fmovecr __P((struct fpemu *fe, struct instruction *insn));
+int fpu_emul_fstore __P((struct fpemu *fe, struct instruction *insn));
+int fpu_emul_fscale __P((struct fpemu *fe, struct instruction *insn));
+
+/*
+ * include function declarations of those which are called by fpu_emul_arith()
+ */
+#include "fpu_arith_proto.h"
+
+/*
+ * "helper" functions
+ */
+/* return values from constant rom */
+struct fpn *fpu_const __P((struct fpn *fp, u_int offset));
+/* update exceptions and FPSR */
+int fpu_upd_excp __P((struct fpemu *fe));
+u_int fpu_upd_fpsr __P((struct fpemu *fe, struct fpn *fp));
+
+/* address mode decoder, and load/store */
+int fpu_decode_ea __P((struct frame *frame, struct instruction *insn,
+ struct insn_ea *ea, int modreg));
+int fpu_load_ea __P((struct frame *frame, struct instruction *insn,
+ struct insn_ea *ea, char *dst));
+int fpu_store_ea __P((struct frame *frame, struct instruction *insn,
+ struct insn_ea *ea, char *src));
+
+/* macros for debugging */
+#define DEBUG /* XXX */
+
+extern int fpu_debug_level;
+
+/* debug classes */
+#define DL_DUMPINSN 0x0001
+#define DL_DECODEEA 0x0002
+#define DL_LOADEA 0x0004
+#define DL_STOREEA 0x0008
+#define DL_OPERANDS 0x0010
+#define DL_RESULT 0x0020
+#define DL_TESTCC 0x0040
+#define DL_BRANCH 0x0080
+#define DL_FSTORE 0x0100
+#define DL_FSCALE 0x0200
+#define DL_ARITH 0x0400
+#define DL_INSN 0x0800
+#define DL_FMOVEM 0x1000
+/* not defined yet
+#define DL_2000 0x2000
+#define DL_4000 0x4000
+*/
+#define DL_VERBOSE 0x8000
+/* composit debug classes */
+#define DL_EA (DL_DECODEEA|DL_LOADEA|DL_STOREEA)
+#define DL_VALUES (DL_OPERANDS|DL_RESULT)
+#define DL_COND (DL_TESTCC|DL_BRANCH)
+#define DL_ALL 0xffff
+
+#endif /* _FPU_EMULATE_H_ */
--- /dev/null
+/* $NetBSD: fpu_exp.c,v 1.1 1995/11/03 04:47:06 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_exp.c 10/24/95
+ */
+
+#include "fpu_emulate.h"
+
+/*
+ * fpu_exp.c: defines fpu_etox(), fpu_etoxm1(), fpu_tentox(), and fpu_twotox();
+ */
+
+struct fpn *
+fpu_etox(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_etoxm1(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_tentox(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_twotox(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
--- /dev/null
+/* $NetBSD: fpu_explode.c,v 1.1 1995/11/03 04:47:07 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_explode.c 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * FPU subroutines: `explode' the machine's `packed binary' format numbers
+ * into our internal format.
+ */
+
+#include <sys/types.h>
+
+#include "ieee.h"
+#include <machine/reg.h>
+
+#include "fpu_arith.h"
+#include "fpu_emulate.h"
+
+
+/* Conversion to internal format -- note asymmetry. */
+static int fpu_itof __P((struct fpn *fp, u_int i));
+static int fpu_stof __P((struct fpn *fp, u_int i));
+static int fpu_dtof __P((struct fpn *fp, u_int i, u_int j));
+static int fpu_xtof __P((struct fpn *fp, u_int i, u_int j, u_int k));
+
+/*
+ * N.B.: in all of the following, we assume the FP format is
+ *
+ * ---------------------------
+ * | s | exponent | fraction |
+ * ---------------------------
+ *
+ * (which represents -1**s * 1.fraction * 2**exponent), so that the
+ * sign bit is way at the top (bit 31), the exponent is next, and
+ * then the remaining bits mark the fraction. A zero exponent means
+ * zero or denormalized (0.fraction rather than 1.fraction), and the
+ * maximum possible exponent, 2bias+1, signals inf (fraction==0) or NaN.
+ *
+ * Since the sign bit is always the topmost bit---this holds even for
+ * integers---we set that outside all the *tof functions. Each function
+ * returns the class code for the new number (but note that we use
+ * FPC_QNAN for all NaNs; fpu_explode will fix this if appropriate).
+ */
+
+/*
+ * int -> fpn.
+ */
+static int
+fpu_itof(fp, i)
+ register struct fpn *fp;
+ register u_int i;
+{
+
+ if (i == 0)
+ return (FPC_ZERO);
+ /*
+ * The value FP_1 represents 2^FP_LG, so set the exponent
+ * there and let normalization fix it up. Convert negative
+ * numbers to sign-and-magnitude. Note that this relies on
+ * fpu_norm()'s handling of `supernormals'; see fpu_subr.c.
+ */
+ fp->fp_exp = FP_LG;
+ fp->fp_mant[0] = (int)i < 0 ? -i : i;
+ fp->fp_mant[1] = 0;
+ fp->fp_mant[2] = 0;
+ fp->fp_mant[3] = 0;
+ fpu_norm(fp);
+ return (FPC_NUM);
+}
+
+#define mask(nbits) ((1 << (nbits)) - 1)
+
+/*
+ * All external floating formats convert to internal in the same manner,
+ * as defined here. Note that only normals get an implied 1.0 inserted.
+ */
+#define FP_TOF(exp, expbias, allfrac, f0, f1, f2, f3) \
+ if (exp == 0) { \
+ if (allfrac == 0) \
+ return (FPC_ZERO); \
+ fp->fp_exp = 1 - expbias; \
+ fp->fp_mant[0] = f0; \
+ fp->fp_mant[1] = f1; \
+ fp->fp_mant[2] = f2; \
+ fp->fp_mant[3] = f3; \
+ fpu_norm(fp); \
+ return (FPC_NUM); \
+ } \
+ if (exp == (2 * expbias + 1)) { \
+ if (allfrac == 0) \
+ return (FPC_INF); \
+ fp->fp_mant[0] = f0; \
+ fp->fp_mant[1] = f1; \
+ fp->fp_mant[2] = f2; \
+ fp->fp_mant[3] = f3; \
+ return (FPC_QNAN); \
+ } \
+ fp->fp_exp = exp - expbias; \
+ fp->fp_mant[0] = FP_1 | f0; \
+ fp->fp_mant[1] = f1; \
+ fp->fp_mant[2] = f2; \
+ fp->fp_mant[3] = f3; \
+ return (FPC_NUM)
+
+/*
+ * 32-bit single precision -> fpn.
+ * We assume a single occupies at most (64-FP_LG) bits in the internal
+ * format: i.e., needs at most fp_mant[0] and fp_mant[1].
+ */
+static int
+fpu_stof(fp, i)
+ register struct fpn *fp;
+ register u_int i;
+{
+ register int exp;
+ register u_int frac, f0, f1;
+#define SNG_SHIFT (SNG_FRACBITS - FP_LG)
+
+ exp = (i >> (32 - 1 - SNG_EXPBITS)) & mask(SNG_EXPBITS);
+ frac = i & mask(SNG_FRACBITS);
+ f0 = frac >> SNG_SHIFT;
+ f1 = frac << (32 - SNG_SHIFT);
+ FP_TOF(exp, SNG_EXP_BIAS, frac, f0, f1, 0, 0);
+}
+
+/*
+ * 64-bit double -> fpn.
+ * We assume this uses at most (96-FP_LG) bits.
+ */
+static int
+fpu_dtof(fp, i, j)
+ register struct fpn *fp;
+ register u_int i, j;
+{
+ register int exp;
+ register u_int frac, f0, f1, f2;
+#define DBL_SHIFT (DBL_FRACBITS - 32 - FP_LG)
+
+ exp = (i >> (32 - 1 - DBL_EXPBITS)) & mask(DBL_EXPBITS);
+ frac = i & mask(DBL_FRACBITS - 32);
+ f0 = frac >> DBL_SHIFT;
+ f1 = (frac << (32 - DBL_SHIFT)) | (j >> DBL_SHIFT);
+ f2 = j << (32 - DBL_SHIFT);
+ frac |= j;
+ FP_TOF(exp, DBL_EXP_BIAS, frac, f0, f1, f2, 0);
+}
+
+/*
+ * 96-bit extended -> fpn.
+ */
+static int
+fpu_xtof(fp, i, j, k)
+ register struct fpn *fp;
+ register u_int i, j, k;
+{
+ register int exp;
+ register u_int frac, f0, f1, f2;
+#define EXT_SHIFT (EXT_FRACBITS - 1 - 32 - FP_LG)
+
+ exp = (i >> (32 - 1 - EXT_EXPBITS)) & mask(EXT_EXPBITS);
+ f0 = j >> EXT_SHIFT;
+ f1 = (j << (32 - EXT_SHIFT)) | (k >> EXT_SHIFT);
+ f2 = k << (32 - EXT_SHIFT);
+ frac = j | k;
+
+ /* m68k extended does not imply denormal by exp==0 */
+ if (exp == 0) {
+ if (frac == 0)
+ return (FPC_ZERO);
+ fp->fp_exp = - EXT_EXP_BIAS;
+ fp->fp_mant[0] = f0;
+ fp->fp_mant[1] = f1;
+ fp->fp_mant[2] = f2;
+ fp->fp_mant[3] = 0;
+ fpu_norm(fp);
+ return (FPC_NUM);
+ }
+ if (exp == (2 * EXT_EXP_BIAS + 1)) {
+ if (frac == 0)
+ return (FPC_INF);
+ fp->fp_mant[0] = f0;
+ fp->fp_mant[1] = f1;
+ fp->fp_mant[2] = f2;
+ fp->fp_mant[3] = 0;
+ return (FPC_QNAN);
+ }
+ fp->fp_exp = exp - EXT_EXP_BIAS;
+ fp->fp_mant[0] = FP_1 | f0;
+ fp->fp_mant[1] = f1;
+ fp->fp_mant[2] = f2;
+ fp->fp_mant[3] = 0;
+ return (FPC_NUM);
+}
+
+/*
+ * Explode the contents of a memory operand.
+ */
+void
+fpu_explode(fe, fp, type, space)
+ register struct fpemu *fe;
+ register struct fpn *fp;
+ int type;
+ register u_int *space;
+{
+ register u_int s;
+
+ s = space[0];
+ fp->fp_sign = s >> 31;
+ fp->fp_sticky = 0;
+ switch (type) {
+
+ case FTYPE_BYT:
+ s >>= 8;
+ case FTYPE_WRD:
+ s >>= 16;
+ case FTYPE_LNG:
+ s = fpu_itof(fp, s);
+ break;
+
+ case FTYPE_SNG:
+ s = fpu_stof(fp, s);
+ break;
+
+ case FTYPE_DBL:
+ s = fpu_dtof(fp, s, space[1]);
+ break;
+
+ case FTYPE_EXT:
+ s = fpu_xtof(fp, s, space[1], space[2]);
+ break;
+
+ default:
+ panic("fpu_explode");
+ }
+ if (s == FPC_QNAN && (fp->fp_mant[0] & FP_QUIETBIT) == 0) {
+ /*
+ * Input is a signalling NaN. All operations that return
+ * an input NaN operand put it through a ``NaN conversion'',
+ * which basically just means ``turn on the quiet bit''.
+ * We do this here so that all NaNs internally look quiet
+ * (we can tell signalling ones by their class).
+ */
+ fp->fp_mant[0] |= FP_QUIETBIT;
+ fe->fe_fpsr |= FPSR_SNAN; /* assert SNAN exception */
+ s = FPC_SNAN;
+ }
+ fp->fp_class = s;
+}
--- /dev/null
+/* $NetBSD: fpu_fmovecr.c,v 1.2 1995/11/05 00:35:23 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_fmovecr.c 10/8/95
+ */
+
+#include <sys/types.h>
+#include <machine/frame.h>
+
+#include <stddef.h>
+
+#include "fpu_emulate.h"
+
+static struct fpn constrom[] = {
+ /* fp_class, fp_sign, fp_exp, fp_sticky, fp_mant[0] ... [3] */
+ { FPC_NUM, 0, 1, 0, 0x6487e, 0xd5110b46, 0x11a80000, 0x0 },
+ { FPC_NUM, 0, -2, 0, 0x4d104, 0xd427de7f, 0xbcc00000, 0x0 },
+ { FPC_NUM, 0, 1, 0, 0x56fc2, 0xa2c515da, 0x54d00000, 0x0 },
+ { FPC_NUM, 0, 0, 0, 0x5c551, 0xd94ae0bf, 0x85e00000, 0x0 },
+ { FPC_NUM, 0, -2, 0, 0x6f2de, 0xc549b943, 0x8ca80000, 0x0 },
+ { FPC_ZERO, 0, 0, 0, 0x0, 0x0, 0x0, 0x0 },
+ { FPC_NUM, 0, -1, 0, 0x58b90, 0xbfbe8e7b, 0xcd600000, 0x0 },
+ { FPC_NUM, 0, 1, 0, 0x49aec, 0x6eed5545, 0x60b80000, 0x0 },
+ { FPC_NUM, 0, 0, 0, 0x40000, 0x0, 0x0, 0x0 },
+ { FPC_NUM, 0, 3, 0, 0x50000, 0x0, 0x0, 0x0 },
+ { FPC_NUM, 0, 6, 0, 0x64000, 0x0, 0x0, 0x0 },
+ { FPC_NUM, 0, 13, 0, 0x4e200, 0x0, 0x0, 0x0 },
+ { FPC_NUM, 0, 26, 0, 0x5f5e1, 0x0, 0x0, 0x0 },
+ { FPC_NUM, 0, 53, 0, 0x470de, 0x4df82000, 0x0, 0x0 },
+ { FPC_NUM, 0, 106, 0, 0x4ee2d, 0x6d415b85, 0xacf00000, 0x0 },
+ { FPC_NUM, 0, 212, 0, 0x613c0, 0xfa4ffe7d, 0x36a80000, 0x0 },
+ { FPC_NUM, 0, 425, 0, 0x49dd2, 0x3e4c074c, 0x67000000, 0x0 },
+ { FPC_NUM, 0, 850, 0, 0x553f7, 0x5fdcefce, 0xf4700000, 0x0 },
+ { FPC_NUM, 0, 1700, 0, 0x718cd, 0x5753074, 0x8e380000, 0x0 },
+ { FPC_NUM, 0, 3401, 0, 0x64bb3, 0xac340ba8, 0x60b80000, 0x0 },
+ { FPC_NUM, 0, 6803, 0, 0x4f459, 0xdaee29ea, 0xef280000, 0x0 },
+ { FPC_NUM, 0, 13606, 0, 0x62302, 0x90145104, 0xbcd80000, 0x0 },
+};
+
+struct fpn *
+fpu_const(fp, offset)
+ struct fpn *fp;
+ u_int offset;
+{
+ struct fpn *r;
+ int i;
+
+#ifdef DEBUG
+ if (fp == NULL) {
+ panic("fpu_const: NULL pointer passed\n");
+ }
+#endif
+ if (offset == 0) {
+ r = &constrom[0];
+ } else if (0xb <= offset && offset <= 0xe) {
+ r = &constrom[offset - 0xb + 1];
+ } else if (0x30 <= offset && offset <= 0x3f) {
+ r = &constrom[offset - 0x30 + 6];
+ } else {
+ /* return 0.0 for anything else (incl. valid offset 0xf) */
+ r = &constrom[5];
+ }
+
+ CPYFPN(fp, r);
+
+ return fp;
+}
+
+int
+fpu_emul_fmovecr(fe, insn)
+ struct fpemu *fe;
+ struct instruction *insn;
+{
+ int dstreg, offset, sig;
+ u_int *fpreg;
+
+ dstreg = (insn->is_word1 >> 7) & 0x7;
+ offset = insn->is_word1 & 0x7F;
+ fpreg = &(fe->fe_fpframe->fpf_regs[0]);
+
+ (void)fpu_const(&fe->fe_f3, offset);
+ (void)fpu_upd_fpsr(fe, &fe->fe_f3);
+ fpu_implode(fe, &fe->fe_f3, FTYPE_EXT, &fpreg[dstreg * 3]);
+ if (fpu_debug_level & DL_RESULT) {
+ printf(" fpu_emul_fmovecr: result %08x,%08x,%08x to FP%d\n",
+ fpreg[dstreg * 3], fpreg[dstreg * 3 + 1], fpreg[dstreg * 3 + 2],
+ dstreg);
+ }
+ return 0;
+}
--- /dev/null
+/* $NetBSD: fpu_fscale.c,v 1.2 1995/11/05 00:35:25 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gordon Ross
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * FSCALE - separated from the other type0 arithmetic instructions
+ * for performance reason; maybe unnecessary, but FSCALE assumes
+ * the source operand be an integer. It performs type conversion
+ * only if the source operand is *not* an integer.
+ */
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <machine/frame.h>
+
+#include "fpu_emulate.h"
+
+int
+fpu_emul_fscale(fe, insn)
+ struct fpemu *fe;
+ struct instruction *insn;
+{
+ struct frame *frame;
+ u_int *fpregs;
+ int word1, sig;
+ int regnum, format;
+ int scale, sign, exp;
+ u_int m0, m1;
+ u_int buf[3], fpsr;
+ int flags;
+ char regname;
+
+ sig = 0;
+ frame = fe->fe_frame;
+ fpregs = &(fe->fe_fpframe->fpf_regs[0]);
+ /* clear all exceptions and conditions */
+ fpsr = fe->fe_fpsr & ~FPSR_EXCP & ~FPSR_CCB;
+ if (fpu_debug_level & DL_FSCALE) {
+ printf(" fpu_emul_fscale: FPSR = %08x, FPCR = %08x\n", fpsr, fe->fe_fpcr);
+ }
+
+ word1 = insn->is_word1;
+ format = (word1 >> 10) & 7;
+ regnum = (word1 >> 7) & 7;
+
+ fe->fe_fpcr &= FPCR_ROUND;
+ fe->fe_fpcr |= FPCR_ZERO;
+
+ /* get the source operand */
+ if ((word1 & 0x4000) == 0) {
+ if (fpu_debug_level & DL_FSCALE) {
+ printf(" fpu_emul_fscale: FP%d op FP%d => FP%d\n",
+ format, regnum, regnum);
+ }
+ /* the operand is an FP reg */
+ if (fpu_debug_level & DL_FSCALE) {
+ printf(" fpu_emul_scale: src opr FP%d=%08x%08x%08x\n",
+ format, fpregs[format*3], fpregs[format*3+1],
+ fpregs[format*3+2]);
+ }
+ fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
+ fpu_implode(fe, &fe->fe_f2, FTYPE_LNG, buf);
+ } else {
+ /* the operand is in memory */
+ if (format == FTYPE_DBL) {
+ insn->is_datasize = 8;
+ } else if (format == FTYPE_SNG || format == FTYPE_LNG) {
+ insn->is_datasize = 4;
+ } else if (format == FTYPE_WRD) {
+ insn->is_datasize = 2;
+ } else if (format == FTYPE_BYT) {
+ insn->is_datasize = 1;
+ } else if (format == FTYPE_EXT) {
+ insn->is_datasize = 12;
+ } else {
+ /* invalid or unsupported operand format */
+ sig = SIGFPE;
+ return sig;
+ }
+
+ /* Get effective address. (modreg=opcode&077) */
+ sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
+ if (sig) {
+ if (fpu_debug_level & DL_FSCALE) {
+ printf(" fpu_emul_fscale: error in decode_ea\n");
+ }
+ return sig;
+ }
+
+ if (fpu_debug_level & DL_FSCALE) {
+ printf(" fpu_emul_fscale: addr mode = ");
+ flags = insn->is_ea0.ea_flags;
+ regname = (insn->is_ea0.ea_regnum & 8) ? 'a' : 'd';
+
+ if (flags & EA_DIRECT) {
+ printf("%c%d\n", regname, insn->is_ea0.ea_regnum & 7);
+ } else if (insn->is_ea0.ea_flags & EA_PREDECR) {
+ printf("%c%d@-\n", regname, insn->is_ea0.ea_regnum & 7);
+ } else if (insn->is_ea0.ea_flags & EA_POSTINCR) {
+ printf("%c%d@+\n", regname, insn->is_ea0.ea_regnum & 7);
+ } else if (insn->is_ea0.ea_flags & EA_OFFSET) {
+ printf("%c%d@(%d)\n", regname, insn->is_ea0.ea_regnum & 7,
+ insn->is_ea0.ea_offset);
+ } else if (insn->is_ea0.ea_flags & EA_INDEXED) {
+ printf("%c%d@(...)\n", regname, insn->is_ea0.ea_regnum & 7);
+ } else if (insn->is_ea0.ea_flags & EA_ABS) {
+ printf("0x%08x\n", insn->is_ea0.ea_absaddr);
+ } else if (insn->is_ea0.ea_flags & EA_PC_REL) {
+ printf("pc@(%d)\n", insn->is_ea0.ea_offset);
+ } else if (flags & EA_IMMED) {
+ printf("#0x%08x%08x%08x\n",
+ insn->is_ea0.ea_immed[0], insn->is_ea0.ea_immed[1],
+ insn->is_ea0.ea_immed[2]);
+ } else {
+ printf("%c%d@\n", regname, insn->is_ea0.ea_regnum & 7);
+ }
+ }
+ fpu_load_ea(frame, insn, &insn->is_ea0, (char*)buf);
+
+ if (fpu_debug_level & DL_FSCALE) {
+ printf(" fpu_emul_fscale: src = %08x%08x%08x, siz = %d\n",
+ buf[0], buf[1], buf[2], insn->is_datasize);
+ }
+ if (format == FTYPE_LNG) {
+ /* nothing */
+ } else if (format == FTYPE_WRD) {
+ /* sign-extend */
+ scale = buf[0] & 0xffff;
+ if (scale & 0x8000) {
+ scale |= 0xffff0000;
+ }
+ } else if (format == FTYPE_BYT) {
+ /* sign-extend */
+ scale = buf[0] & 0xff;
+ if (scale & 0x80) {
+ scale |= 0xffffff00;
+ }
+ } else if (format == FTYPE_DBL || format == FTYPE_SNG ||
+ format == FTYPE_EXT) {
+ fpu_explode(fe, &fe->fe_f2, format, buf);
+ fpu_implode(fe, &fe->fe_f2, FTYPE_LNG, buf);
+ }
+ /* make it look like we've got an FP oprand */
+ fe->fe_f2.fp_class = (buf[0] == 0) ? FPC_ZERO : FPC_NUM;
+ }
+
+ /* assume there's no exception */
+ sig = 0;
+
+ /* it's barbaric but we're going to operate directly on
+ * the dst operand's bit pattern */
+ sign = fpregs[regnum * 3] & 0x80000000;
+ exp = (fpregs[regnum * 3] & 0x7fff0000) >> 16;
+ m0 = fpregs[regnum * 3 + 1];
+ m1 = fpregs[regnum * 3 + 2];
+
+ switch (fe->fe_f2.fp_class) {
+ case FPC_SNAN:
+ fpsr |= FPSR_SNAN;
+ case FPC_QNAN:
+ /* dst = NaN */
+ exp = 0x7fff;
+ m0 = m1 = 0xffffffff;
+ break;
+ case FPC_ZERO:
+ case FPC_NUM:
+ if ((0 < exp && exp < 0x7fff) ||
+ (exp == 0 && (m0 | m1) != 0)) {
+ /* normal or denormal */
+ exp += scale;
+ if (exp < 0) {
+ /* underflow */
+ u_int grs; /* guard, round and sticky */
+
+ exp = 0;
+ grs = m1 << (32 + exp);
+ m1 = m0 << (32 + exp) | m1 >> -exp;
+ m0 >>= -exp;
+ if (grs != 0) {
+ fpsr |= FPSR_INEX2;
+
+ switch (fe->fe_fpcr & 0x30) {
+ case FPCR_MINF:
+ if (sign != 0) {
+ if (++m1 == 0 &&
+ ++m0 == 0) {
+ m0 = 0x80000000;
+ exp++;
+ }
+ }
+ break;
+ case FPCR_NEAR:
+ if (grs == 0x80000000) {
+ /* tie */
+ if ((m1 & 1) &&
+ ++m1 == 0 &&
+ ++m0 == 0) {
+ m0 = 0x80000000;
+ exp++;
+ }
+ } else if (grs & 0x80000000) {
+ if (++m1 == 0 &&
+ ++m0 == 0) {
+ m0 = 0x80000000;
+ exp++;
+ }
+ }
+ break;
+ case FPCR_PINF:
+ if (sign == 0) {
+ if (++m1 == 0 &&
+ ++m0 == 0) {
+ m0 = 0x80000000;
+ exp++;
+ }
+ }
+ break;
+ case FPCR_ZERO:
+ break;
+ }
+ }
+ if (exp == 0 && (m0 & 0x80000000) == 0) {
+ fpsr |= FPSR_UNFL;
+ if ((m0 | m1) == 0) {
+ fpsr |= FPSR_ZERO;
+ }
+ }
+ } else if (exp >= 0x7fff) {
+ /* overflow --> result = Inf */
+ /* but first, try to normalize in case it's an unnormalized */
+ while ((m0 & 0x80000000) == 0) {
+ exp--;
+ m0 = (m0 << 1) | (m1 >> 31);
+ m1 = m1 << 1;
+ }
+ /* if it's still too large, then return Inf */
+ if (exp >= 0x7fff) {
+ exp = 0x7fff;
+ m0 = m1 = 0;
+ fpsr |= FPSR_OVFL | FPSR_INF;
+ }
+ } else if ((m0 & 0x80000000) == 0) {
+ /*
+ * it's a denormal; we try to normalize but
+ * result may and may not be a normal.
+ */
+ while (exp > 0 && (m0 & 0x80000000) == 0) {
+ exp--;
+ m0 = (m0 << 1) | (m1 >> 31);
+ m1 = m1 << 1;
+ }
+ if ((m0 & 0x80000000) == 0) {
+ fpsr |= FPSR_UNFL;
+ }
+ } /* exp in range and mantissa normalized */
+ } else if (exp == 0 && m0 == 0 && m1 == 0) {
+ /* dst is Zero */
+ fpsr |= FPSR_ZERO;
+ } /* else we know exp == 0x7fff */
+ else if ((m0 | m1) == 0) {
+ fpsr |= FPSR_INF;
+ } else if ((m0 & 0x40000000) == 0) {
+ /* a signaling NaN */
+ fpsr |= FPSR_NAN | FPSR_SNAN;
+ } else {
+ /* a quiet NaN */
+ fpsr |= FPSR_NAN;
+ }
+ break;
+ case FPC_INF:
+ /* dst = NaN */
+ exp = 0x7fff;
+ m0 = m1 = 0xffffffff;
+ fpsr |= FPSR_OPERR | FPSR_NAN;
+ break;
+ default:
+#ifdef DEBUG
+ panic(" fpu_emul_fscale: invalid fp class");
+#endif
+ break;
+ }
+
+ /* store the result */
+ fpregs[regnum * 3] = sign | (exp << 16);
+ fpregs[regnum * 3 + 1] = m0;
+ fpregs[regnum * 3 + 2] = m1;
+
+ if (sign) {
+ fpsr |= FPSR_NEG;
+ }
+
+ /* update fpsr according to the result of operation */
+ fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
+
+ if (fpu_debug_level & DL_FSCALE) {
+ printf(" fpu_emul_fscale: FPSR = %08x, FPCR = %08x\n",
+ fe->fe_fpsr, fe->fe_fpcr);
+ }
+
+ return (fpsr & fe->fe_fpcr & FPSR_EXCP) ? SIGFPE : sig;
+}
--- /dev/null
+/* $NetBSD: fpu_fstore.c,v 1.2 1995/11/05 00:35:29 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <machine/frame.h>
+
+#include "fpu_emulate.h"
+
+/*
+ * type 0: fmove mem/fpr->fpr
+ * In this function, we know
+ * (opcode & 0x01c0) == 0
+ * (word1 & 0xe000) == 0x6000
+ */
+int
+fpu_emul_fstore(fe, insn)
+ struct fpemu *fe;
+ struct instruction *insn;
+{
+ struct frame *frame = fe->fe_frame;
+ u_int *fpregs = fe->fe_fpframe->fpf_regs;
+ int word1, sig;
+ int regnum;
+ int format;
+ u_int buf[3];
+ u_int flags;
+ char regname;
+
+ if (fpu_debug_level & DL_FSTORE) {
+ printf(" fpu_emul_fstore: frame at %08x fpframe at %08x\n",
+ frame, fe->fe_fpframe);
+ }
+
+ word1 = insn->is_word1;
+ format = (word1 >> 10) & 7;
+ regnum = (word1 >> 7) & 7;
+
+ insn->is_advance = 4;
+
+ if (format == FTYPE_DBL) {
+ insn->is_datasize = 8;
+ } else if (format == FTYPE_SNG || format == FTYPE_LNG) {
+ insn->is_datasize = 4;
+ } else if (format == FTYPE_WRD) {
+ insn->is_datasize = 2;
+ format = FTYPE_LNG;
+ } else if (format == FTYPE_BYT) {
+ insn->is_datasize = 1;
+ format = FTYPE_LNG;
+ } else if (format == FTYPE_EXT) {
+ insn->is_datasize = 12;
+ } else {
+ /* invalid or unsupported operand format */
+ if (fpu_debug_level & DL_FSTORE) {
+ printf(" fpu_emul_fstore: invalid format %d\n", format);
+ }
+ sig = SIGFPE;
+ }
+ if (fpu_debug_level & DL_FSTORE) {
+ printf(" fpu_emul_fstore: format %d, size %d\n",
+ format, insn->is_datasize);
+ }
+
+ /* Get effective address. (modreg=opcode&077) */
+ sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
+ if (sig) {
+ if (fpu_debug_level & DL_FSTORE) {
+ printf(" fpu_emul_fstore: failed in decode_ea sig=%d\n", sig);
+ }
+ return sig;
+ }
+
+ if (insn->is_datasize > 4 && insn->is_ea0.ea_flags == EA_DIRECT) {
+ /* trying to store dbl or ext into a data register */
+#ifdef DEBUG
+ printf(" fpu_fstore: attempted to store dbl/ext to reg\n");
+#endif
+ return SIGILL;
+ }
+
+ if (fpu_debug_level & DL_OPERANDS)
+ printf(" fpu_emul_fstore: saving FP%d (%08x,%08x,%08x)\n",
+ regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
+ fpregs[regnum * 3 + 2]);
+ fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &fpregs[regnum * 3]);
+ if (fpu_debug_level & DL_VALUES) {
+ static char *class_name[] = { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
+ printf(" fpu_emul_fstore: fpn (%s,%c,%d,%08x,%08x,%08x,%08x)\n",
+ class_name[fe->fe_f3.fp_class + 2],
+ fe->fe_f3.fp_sign ? '-' : '+', fe->fe_f3.fp_exp,
+ fe->fe_f3.fp_mant[0], fe->fe_f3.fp_mant[1],
+ fe->fe_f3.fp_mant[2], fe->fe_f3.fp_mant[3]);
+ }
+ fpu_implode(fe, &fe->fe_f3, format, buf);
+
+ fpu_store_ea(frame, insn, &insn->is_ea0, (char *)buf);
+ if (fpu_debug_level & DL_RESULT)
+ printf(" fpu_emul_fstore: %08x,%08x,%08x size %d\n",
+ buf[0], buf[1], buf[2], insn->is_datasize);
+
+ return 0;
+}
--- /dev/null
+/* $NetBSD: fpu_getexp.c,v 1.1 1995/11/03 04:47:11 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_getexp.c 10/8/95
+ */
+
+#include <sys/types.h>
+
+#include "fpu_emulate.h"
+
+struct fpn *
+fpu_getexp(fe)
+ struct fpemu *fe;
+{
+ struct fpn *fp = &fe->fe_f2;
+
+ fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+ if (fp->fp_class == FPC_INF) {
+ fp = fpu_newnan(fe);
+ fe->fe_fpsr |= FPSR_OPERR;
+ } else if (fp->fp_class == FPC_NUM) { /* a number */
+ fpu_explode(fe, &fe->fe_f3, FTYPE_LNG, &fp->fp_exp);
+ fp = &fe->fe_f3;
+ } else if (fp->fp_class == FPC_SNAN) { /* signaling NaN */
+ fe->fe_fpsr |= FPSR_SNAN;
+ } /* else if fp == zero or fp == quiet NaN, return itself */
+ return fp;
+}
+
+struct fpn *
+fpu_getman(fe)
+ struct fpemu *fe;
+{
+ struct fpn *fp = &fe->fe_f2;
+
+ fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+ if (fp->fp_class == FPC_INF) {
+ fp = fpu_newnan(fe);
+ fe->fe_fpsr |= FPSR_OPERR;
+ } else if (fp->fp_class == FPC_NUM) { /* a number */
+ fp->fp_exp = 0;
+ } else if (fp->fp_class == FPC_SNAN) { /* signaling NaN */
+ fe->fe_fpsr |= FPSR_SNAN;
+ } /* else if fp == zero or fp == quiet NaN, return itself */
+ return fp;
+}
+
--- /dev/null
+/* $NetBSD: fpu_hyperb.c,v 1.1 1995/11/03 04:47:11 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_hyperb.c 10/24/95
+ */
+
+#include "fpu_emulate.h"
+
+/*
+ * fpu_hyperb.c: defines the following functions
+ *
+ * fpu_atanh(), fpu_cosh(), fpu_sinh(), and fpu_tanh()
+ */
+
+struct fpn *
+fpu_atanh(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_cosh(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_sinh(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_tanh(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
--- /dev/null
+/* $NetBSD: fpu_implode.c,v 1.1 1995/11/03 04:47:12 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_implode.c 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * FPU subroutines: `implode' internal format numbers into the machine's
+ * `packed binary' format.
+ */
+
+#include <sys/types.h>
+
+#include "ieee.h"
+#include <machine/reg.h>
+
+#include "fpu_emulate.h"
+#include "fpu_arith.h"
+
+/* Conversion from internal format -- note asymmetry. */
+static u_int fpu_ftoi __P((struct fpemu *fe, struct fpn *fp));
+static u_int fpu_ftos __P((struct fpemu *fe, struct fpn *fp));
+static u_int fpu_ftod __P((struct fpemu *fe, struct fpn *fp, u_int *));
+static u_int fpu_ftox __P((struct fpemu *fe, struct fpn *fp, u_int *));
+
+/*
+ * Round a number (algorithm from Motorola MC68882 manual, modified for
+ * our internal format). Set inexact exception if rounding is required.
+ * Return true iff we rounded up.
+ *
+ * After rounding, we discard the guard and round bits by shifting right
+ * 2 bits (a la fpu_shr(), but we do not bother with fp->fp_sticky).
+ * This saves effort later.
+ *
+ * Note that we may leave the value 2.0 in fp->fp_mant; it is the caller's
+ * responsibility to fix this if necessary.
+ */
+int
+round(register struct fpemu *fe, register struct fpn *fp)
+{
+ register u_int m0, m1, m2, m3;
+ register int gr, s, ret;
+
+ m0 = fp->fp_mant[0];
+ m1 = fp->fp_mant[1];
+ m2 = fp->fp_mant[2];
+ m3 = fp->fp_mant[3];
+ gr = m3 & 3;
+ s = fp->fp_sticky;
+
+ /* mant >>= FP_NG */
+ m3 = (m3 >> FP_NG) | (m2 << (32 - FP_NG));
+ m2 = (m2 >> FP_NG) | (m1 << (32 - FP_NG));
+ m1 = (m1 >> FP_NG) | (m0 << (32 - FP_NG));
+ m0 >>= FP_NG;
+
+ if ((gr | s) == 0) /* result is exact: no rounding needed */
+ goto rounddown;
+
+ fe->fe_fpsr |= FPSR_INEX2; /* inexact */
+
+ /* Go to rounddown to round down; break to round up. */
+ switch (fe->fe_fpcr & FPCR_ROUND) {
+
+ case FPCR_NEAR:
+ default:
+ /*
+ * Round only if guard is set (gr & 2). If guard is set,
+ * but round & sticky both clear, then we want to round
+ * but have a tie, so round to even, i.e., add 1 iff odd.
+ */
+ if ((gr & 2) == 0)
+ goto rounddown;
+ if ((gr & 1) || fp->fp_sticky || (m3 & 1))
+ break;
+ goto rounddown;
+
+ case FPCR_ZERO:
+ /* Round towards zero, i.e., down. */
+ goto rounddown;
+
+ case FPCR_MINF:
+ /* Round towards -Inf: up if negative, down if positive. */
+ if (fp->fp_sign)
+ break;
+ goto rounddown;
+
+ case FPCR_PINF:
+ /* Round towards +Inf: up if positive, down otherwise. */
+ if (!fp->fp_sign)
+ break;
+ goto rounddown;
+ }
+
+ /* Bump low bit of mantissa, with carry. */
+#ifdef sparc /* ``cheating'' (left out FPU_DECL_CARRY; know this is faster) */
+ FPU_ADDS(m3, m3, 1);
+ FPU_ADDCS(m2, m2, 0);
+ FPU_ADDCS(m1, m1, 0);
+ FPU_ADDC(m0, m0, 0);
+#else
+ if (++m3 == 0 && ++m2 == 0 && ++m1 == 0)
+ m0++;
+#endif
+ fp->fp_mant[0] = m0;
+ fp->fp_mant[1] = m1;
+ fp->fp_mant[2] = m2;
+ fp->fp_mant[3] = m3;
+ return (1);
+
+rounddown:
+ fp->fp_mant[0] = m0;
+ fp->fp_mant[1] = m1;
+ fp->fp_mant[2] = m2;
+ fp->fp_mant[3] = m3;
+ return (0);
+}
+
+/*
+ * For overflow: return true if overflow is to go to +/-Inf, according
+ * to the sign of the overflowing result. If false, overflow is to go
+ * to the largest magnitude value instead.
+ */
+static int
+toinf(struct fpemu *fe, int sign)
+{
+ int inf;
+
+ /* look at rounding direction */
+ switch (fe->fe_fpcr & FPCR_ROUND) {
+
+ default:
+ case FPCR_NEAR: /* the nearest value is always Inf */
+ inf = 1;
+ break;
+
+ case FPCR_ZERO: /* toward 0 => never towards Inf */
+ inf = 0;
+ break;
+
+ case FPCR_PINF: /* toward +Inf iff positive */
+ inf = (sign == 0);
+ break;
+
+ case FPCR_MINF: /* toward -Inf iff negative */
+ inf = sign;
+ break;
+ }
+ return (inf);
+}
+
+/*
+ * fpn -> int (int value returned as return value).
+ *
+ * N.B.: this conversion always rounds towards zero (this is a peculiarity
+ * of the SPARC instruction set).
+ */
+static u_int
+fpu_ftoi(fe, fp)
+ struct fpemu *fe;
+ register struct fpn *fp;
+{
+ register u_int i;
+ register int sign, exp;
+
+ sign = fp->fp_sign;
+ switch (fp->fp_class) {
+
+ case FPC_ZERO:
+ return (0);
+
+ case FPC_NUM:
+ /*
+ * If exp >= 2^32, overflow. Otherwise shift value right
+ * into last mantissa word (this will not exceed 0xffffffff),
+ * shifting any guard and round bits out into the sticky
+ * bit. Then ``round'' towards zero, i.e., just set an
+ * inexact exception if sticky is set (see round()).
+ * If the result is > 0x80000000, or is positive and equals
+ * 0x80000000, overflow; otherwise the last fraction word
+ * is the result.
+ */
+ if ((exp = fp->fp_exp) >= 32)
+ break;
+ /* NB: the following includes exp < 0 cases */
+ if (fpu_shr(fp, FP_NMANT - 1 - FP_NG - exp) != 0)
+ /* m68881/2 do not underflow when
+ converting to integer */;
+ round(fe, fp);
+ i = fp->fp_mant[3];
+ if (i >= ((u_int)0x80000000 + sign))
+ break;
+ return (sign ? -i : i);
+
+ default: /* Inf, qNaN, sNaN */
+ break;
+ }
+ /* overflow: replace any inexact exception with invalid */
+ fe->fe_fpsr = (fe->fe_fpsr & ~FPSR_INEX2) | FPSR_OPERR;
+ return (0x7fffffff + sign);
+}
+
+/*
+ * fpn -> single (32 bit single returned as return value).
+ * We assume <= 29 bits in a single-precision fraction (1.f part).
+ */
+static u_int
+fpu_ftos(fe, fp)
+ struct fpemu *fe;
+ register struct fpn *fp;
+{
+ register u_int sign = fp->fp_sign << 31;
+ register int exp;
+
+#define SNG_EXP(e) ((e) << SNG_FRACBITS) /* makes e an exponent */
+#define SNG_MASK (SNG_EXP(1) - 1) /* mask for fraction */
+
+ /* Take care of non-numbers first. */
+ if (ISNAN(fp)) {
+ /*
+ * Preserve upper bits of NaN, per SPARC V8 appendix N.
+ * Note that fp->fp_mant[0] has the quiet bit set,
+ * even if it is classified as a signalling NaN.
+ */
+ (void) fpu_shr(fp, FP_NMANT - 1 - SNG_FRACBITS);
+ exp = SNG_EXP_INFNAN;
+ goto done;
+ }
+ if (ISINF(fp))
+ return (sign | SNG_EXP(SNG_EXP_INFNAN));
+ if (ISZERO(fp))
+ return (sign);
+
+ /*
+ * Normals (including subnormals). Drop all the fraction bits
+ * (including the explicit ``implied'' 1 bit) down into the
+ * single-precision range. If the number is subnormal, move
+ * the ``implied'' 1 into the explicit range as well, and shift
+ * right to introduce leading zeroes. Rounding then acts
+ * differently for normals and subnormals: the largest subnormal
+ * may round to the smallest normal (1.0 x 2^minexp), or may
+ * remain subnormal. In the latter case, signal an underflow
+ * if the result was inexact or if underflow traps are enabled.
+ *
+ * Rounding a normal, on the other hand, always produces another
+ * normal (although either way the result might be too big for
+ * single precision, and cause an overflow). If rounding a
+ * normal produces 2.0 in the fraction, we need not adjust that
+ * fraction at all, since both 1.0 and 2.0 are zero under the
+ * fraction mask.
+ *
+ * Note that the guard and round bits vanish from the number after
+ * rounding.
+ */
+ if ((exp = fp->fp_exp + SNG_EXP_BIAS) <= 0) { /* subnormal */
+ /* -NG for g,r; -SNG_FRACBITS-exp for fraction */
+ (void) fpu_shr(fp, FP_NMANT - FP_NG - SNG_FRACBITS - exp);
+ if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(1))
+ return (sign | SNG_EXP(1) | 0);
+ if (fe->fe_fpsr & FPSR_INEX2)
+ /* mc68881/2 don't underflow when converting */;
+ return (sign | SNG_EXP(0) | fp->fp_mant[3]);
+ }
+ /* -FP_NG for g,r; -1 for implied 1; -SNG_FRACBITS for fraction */
+ (void) fpu_shr(fp, FP_NMANT - FP_NG - 1 - SNG_FRACBITS);
+#ifdef DIAGNOSTIC
+ if ((fp->fp_mant[3] & SNG_EXP(1 << FP_NG)) == 0)
+ panic("fpu_ftos");
+#endif
+ if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(2))
+ exp++;
+ if (exp >= SNG_EXP_INFNAN) {
+ /* overflow to inf or to max single */
+ fe->fe_fpsr |= FPSR_OPERR | FPSR_INEX2;
+ if (toinf(fe, sign))
+ return (sign | SNG_EXP(SNG_EXP_INFNAN));
+ return (sign | SNG_EXP(SNG_EXP_INFNAN - 1) | SNG_MASK);
+ }
+done:
+ /* phew, made it */
+ return (sign | SNG_EXP(exp) | (fp->fp_mant[3] & SNG_MASK));
+}
+
+/*
+ * fpn -> double (32 bit high-order result returned; 32-bit low order result
+ * left in res[1]). Assumes <= 61 bits in double precision fraction.
+ *
+ * This code mimics fpu_ftos; see it for comments.
+ */
+static u_int
+fpu_ftod(fe, fp, res)
+ struct fpemu *fe;
+ register struct fpn *fp;
+ u_int *res;
+{
+ register u_int sign = fp->fp_sign << 31;
+ register int exp;
+
+#define DBL_EXP(e) ((e) << (DBL_FRACBITS & 31))
+#define DBL_MASK (DBL_EXP(1) - 1)
+
+ if (ISNAN(fp)) {
+ (void) fpu_shr(fp, FP_NMANT - 1 - DBL_FRACBITS);
+ exp = DBL_EXP_INFNAN;
+ goto done;
+ }
+ if (ISINF(fp)) {
+ sign |= DBL_EXP(DBL_EXP_INFNAN);
+ res[1] = 0;
+ return (sign);
+ }
+ if (ISZERO(fp)) {
+ res[1] = 0;
+ return (sign);
+ }
+
+ if ((exp = fp->fp_exp + DBL_EXP_BIAS) <= 0) {
+ (void) fpu_shr(fp, FP_NMANT - FP_NG - DBL_FRACBITS - exp);
+ if (round(fe, fp) && fp->fp_mant[2] == DBL_EXP(1)) {
+ res[1] = 0;
+ return (sign | DBL_EXP(1) | 0);
+ }
+ if (fe->fe_fpsr & FPSR_INEX2)
+ /* mc68881/2 don't underflow when converting */;
+ exp = 0;
+ goto done;
+ }
+ (void) fpu_shr(fp, FP_NMANT - FP_NG - 1 - DBL_FRACBITS);
+ if (round(fe, fp) && fp->fp_mant[2] == DBL_EXP(2))
+ exp++;
+ if (exp >= DBL_EXP_INFNAN) {
+ fe->fe_fpsr |= FPSR_OPERR | FPSR_INEX2;
+ if (toinf(fe, sign)) {
+ res[1] = 0;
+ return (sign | DBL_EXP(DBL_EXP_INFNAN) | 0);
+ }
+ res[1] = ~0;
+ return (sign | DBL_EXP(DBL_EXP_INFNAN) | DBL_MASK);
+ }
+done:
+ res[1] = fp->fp_mant[3];
+ return (sign | DBL_EXP(exp) | (fp->fp_mant[2] & DBL_MASK));
+}
+
+/*
+ * fpn -> 68k extended (32 bit high-order result returned; two 32-bit low
+ * order result left in res[1] & res[2]). Assumes == 64 bits in extended
+ * precision fraction.
+ *
+ * This code mimics fpu_ftos; see it for comments.
+ */
+static u_int
+fpu_ftox(fe, fp, res)
+ struct fpemu *fe;
+ register struct fpn *fp;
+ u_int *res;
+{
+ register u_int sign = fp->fp_sign << 31;
+ register int exp;
+
+#define EXT_EXP(e) ((e) << 16)
+#define EXT_MASK (EXT_EXP(1) - 1)
+
+ if (ISNAN(fp)) {
+ (void) fpu_shr(fp, FP_NMANT - 1 - EXT_FRACBITS);
+ exp = EXT_EXP_INFNAN;
+ goto done;
+ }
+ if (ISINF(fp)) {
+ sign |= EXT_EXP(EXT_EXP_INFNAN);
+ res[1] = res[2] = 0;
+ return (sign);
+ }
+ if (ISZERO(fp)) {
+ res[1] = res[2] = 0;
+ return (sign);
+ }
+
+ if ((exp = fp->fp_exp + EXT_EXP_BIAS) <= 0) {
+ /* I'm not sure about this <=... exp==0 doesn't mean
+ it's a denormal in extended format */
+ (void) fpu_shr(fp, FP_NMANT - FP_NG - EXT_FRACBITS - exp);
+ if (round(fe, fp) && fp->fp_mant[2] == EXT_EXP(1)) {
+ res[1] = res[2] = 0;
+ return (sign | EXT_EXP(1) | 0);
+ }
+ if (fe->fe_fpsr & FPSR_INEX2)
+ /* mc68881/2 don't underflow */;
+ exp = 0;
+ goto done;
+ }
+ (void) fpu_shr(fp, FP_NMANT - FP_NG - EXT_FRACBITS);
+ if (round(fe, fp) && fp->fp_mant[2] == EXT_EXP(2))
+ exp++;
+ if (exp >= EXT_EXP_INFNAN) {
+ fe->fe_fpsr |= FPSR_OPERR | FPSR_INEX2;
+ if (toinf(fe, sign)) {
+ res[1] = res[2] = 0;
+ return (sign | EXT_EXP(EXT_EXP_INFNAN) | 0);
+ }
+ res[1] = res[2] = ~0;
+ return (sign | EXT_EXP(EXT_EXP_INFNAN) | EXT_MASK);
+ }
+done:
+ res[1] = fp->fp_mant[2];
+ res[2] = fp->fp_mant[3];
+ return (sign | EXT_EXP(exp));
+}
+
+/*
+ * Implode an fpn, writing the result into the given space.
+ */
+void
+fpu_implode(fe, fp, type, space)
+ struct fpemu *fe;
+ register struct fpn *fp;
+ int type;
+ register u_int *space;
+{
+ fe->fe_fpsr &= ~FPSR_EXCP;
+
+ switch (type) {
+ case FTYPE_LNG:
+ space[0] = fpu_ftoi(fe, fp);
+ break;
+
+ case FTYPE_SNG:
+ space[0] = fpu_ftos(fe, fp);
+ break;
+
+ case FTYPE_DBL:
+ space[0] = fpu_ftod(fe, fp, space);
+ break;
+
+ case FTYPE_EXT:
+ /* funky rounding precision options ?? */
+ space[0] = fpu_ftox(fe, fp, space);
+ break;
+
+ default:
+ panic("fpu_implode");
+ }
+}
--- /dev/null
+/* $NetBSD: fpu_int.c,v 1.1 1995/11/03 04:47:14 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_int.c
+ */
+
+#include <sys/types.h>
+
+#include <machine/reg.h>
+
+#include "fpu_arith.h"
+#include "fpu_emulate.h"
+
+/* FINTRZ - always round to zero */
+struct fpn *
+fpu_intrz(fe)
+ struct fpemu *fe;
+{
+ register struct fpn *x = &fe->fe_f2;
+ register int sh, clr, mask, i;
+
+ /* special cases first */
+ if (x->fp_class != FPC_NUM) {
+ return x;
+ }
+ /* when |x| < 1.0 */
+ if (x->fp_exp < 0) {
+ x->fp_class = FPC_ZERO;
+ x->fp_mant[0] = x->fp_mant[1] = x->fp_mant[2] = x->fp_mant[3] = 0;
+ return x;
+ }
+
+ /* real work */
+ sh = FP_NMANT - 1 - x->fp_exp;
+ if (sh <= 0) {
+ return x;
+ }
+
+ clr = 3 - sh / 32;
+ mask = (0xffffffff << (sh % 32));
+
+ for (i = 3; i > clr; i--) {
+ x->fp_mant[i] = 0;
+ }
+ x->fp_mant[i] &= mask;
+
+ return x;
+}
+
+/* FINT */
+struct fpn *
+fpu_int(fe)
+ struct fpemu *fe;
+{
+ register struct fpn *x = &fe->fe_f2;
+ register int rsh, lsh, wsh, i;
+
+ /* special cases first */
+ if (x->fp_class != FPC_NUM) {
+ return x;
+ }
+ /* even if we have exponent == -1, we still have possiblity
+ that the result >= 1.0 when mantissa ~= 1.0 and rounded up */
+ if (x->fp_exp < -1) {
+ x->fp_class = FPC_ZERO;
+ x->fp_mant[0] = x->fp_mant[1] = x->fp_mant[2] = x->fp_mant[3] = 0;
+ return x;
+ }
+
+ /* real work */
+ rsh = FP_NMANT - 1 - x->fp_exp;
+ if (rsh - FP_NG <= 0) {
+ return x;
+ }
+
+ fpu_shr(x, rsh - FP_NG); /* shift to the right */
+
+ if (round(fe, x) == 1 /* rounded up */ &&
+ x->fp_mant[3 - (FP_NMANT-rsh)/32] & (1 << ((FP_NMANT-rsh)%32))
+ /* x >= 2.0 */) {
+ rsh--; /* reduce shift count by 1 */
+ x->fp_exp++; /* adjust exponent */
+ }
+
+ /* shift it back to the left */
+ wsh = rsh / 32;
+ lsh = rsh % 32;
+ rsh = 32 - lsh;
+ for (i = 0; i + wsh < 3; i++) {
+ x->fp_mant[i] = (x->fp_mant[i+wsh] << lsh) | (x->fp_mant[i+wsh+1] >> rsh);
+ }
+ x->fp_mant[i++] = (x->fp_mant[i+wsh] << lsh);
+ for (; i < 4; i++) {
+ x->fp_mant[i] = 0;
+ }
+
+ return x;
+}
--- /dev/null
+/* $NetBSD: fpu_log.c,v 1.2 1995/11/05 00:35:31 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_log.c 10/8/95
+ */
+
+#include <sys/types.h>
+
+#include "fpu_emulate.h"
+
+static u_int logA6[] = { 0x3FC2499A, 0xB5E4040B };
+static u_int logA5[] = { 0xBFC555B5, 0x848CB7DB };
+static u_int logA4[] = { 0x3FC99999, 0x987D8730 };
+static u_int logA3[] = { 0xBFCFFFFF, 0xFF6F7E97 };
+static u_int logA2[] = { 0x3FD55555, 0x555555A4 };
+static u_int logA1[] = { 0xBFE00000, 0x00000008 };
+
+static u_int logB5[] = { 0x3F175496, 0xADD7DAD6 };
+static u_int logB4[] = { 0x3F3C71C2, 0xFE80C7E0 };
+static u_int logB3[] = { 0x3F624924, 0x928BCCFF };
+static u_int logB2[] = { 0x3F899999, 0x999995EC };
+static u_int logB1[] = { 0x3FB55555, 0x55555555 };
+
+/* sfpn = shortened fp number; can represent only positive numbers */
+static struct sfpn {
+ int sp_exp;
+ u_int sp_m0, sp_m1;
+} logtbl[] = {
+ { 0x3FFE - 0x3fff, 0xFE03F80FU, 0xE03F80FEU },
+ { 0x3FF7 - 0x3fff, 0xFF015358U, 0x833C47E2U },
+ { 0x3FFE - 0x3fff, 0xFA232CF2U, 0x52138AC0U },
+ { 0x3FF9 - 0x3fff, 0xBDC8D83EU, 0xAD88D549U },
+ { 0x3FFE - 0x3fff, 0xF6603D98U, 0x0F6603DAU },
+ { 0x3FFA - 0x3fff, 0x9CF43DCFU, 0xF5EAFD48U },
+ { 0x3FFE - 0x3fff, 0xF2B9D648U, 0x0F2B9D65U },
+ { 0x3FFA - 0x3fff, 0xDA16EB88U, 0xCB8DF614U },
+ { 0x3FFE - 0x3fff, 0xEF2EB71FU, 0xC4345238U },
+ { 0x3FFB - 0x3fff, 0x8B29B775U, 0x1BD70743U },
+ { 0x3FFE - 0x3fff, 0xEBBDB2A5U, 0xC1619C8CU },
+ { 0x3FFB - 0x3fff, 0xA8D839F8U, 0x30C1FB49U },
+ { 0x3FFE - 0x3fff, 0xE865AC7BU, 0x7603A197U },
+ { 0x3FFB - 0x3fff, 0xC61A2EB1U, 0x8CD907ADU },
+ { 0x3FFE - 0x3fff, 0xE525982AU, 0xF70C880EU },
+ { 0x3FFB - 0x3fff, 0xE2F2A47AU, 0xDE3A18AFU },
+ { 0x3FFE - 0x3fff, 0xE1FC780EU, 0x1FC780E2U },
+ { 0x3FFB - 0x3fff, 0xFF64898EU, 0xDF55D551U },
+ { 0x3FFE - 0x3fff, 0xDEE95C4CU, 0xA037BA57U },
+ { 0x3FFC - 0x3fff, 0x8DB956A9U, 0x7B3D0148U },
+ { 0x3FFE - 0x3fff, 0xDBEB61EEU, 0xD19C5958U },
+ { 0x3FFC - 0x3fff, 0x9B8FE100U, 0xF47BA1DEU },
+ { 0x3FFE - 0x3fff, 0xD901B203U, 0x6406C80EU },
+ { 0x3FFC - 0x3fff, 0xA9372F1DU, 0x0DA1BD17U },
+ { 0x3FFE - 0x3fff, 0xD62B80D6U, 0x2B80D62CU },
+ { 0x3FFC - 0x3fff, 0xB6B07F38U, 0xCE90E46BU },
+ { 0x3FFE - 0x3fff, 0xD3680D36U, 0x80D3680DU },
+ { 0x3FFC - 0x3fff, 0xC3FD0329U, 0x06488481U },
+ { 0x3FFE - 0x3fff, 0xD0B69FCBU, 0xD2580D0BU },
+ { 0x3FFC - 0x3fff, 0xD11DE0FFU, 0x15AB18CAU },
+ { 0x3FFE - 0x3fff, 0xCE168A77U, 0x25080CE1U },
+ { 0x3FFC - 0x3fff, 0xDE1433A1U, 0x6C66B150U },
+ { 0x3FFE - 0x3fff, 0xCB8727C0U, 0x65C393E0U },
+ { 0x3FFC - 0x3fff, 0xEAE10B5AU, 0x7DDC8ADDU },
+ { 0x3FFE - 0x3fff, 0xC907DA4EU, 0x871146ADU },
+ { 0x3FFC - 0x3fff, 0xF7856E5EU, 0xE2C9B291U },
+ { 0x3FFE - 0x3fff, 0xC6980C69U, 0x80C6980CU },
+ { 0x3FFD - 0x3fff, 0x82012CA5U, 0xA68206D7U },
+ { 0x3FFE - 0x3fff, 0xC4372F85U, 0x5D824CA6U },
+ { 0x3FFD - 0x3fff, 0x882C5FCDU, 0x7256A8C5U },
+ { 0x3FFE - 0x3fff, 0xC1E4BBD5U, 0x95F6E947U },
+ { 0x3FFD - 0x3fff, 0x8E44C60BU, 0x4CCFD7DEU },
+ { 0x3FFE - 0x3fff, 0xBFA02FE8U, 0x0BFA02FFU },
+ { 0x3FFD - 0x3fff, 0x944AD09EU, 0xF4351AF6U },
+ { 0x3FFE - 0x3fff, 0xBD691047U, 0x07661AA3U },
+ { 0x3FFD - 0x3fff, 0x9A3EECD4U, 0xC3EAA6B2U },
+ { 0x3FFE - 0x3fff, 0xBB3EE721U, 0xA54D880CU },
+ { 0x3FFD - 0x3fff, 0xA0218434U, 0x353F1DE8U },
+ { 0x3FFE - 0x3fff, 0xB92143FAU, 0x36F5E02EU },
+ { 0x3FFD - 0x3fff, 0xA5F2FCABU, 0xBBC506DAU },
+ { 0x3FFE - 0x3fff, 0xB70FBB5AU, 0x19BE3659U },
+ { 0x3FFD - 0x3fff, 0xABB3B8BAU, 0x2AD362A5U },
+ { 0x3FFE - 0x3fff, 0xB509E68AU, 0x9B94821FU },
+ { 0x3FFD - 0x3fff, 0xB1641795U, 0xCE3CA97BU },
+ { 0x3FFE - 0x3fff, 0xB30F6352U, 0x8917C80BU },
+ { 0x3FFD - 0x3fff, 0xB7047551U, 0x5D0F1C61U },
+ { 0x3FFE - 0x3fff, 0xB11FD3B8U, 0x0B11FD3CU },
+ { 0x3FFD - 0x3fff, 0xBC952AFEU, 0xEA3D13E1U },
+ { 0x3FFE - 0x3fff, 0xAF3ADDC6U, 0x80AF3ADEU },
+ { 0x3FFD - 0x3fff, 0xC2168ED0U, 0xF458BA4AU },
+ { 0x3FFE - 0x3fff, 0xAD602B58U, 0x0AD602B6U },
+ { 0x3FFD - 0x3fff, 0xC788F439U, 0xB3163BF1U },
+ { 0x3FFE - 0x3fff, 0xAB8F69E2U, 0x8359CD11U },
+ { 0x3FFD - 0x3fff, 0xCCECAC08U, 0xBF04565DU },
+ { 0x3FFE - 0x3fff, 0xA9C84A47U, 0xA07F5638U },
+ { 0x3FFD - 0x3fff, 0xD2420487U, 0x2DD85160U },
+ { 0x3FFE - 0x3fff, 0xA80A80A8U, 0x0A80A80BU },
+ { 0x3FFD - 0x3fff, 0xD7894992U, 0x3BC3588AU },
+ { 0x3FFE - 0x3fff, 0xA655C439U, 0x2D7B73A8U },
+ { 0x3FFD - 0x3fff, 0xDCC2C4B4U, 0x9887DACCU },
+ { 0x3FFE - 0x3fff, 0xA4A9CF1DU, 0x96833751U },
+ { 0x3FFD - 0x3fff, 0xE1EEBD3EU, 0x6D6A6B9EU },
+ { 0x3FFE - 0x3fff, 0xA3065E3FU, 0xAE7CD0E0U },
+ { 0x3FFD - 0x3fff, 0xE70D785CU, 0x2F9F5BDCU },
+ { 0x3FFE - 0x3fff, 0xA16B312EU, 0xA8FC377DU },
+ { 0x3FFD - 0x3fff, 0xEC1F392CU, 0x5179F283U },
+ { 0x3FFE - 0x3fff, 0x9FD809FDU, 0x809FD80AU },
+ { 0x3FFD - 0x3fff, 0xF12440D3U, 0xE36130E6U },
+ { 0x3FFE - 0x3fff, 0x9E4CAD23U, 0xDD5F3A20U },
+ { 0x3FFD - 0x3fff, 0xF61CCE92U, 0x346600BBU },
+ { 0x3FFE - 0x3fff, 0x9CC8E160U, 0xC3FB19B9U },
+ { 0x3FFD - 0x3fff, 0xFB091FD3U, 0x8145630AU },
+ { 0x3FFE - 0x3fff, 0x9B4C6F9EU, 0xF03A3CAAU },
+ { 0x3FFD - 0x3fff, 0xFFE97042U, 0xBFA4C2ADU },
+ { 0x3FFE - 0x3fff, 0x99D722DAU, 0xBDE58F06U },
+ { 0x3FFE - 0x3fff, 0x825EFCEDU, 0x49369330U },
+ { 0x3FFE - 0x3fff, 0x9868C809U, 0x868C8098U },
+ { 0x3FFE - 0x3fff, 0x84C37A7AU, 0xB9A905C9U },
+ { 0x3FFE - 0x3fff, 0x97012E02U, 0x5C04B809U },
+ { 0x3FFE - 0x3fff, 0x87224C2EU, 0x8E645FB7U },
+ { 0x3FFE - 0x3fff, 0x95A02568U, 0x095A0257U },
+ { 0x3FFE - 0x3fff, 0x897B8CACU, 0x9F7DE298U },
+ { 0x3FFE - 0x3fff, 0x94458094U, 0x45809446U },
+ { 0x3FFE - 0x3fff, 0x8BCF55DEU, 0xC4CD05FEU },
+ { 0x3FFE - 0x3fff, 0x92F11384U, 0x0497889CU },
+ { 0x3FFE - 0x3fff, 0x8E1DC0FBU, 0x89E125E5U },
+ { 0x3FFE - 0x3fff, 0x91A2B3C4U, 0xD5E6F809U },
+ { 0x3FFE - 0x3fff, 0x9066E68CU, 0x955B6C9BU },
+ { 0x3FFE - 0x3fff, 0x905A3863U, 0x3E06C43BU },
+ { 0x3FFE - 0x3fff, 0x92AADE74U, 0xC7BE59E0U },
+ { 0x3FFE - 0x3fff, 0x8F1779D9U, 0xFDC3A219U },
+ { 0x3FFE - 0x3fff, 0x94E9BFF6U, 0x15845643U },
+ { 0x3FFE - 0x3fff, 0x8DDA5202U, 0x37694809U },
+ { 0x3FFE - 0x3fff, 0x9723A1B7U, 0x20134203U },
+ { 0x3FFE - 0x3fff, 0x8CA29C04U, 0x6514E023U },
+ { 0x3FFE - 0x3fff, 0x995899C8U, 0x90EB8990U },
+ { 0x3FFE - 0x3fff, 0x8B70344AU, 0x139BC75AU },
+ { 0x3FFE - 0x3fff, 0x9B88BDAAU, 0x3A3DAE2FU },
+ { 0x3FFE - 0x3fff, 0x8A42F870U, 0x5669DB46U },
+ { 0x3FFE - 0x3fff, 0x9DB4224FU, 0xFFE1157CU },
+ { 0x3FFE - 0x3fff, 0x891AC73AU, 0xE9819B50U },
+ { 0x3FFE - 0x3fff, 0x9FDADC26U, 0x8B7A12DAU },
+ { 0x3FFE - 0x3fff, 0x87F78087U, 0xF78087F8U },
+ { 0x3FFE - 0x3fff, 0xA1FCFF17U, 0xCE733BD4U },
+ { 0x3FFE - 0x3fff, 0x86D90544U, 0x7A34ACC6U },
+ { 0x3FFE - 0x3fff, 0xA41A9E8FU, 0x5446FB9FU },
+ { 0x3FFE - 0x3fff, 0x85BF3761U, 0x2CEE3C9BU },
+ { 0x3FFE - 0x3fff, 0xA633CD7EU, 0x6771CD8BU },
+ { 0x3FFE - 0x3fff, 0x84A9F9C8U, 0x084A9F9DU },
+ { 0x3FFE - 0x3fff, 0xA8489E60U, 0x0B435A5EU },
+ { 0x3FFE - 0x3fff, 0x83993052U, 0x3FBE3368U },
+ { 0x3FFE - 0x3fff, 0xAA59233CU, 0xCCA4BD49U },
+ { 0x3FFE - 0x3fff, 0x828CBFBEU, 0xB9A020A3U },
+ { 0x3FFE - 0x3fff, 0xAC656DAEU, 0x6BCC4985U },
+ { 0x3FFE - 0x3fff, 0x81848DA8U, 0xFAF0D277U },
+ { 0x3FFE - 0x3fff, 0xAE6D8EE3U, 0x60BB2468U },
+ { 0x3FFE - 0x3fff, 0x80808080U, 0x80808081U },
+ { 0x3FFE - 0x3fff, 0xB07197A2U, 0x3C46C654U },
+};
+
+static struct fpn *__fpu_logn __P((struct fpemu *fe));
+
+/*
+ * natural log - algorithm taken from Motorola FPSP,
+ * except this doesn't bother to check for invalid input.
+ */
+static struct fpn *
+__fpu_logn(fe)
+ struct fpemu *fe;
+{
+ static struct fpn X, F, U, V, W, KLOG2;
+ struct fpn *d;
+ int i, k;
+
+ CPYFPN(&X, &fe->fe_f2);
+
+ /* see if |X-1| < 1/16 approx. */
+ if ((-1 == X.fp_exp && (0xf07d0000U >> (31 - FP_LG)) <= X.fp_mant[0]) ||
+ (0 == X.fp_exp && X.fp_mant[0] <= (0x88410000U >> (31 - FP_LG)))) {
+ /* log near 1 */
+ if (fpu_debug_level & DL_ARITH)
+ printf("__fpu_logn: log near 1\n");
+
+ fpu_const(&fe->fe_f1, 0x32);
+ /* X+1 */
+ d = fpu_add(fe);
+ CPYFPN(&V, d);
+
+ CPYFPN(&fe->fe_f1, &X);
+ fpu_const(&fe->fe_f2, 0x32); /* 1.0 */
+ fe->fe_f2.fp_sign = 1; /* -1.0 */
+ /* X-1 */
+ d = fpu_add(fe);
+ CPYFPN(&fe->fe_f1, d);
+ /* 2(X-1) */
+ fe->fe_f1.fp_exp++; /* *= 2 */
+ CPYFPN(&fe->fe_f2, &V);
+ /* U=2(X-1)/(X+1) */
+ d = fpu_div(fe);
+ CPYFPN(&U, d);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, d);
+ /* V=U*U */
+ d = fpu_mul(fe);
+ CPYFPN(&V, d);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, d);
+ /* W=V*V */
+ d = fpu_mul(fe);
+ CPYFPN(&W, d);
+
+ /* calculate U+U*V*([B1+W*(B3+W*B5)]+[V*(B2+W*B4)]) */
+
+ /* B1+W*(B3+W*B5) part */
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logB5);
+ /* W*B5 */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logB3);
+ /* B3+W*B5 */
+ d = fpu_add(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &W);
+ /* W*(B3+W*B5) */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logB1);
+ /* B1+W*(B3+W*B5) */
+ d = fpu_add(fe);
+ CPYFPN(&X, d);
+
+ /* [V*(B2+W*B4)] part */
+ CPYFPN(&fe->fe_f1, &W);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logB4);
+ /* W*B4 */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logB2);
+ /* B2+W*B4 */
+ d = fpu_add(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &V);
+ /* V*(B2+W*B4) */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &X);
+ /* B1+W*(B3+W*B5)+V*(B2+W*B4) */
+ d = fpu_add(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &V);
+ /* V*(B1+W*(B3+W*B5)+V*(B2+W*B4)) */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &U);
+ /* U*V*(B1+W*(B3+W*B5)+V*(B2+W*B4)) */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &U);
+ /* U+U*V*(B1+W*(B3+W*B5)+V*(B2+W*B4)) */
+ d = fpu_add(fe);
+ } else /* the usual case */ {
+ if (fpu_debug_level & DL_ARITH)
+ printf("__fpu_logn: the usual case. X=(%d,%08x,%08x...)\n",
+ X.fp_exp, X.fp_mant[0], X.fp_mant[1]);
+
+ k = X.fp_exp;
+ /* X <- Y */
+ X.fp_exp = fe->fe_f2.fp_exp = 0;
+
+ /* get the most significant 7 bits of X */
+ F.fp_class = FPC_NUM;
+ F.fp_sign = 0;
+ F.fp_exp = X.fp_exp;
+ F.fp_mant[0] = X.fp_mant[0] & (0xfe000000U >> (31 - FP_LG));
+ F.fp_mant[0] |= (0x01000000U >> (31 - FP_LG));
+ F.fp_mant[1] = F.fp_mant[2] = F.fp_mant[3] = 0;
+ F.fp_sticky = 0;
+
+ if (fpu_debug_level & DL_ARITH) {
+ printf("__fpu_logn: X=Y*2^k=(%d,%08x,%08x...)*2^%d\n",
+ fe->fe_f2.fp_exp, fe->fe_f2.fp_mant[0],
+ fe->fe_f2.fp_mant[1], k);
+ printf("__fpu_logn: F=(%d,%08x,%08x...)\n",
+ F.fp_exp, F.fp_mant[0], F.fp_mant[1]);
+ }
+
+ /* index to the table */
+ i = (F.fp_mant[0] >> (FP_LG - 7)) & 0x7e;
+
+ if (fpu_debug_level & DL_ARITH)
+ printf("__fpu_logn: index to logtbl i=%d(%x)\n", i, i);
+
+ CPYFPN(&fe->fe_f1, &F);
+ /* -F */
+ fe->fe_f1.fp_sign = 1;
+ /* Y-F */
+ d = fpu_add(fe);
+ CPYFPN(&fe->fe_f1, d);
+
+ /* fe_f2 = 1/F */
+ fe->fe_f2.fp_class = FPC_NUM;
+ fe->fe_f2.fp_sign = fe->fe_f2.fp_sticky = fe->fe_f2.fp_mant[3] = 0;
+ fe->fe_f2.fp_exp = logtbl[i].sp_exp;
+ fe->fe_f2.fp_mant[0] = (logtbl[i].sp_m0 >> (31 - FP_LG));
+ fe->fe_f2.fp_mant[1] = (logtbl[i].sp_m0 << (FP_LG + 1)) |
+ (logtbl[i].sp_m1 >> (31 - FP_LG));
+ fe->fe_f2.fp_mant[2] = (u_int)(logtbl[i].sp_m1 << (FP_LG + 1));
+
+ if (fpu_debug_level & DL_ARITH)
+ printf("__fpu_logn: 1/F=(%d,%08x,%08x...)\n", fe->fe_f2.fp_exp,
+ fe->fe_f2.fp_mant[0], fe->fe_f2.fp_mant[1]);
+
+ /* U = (Y-F) * (1/F) */
+ d = fpu_mul(fe);
+ CPYFPN(&U, d);
+
+ /* KLOG2 = K * ln(2) */
+ /* fe_f1 == (fpn)k */
+ fpu_explode(fe, &fe->fe_f1, FTYPE_LNG, &k);
+ (void)fpu_const(&fe->fe_f2, 0x30 /* ln(2) */);
+ if (fpu_debug_level & DL_ARITH) {
+ printf("__fpu_logn: fp(k)=(%d,%08x,%08x...)\n", fe->fe_f1.fp_exp,
+ fe->fe_f1.fp_mant[0], fe->fe_f1.fp_mant[1]);
+ printf("__fpu_logn: ln(2)=(%d,%08x,%08x...)\n", fe->fe_f2.fp_exp,
+ fe->fe_f2.fp_mant[0], fe->fe_f2.fp_mant[1]);
+ }
+ /* K * LOGOF2 */
+ d = fpu_mul(fe);
+ CPYFPN(&KLOG2, d);
+
+ /* V=U*U */
+ CPYFPN(&fe->fe_f1, &U);
+ CPYFPN(&fe->fe_f2, &U);
+ d = fpu_mul(fe);
+ CPYFPN(&V, d);
+
+ /*
+ * approximation of LOG(1+U) by
+ * (U+V*(A1+V*(A3+V*A5)))+(U*V*(A2+V*(A4+V*A6)))
+ */
+
+ /* (U+V*(A1+V*(A3+V*A5))) part */
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logA5);
+ /* V*A5 */
+ d = fpu_mul(fe);
+
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logA3);
+ /* A3+V*A5 */
+ d = fpu_add(fe);
+
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &V);
+ /* V*(A3+V*A5) */
+ d = fpu_mul(fe);
+
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logA1);
+ /* A1+V*(A3+V*A5) */
+ d = fpu_add(fe);
+
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &V);
+ /* V*(A1+V*(A3+V*A5)) */
+ d = fpu_mul(fe);
+
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &U);
+ /* U+V*(A1+V*(A3+V*A5)) */
+ d = fpu_add(fe);
+
+ CPYFPN(&X, d);
+
+ /* (U*V*(A2+V*(A4+V*A6))) part */
+ CPYFPN(&fe->fe_f1, &V);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logA6);
+ /* V*A6 */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logA4);
+ /* A4+V*A6 */
+ d = fpu_add(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &V);
+ /* V*(A4+V*A6) */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ fpu_explode(fe, &fe->fe_f2, FTYPE_DBL, logA2);
+ /* A2+V*(A4+V*A6) */
+ d = fpu_add(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &V);
+ /* V*(A2+V*(A4+V*A6)) */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &U);
+ /* U*V*(A2+V*(A4+V*A6)) */
+ d = fpu_mul(fe);
+ CPYFPN(&fe->fe_f1, d);
+ i++;
+ /* fe_f2 = logtbl[i+1] (== LOG(F)) */
+ fe->fe_f2.fp_class = FPC_NUM;
+ fe->fe_f2.fp_sign = fe->fe_f2.fp_sticky = fe->fe_f2.fp_mant[3] = 0;
+ fe->fe_f2.fp_exp = logtbl[i].sp_exp;
+ fe->fe_f2.fp_mant[0] = (logtbl[i].sp_m0 >> (31 - FP_LG));
+ fe->fe_f2.fp_mant[1] = (logtbl[i].sp_m0 << (FP_LG + 1)) |
+ (logtbl[i].sp_m1 >> (31 - FP_LG));
+ fe->fe_f2.fp_mant[2] = (logtbl[i].sp_m1 << (FP_LG + 1));
+
+ if (fpu_debug_level & DL_ARITH)
+ printf("__fpu_logn: ln(F)=(%d,%08x,%08x,...)\n", fe->fe_f2.fp_exp,
+ fe->fe_f2.fp_mant[0], fe->fe_f2.fp_mant[1]);
+
+ /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
+ d = fpu_add(fe);
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &X);
+ /* LOG(F)+U+V*(A1+V*(A3+V*A5))+U*V*(A2+V*(A4+V*A6)) */
+ d = fpu_add(fe);
+
+ if (fpu_debug_level & DL_ARITH)
+ printf("__fpu_logn: ln(Y)=(%c,%d,%08x,%08x,%08x,%08x)\n",
+ d->fp_sign ? '-' : '+', d->fp_exp,
+ d->fp_mant[0], d->fp_mant[1], d->fp_mant[2], d->fp_mant[3]);
+
+ CPYFPN(&fe->fe_f1, d);
+ CPYFPN(&fe->fe_f2, &KLOG2);
+ /* K*LOGOF2+LOG(F)+U+V*(A1+V*(A3+V*A5))+U*V*(A2+V*(A4+V*A6)) */
+ d = fpu_add(fe);
+ }
+
+ return d;
+}
+
+struct fpn *
+fpu_log10(fe)
+ struct fpemu *fe;
+{
+ struct fpn *fp = &fe->fe_f2;
+ u_int fpsr;
+
+ fpsr = fe->fe_fpsr & ~FPSR_EXCP; /* clear all exceptions */
+
+ if (fp->fp_class >= FPC_NUM) {
+ if (fp->fp_sign) { /* negative number or Inf */
+ fp = fpu_newnan(fe);
+ fpsr |= FPSR_OPERR;
+ } else if (fp->fp_class == FPC_NUM) {
+ /* the real work here */
+ fp = __fpu_logn(fe);
+ if (fp != &fe->fe_f1)
+ CPYFPN(&fe->fe_f1, fp);
+ (void)fpu_const(&fe->fe_f2, 0x31 /* ln(10) */);
+ fp = fpu_div(fe);
+ } /* else if fp == +Inf, return +Inf */
+ } else if (fp->fp_class == FPC_ZERO) {
+ /* return -Inf */
+ fp->fp_class = FPC_INF;
+ fp->fp_sign = 1;
+ fpsr |= FPSR_DZ;
+ } else if (fp->fp_class == FPC_SNAN) {
+ fpsr |= FPSR_SNAN;
+ fp = fpu_newnan(fe);
+ } else {
+ fp = fpu_newnan(fe);
+ }
+
+ fe->fe_fpsr = fpsr;
+
+ return fp;
+}
+
+struct fpn *
+fpu_log2(fe)
+ struct fpemu *fe;
+{
+ struct fpn *fp = &fe->fe_f2;
+ u_int fpsr;
+
+ fpsr = fe->fe_fpsr & ~FPSR_EXCP; /* clear all exceptions */
+
+ if (fp->fp_class >= FPC_NUM) {
+ if (fp->fp_sign) { /* negative number or Inf */
+ fp = fpu_newnan(fe);
+ fpsr |= FPSR_OPERR;
+ } else if (fp->fp_class == FPC_NUM) {
+ /* the real work here */
+ if (fp->fp_mant[0] == FP_1 && fp->fp_mant[1] == 0 &&
+ fp->fp_mant[2] == 0 && fp->fp_mant[3] == 0) {
+ /* fp == 2.0 ^ exp <--> log2(fp) == exp */
+ fpu_explode(fe, &fe->fe_f3, FTYPE_LNG, &fp->fp_exp);
+ fp = &fe->fe_f3;
+ } else {
+ fp = __fpu_logn(fe);
+ if (fp != &fe->fe_f1)
+ CPYFPN(&fe->fe_f1, fp);
+ (void)fpu_const(&fe->fe_f2, 0x30 /* ln(2) */);
+ fp = fpu_div(fe);
+ }
+ } /* else if fp == +Inf, return +Inf */
+ } else if (fp->fp_class == FPC_ZERO) {
+ /* return -Inf */
+ fp->fp_class = FPC_INF;
+ fp->fp_sign = 1;
+ fpsr |= FPSR_DZ;
+ } else if (fp->fp_class == FPC_SNAN) {
+ fpsr |= FPSR_SNAN;
+ fp = fpu_newnan(fe);
+ } else {
+ fp = fpu_newnan(fe);
+ }
+
+ fe->fe_fpsr = fpsr;
+ return fp;
+}
+
+struct fpn *
+fpu_logn(fe)
+ struct fpemu *fe;
+{
+ struct fpn *fp = &fe->fe_f2;
+ u_int fpsr;
+
+ fpsr = fe->fe_fpsr & ~FPSR_EXCP; /* clear all exceptions */
+
+ if (fp->fp_class >= FPC_NUM) {
+ if (fp->fp_sign) { /* negative number or Inf */
+ fp = fpu_newnan(fe);
+ fpsr |= FPSR_OPERR;
+ } else if (fp->fp_class == FPC_NUM) {
+ /* the real work here */
+ fp = __fpu_logn(fe);
+ } /* else if fp == +Inf, return +Inf */
+ } else if (fp->fp_class == FPC_ZERO) {
+ /* return -Inf */
+ fp->fp_class = FPC_INF;
+ fp->fp_sign = 1;
+ fpsr |= FPSR_DZ;
+ } else if (fp->fp_class == FPC_SNAN) {
+ fpsr |= FPSR_SNAN;
+ fp = fpu_newnan(fe);
+ } else {
+ fp = fpu_newnan(fe);
+ }
+
+ fe->fe_fpsr = fpsr;
+
+ return fp;
+}
+
+struct fpn *
+fpu_lognp1(fe)
+ struct fpemu *fe;
+{
+ struct fpn *fp;
+
+ /* build a 1.0 */
+ fp = fpu_const(&fe->fe_f1, 0x32); /* get 1.0 */
+ /* fp = 1.0 + f2 */
+ fp = fpu_add(fe);
+
+ /* copy the result to the src opr */
+ if (&fe->fe_f2 != fp)
+ CPYFPN(&fe->fe_f2, fp);
+
+ return fpu_logn(fe);
+}
--- /dev/null
+/* $NetBSD: fpu_mul.c,v 1.1 1995/11/03 04:47:16 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_mul.c 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Perform an FPU multiply (return x * y).
+ */
+
+#include <sys/types.h>
+
+#include <machine/reg.h>
+
+#include "fpu_arith.h"
+#include "fpu_emulate.h"
+
+/*
+ * The multiplication algorithm for normal numbers is as follows:
+ *
+ * The fraction of the product is built in the usual stepwise fashion.
+ * Each step consists of shifting the accumulator right one bit
+ * (maintaining any guard bits) and, if the next bit in y is set,
+ * adding the multiplicand (x) to the accumulator. Then, in any case,
+ * we advance one bit leftward in y. Algorithmically:
+ *
+ * A = 0;
+ * for (bit = 0; bit < FP_NMANT; bit++) {
+ * sticky |= A & 1, A >>= 1;
+ * if (Y & (1 << bit))
+ * A += X;
+ * }
+ *
+ * (X and Y here represent the mantissas of x and y respectively.)
+ * The resultant accumulator (A) is the product's mantissa. It may
+ * be as large as 11.11111... in binary and hence may need to be
+ * shifted right, but at most one bit.
+ *
+ * Since we do not have efficient multiword arithmetic, we code the
+ * accumulator as four separate words, just like any other mantissa.
+ * We use local `register' variables in the hope that this is faster
+ * than memory. We keep x->fp_mant in locals for the same reason.
+ *
+ * In the algorithm above, the bits in y are inspected one at a time.
+ * We will pick them up 32 at a time and then deal with those 32, one
+ * at a time. Note, however, that we know several things about y:
+ *
+ * - the guard and round bits at the bottom are sure to be zero;
+ *
+ * - often many low bits are zero (y is often from a single or double
+ * precision source);
+ *
+ * - bit FP_NMANT-1 is set, and FP_1*2 fits in a word.
+ *
+ * We can also test for 32-zero-bits swiftly. In this case, the center
+ * part of the loop---setting sticky, shifting A, and not adding---will
+ * run 32 times without adding X to A. We can do a 32-bit shift faster
+ * by simply moving words. Since zeros are common, we optimize this case.
+ * Furthermore, since A is initially zero, we can omit the shift as well
+ * until we reach a nonzero word.
+ */
+struct fpn *
+fpu_mul(fe)
+ register struct fpemu *fe;
+{
+ register struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;
+ register u_int a3, a2, a1, a0, x3, x2, x1, x0, bit, m;
+ register int sticky;
+ FPU_DECL_CARRY
+
+ /*
+ * Put the `heavier' operand on the right (see fpu_emu.h).
+ * Then we will have one of the following cases, taken in the
+ * following order:
+ *
+ * - y = NaN. Implied: if only one is a signalling NaN, y is.
+ * The result is y.
+ * - y = Inf. Implied: x != NaN (is 0, number, or Inf: the NaN
+ * case was taken care of earlier).
+ * If x = 0, the result is NaN. Otherwise the result
+ * is y, with its sign reversed if x is negative.
+ * - x = 0. Implied: y is 0 or number.
+ * The result is 0 (with XORed sign as usual).
+ * - other. Implied: both x and y are numbers.
+ * The result is x * y (XOR sign, multiply bits, add exponents).
+ */
+ ORDER(x, y);
+ if (ISNAN(y)) {
+ y->fp_sign ^= x->fp_sign;
+ return (y);
+ }
+ if (ISINF(y)) {
+ if (ISZERO(x))
+ return (fpu_newnan(fe));
+ y->fp_sign ^= x->fp_sign;
+ return (y);
+ }
+ if (ISZERO(x)) {
+ x->fp_sign ^= y->fp_sign;
+ return (x);
+ }
+
+ /*
+ * Setup. In the code below, the mask `m' will hold the current
+ * mantissa byte from y. The variable `bit' denotes the bit
+ * within m. We also define some macros to deal with everything.
+ */
+ x3 = x->fp_mant[3];
+ x2 = x->fp_mant[2];
+ x1 = x->fp_mant[1];
+ x0 = x->fp_mant[0];
+ sticky = a3 = a2 = a1 = a0 = 0;
+
+#define ADD /* A += X */ \
+ FPU_ADDS(a3, a3, x3); \
+ FPU_ADDCS(a2, a2, x2); \
+ FPU_ADDCS(a1, a1, x1); \
+ FPU_ADDC(a0, a0, x0)
+
+#define SHR1 /* A >>= 1, with sticky */ \
+ sticky |= a3 & 1, a3 = (a3 >> 1) | (a2 << 31), \
+ a2 = (a2 >> 1) | (a1 << 31), a1 = (a1 >> 1) | (a0 << 31), a0 >>= 1
+
+#define SHR32 /* A >>= 32, with sticky */ \
+ sticky |= a3, a3 = a2, a2 = a1, a1 = a0, a0 = 0
+
+#define STEP /* each 1-bit step of the multiplication */ \
+ SHR1; if (bit & m) { ADD; }; bit <<= 1
+
+ /*
+ * We are ready to begin. The multiply loop runs once for each
+ * of the four 32-bit words. Some words, however, are special.
+ * As noted above, the low order bits of Y are often zero. Even
+ * if not, the first loop can certainly skip the guard bits.
+ * The last word of y has its highest 1-bit in position FP_NMANT-1,
+ * so we stop the loop when we move past that bit.
+ */
+ if ((m = y->fp_mant[3]) == 0) {
+ /* SHR32; */ /* unneeded since A==0 */
+ } else {
+ bit = 1 << FP_NG;
+ do {
+ STEP;
+ } while (bit != 0);
+ }
+ if ((m = y->fp_mant[2]) == 0) {
+ SHR32;
+ } else {
+ bit = 1;
+ do {
+ STEP;
+ } while (bit != 0);
+ }
+ if ((m = y->fp_mant[1]) == 0) {
+ SHR32;
+ } else {
+ bit = 1;
+ do {
+ STEP;
+ } while (bit != 0);
+ }
+ m = y->fp_mant[0]; /* definitely != 0 */
+ bit = 1;
+ do {
+ STEP;
+ } while (bit <= m);
+
+ /*
+ * Done with mantissa calculation. Get exponent and handle
+ * 11.111...1 case, then put result in place. We reuse x since
+ * it already has the right class (FP_NUM).
+ */
+ m = x->fp_exp + y->fp_exp;
+ if (a0 >= FP_2) {
+ SHR1;
+ m++;
+ }
+ x->fp_sign ^= y->fp_sign;
+ x->fp_exp = m;
+ x->fp_sticky = sticky;
+ x->fp_mant[3] = a3;
+ x->fp_mant[2] = a2;
+ x->fp_mant[1] = a1;
+ x->fp_mant[0] = a0;
+ return (x);
+}
--- /dev/null
+/* $NetBSD: fpu_rem.c,v 1.1 1995/11/03 04:47:17 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_rem.c 10/24/95
+ */
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <machine/frame.h>
+
+#include "fpu_emulate.h"
+
+/*
+ * ALGORITHM
+ *
+ * Step 1. Save and strip signs of X and Y: signX := sign(X),
+ * signY := sign(Y), X := *X*, Y := *Y*,
+ * signQ := signX EOR signY. Record whether MOD or REM
+ * is requested.
+ *
+ * Step 2. Set L := expo(X)-expo(Y), k := 0, Q := 0.
+ * If (L < 0) then
+ * R := X, go to Step 4.
+ * else
+ * R := 2^(-L)X, j := L.
+ * endif
+ *
+ * Step 3. Perform MOD(X,Y)
+ * 3.1 If R = Y, go to Step 9.
+ * 3.2 If R > Y, then { R := R - Y, Q := Q + 1}
+ * 3.3 If j = 0, go to Step 4.
+ * 3.4 k := k + 1, j := j - 1, Q := 2Q, R := 2R. Go to
+ * Step 3.1.
+ *
+ * Step 4. At this point, R = X - QY = MOD(X,Y). Set
+ * Last_Subtract := false (used in Step 7 below). If
+ * MOD is requested, go to Step 6.
+ *
+ * Step 5. R = MOD(X,Y), but REM(X,Y) is requested.
+ * 5.1 If R < Y/2, then R = MOD(X,Y) = REM(X,Y). Go to
+ * Step 6.
+ * 5.2 If R > Y/2, then { set Last_Subtract := true,
+ * Q := Q + 1, Y := signY*Y }. Go to Step 6.
+ * 5.3 This is the tricky case of R = Y/2. If Q is odd,
+ * then { Q := Q + 1, signX := -signX }.
+ *
+ * Step 6. R := signX*R.
+ *
+ * Step 7. If Last_Subtract = true, R := R - Y.
+ *
+ * Step 8. Return signQ, last 7 bits of Q, and R as required.
+ *
+ * Step 9. At this point, R = 2^(-j)*X - Q Y = Y. Thus,
+ * X = 2^(j)*(Q+1)Y. set Q := 2^(j)*(Q+1),
+ * R := 0. Return signQ, last 7 bits of Q, and R.
+ */
+
+static struct fpn * __fpu_modrem __P((struct fpemu *fe, int modrem));
+
+static struct fpn *
+__fpu_modrem(fe, modrem)
+ struct fpemu *fe;
+ int modrem;
+{
+ static struct fpn X, Y;
+ struct fpn *x, *y, *r;
+ u_int signX, signY, signQ;
+ int i, j, k, l, q;
+ int Last_Subtract;
+
+ CPYFPN(&X, &fe->fe_f1);
+ CPYFPN(&Y, &fe->fe_f2);
+ x = &X;
+ y = &Y;
+ r = &fe->fe_f2;
+
+ /*
+ * Step 1
+ */
+ signX = x->fp_sign;
+ signY = y->fp_sign;
+ signQ = (signX ^ signY);
+ x->fp_sign = y->fp_sign = 0;
+
+ /*
+ * Step 2
+ */
+ l = x->fp_exp - y->fp_exp;
+ k = 0;
+ q = 0;
+ if (l < 0) {
+ goto Step4;
+ } else {
+ CPYFPN(r, x);
+ r->fp_exp -= l;
+ j = l;
+
+ /*
+ * Step 3
+ */
+ while (y->fp_exp != r->fp_exp || y->fp_mant[0] != r->fp_mant[0] ||
+ y->fp_mant[1] != r->fp_mant[1] ||
+ y->fp_mant[2] != r->fp_mant[2] ||
+ y->fp_mant[3] != r->fp_mant[3]) {
+
+ /* Step 3.2 */
+ if (y->fp_exp < r->fp_exp || y->fp_mant[0] < r->fp_mant[0] ||
+ y->fp_mant[1] < r->fp_mant[1] ||
+ y->fp_mant[2] < r->fp_mant[2] ||
+ y->fp_mant[3] < r->fp_mant[3]) {
+ CPYFPN(&fe->fe_f1, r);
+ CPYFPN(&fe->fe_f2, y);
+ fe->fe_f2.fp_sign = 1;
+ r = fpu_add(fe);
+ q++;
+ }
+
+ /* Step 3.3 */
+ if (j == 0)
+ goto Step4;
+
+ /* Step 3.4 */
+ k++;
+ j--;
+ q += q;
+ r->fp_exp++;
+ }
+ /* Step 9 */
+
+ }
+ Step4:
+ Last_Subtract = 0;
+ if (modrem == 0)
+ goto Step6;
+
+ /*
+ * Step 5
+ */
+ /* Step 5.1 */
+ if (r->fp_exp + 1 < y->fp_exp ||
+ r->fp_exp + 1 == y->fp_exp &&
+ (r->fp_mant[0] < y->fp_mant[0] || r->fp_mant[1] < y->fp_mant[1] ||
+ r->fp_mant[2] < y->fp_mant[3] || r->fp_mant[4] < y->fp_mant[4]))
+ /* if r < y/2 */
+ goto Step6;
+ /* Step 5.2 */
+ if (r->fp_exp + 1 != y->fp_exp ||
+ r->fp_mant[0] != y->fp_mant[0] || r->fp_mant[1] != y->fp_mant[1] ||
+ r->fp_mant[2] != y->fp_mant[2] || r->fp_mant[3] != y->fp_mant[3]) {
+ /* if (!(r < y/2) && !(r == y/2)) */
+ Last_Subtract = 1;
+ q++;
+ y->fp_sign = signY;
+ } else {
+ /* Step 5.3 */
+ /* r == y/2 */
+ if (q % 2) {
+ q++;
+ signX = !signX;
+ }
+ }
+
+ Step6:
+ r->fp_sign = signX;
+
+ /*
+ * Step 7
+ */
+ if (Last_Subtract) {
+ CPYFPN(&fe->fe_f1, r);
+ CPYFPN(&fe->fe_f2, y);
+ fe->fe_f2.fp_sign = !y->fp_sign;
+ r = fpu_add(fe);
+ }
+ /*
+ * Step 8
+ */
+ q &= 0x7f;
+ q |= (signQ << 7);
+ fe->fe_fpframe->fpf_fpsr =
+ fe->fe_fpsr =
+ (fe->fe_fpsr & ~FPSR_QTT) | (q << 16);
+ return r;
+
+ Step9:
+ fe->fe_f1.fp_class = FPC_ZERO;
+ q++;
+ q &= 0x7f;
+ q |= (signQ << 7);
+ fe->fe_fpframe->fpf_fpsr =
+ fe->fe_fpsr =
+ (fe->fe_fpsr & ~FPSR_QTT) | (q << 16);
+ return &fe->fe_f1;
+}
+
+struct fpn *
+fpu_rem(fe)
+ struct fpemu *fe;
+{
+ return __fpu_modrem(fe, 1);
+}
+
+struct fpn *
+fpu_mod(fe)
+ struct fpemu *fe;
+{
+ return __fpu_modrem(fe, 0);
+}
--- /dev/null
+/* $NetBSD: fpu_sqrt.c,v 1.1 1995/11/03 04:47:18 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_sqrt.c 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Perform an FPU square root (return sqrt(x)).
+ */
+
+#include <sys/types.h>
+
+#include <machine/reg.h>
+
+#include "fpu_arith.h"
+#include "fpu_emulate.h"
+
+/*
+ * Our task is to calculate the square root of a floating point number x0.
+ * This number x normally has the form:
+ *
+ * exp
+ * x = mant * 2 (where 1 <= mant < 2 and exp is an integer)
+ *
+ * This can be left as it stands, or the mantissa can be doubled and the
+ * exponent decremented:
+ *
+ * exp-1
+ * x = (2 * mant) * 2 (where 2 <= 2 * mant < 4)
+ *
+ * If the exponent `exp' is even, the square root of the number is best
+ * handled using the first form, and is by definition equal to:
+ *
+ * exp/2
+ * sqrt(x) = sqrt(mant) * 2
+ *
+ * If exp is odd, on the other hand, it is convenient to use the second
+ * form, giving:
+ *
+ * (exp-1)/2
+ * sqrt(x) = sqrt(2 * mant) * 2
+ *
+ * In the first case, we have
+ *
+ * 1 <= mant < 2
+ *
+ * and therefore
+ *
+ * sqrt(1) <= sqrt(mant) < sqrt(2)
+ *
+ * while in the second case we have
+ *
+ * 2 <= 2*mant < 4
+ *
+ * and therefore
+ *
+ * sqrt(2) <= sqrt(2*mant) < sqrt(4)
+ *
+ * so that in any case, we are sure that
+ *
+ * sqrt(1) <= sqrt(n * mant) < sqrt(4), n = 1 or 2
+ *
+ * or
+ *
+ * 1 <= sqrt(n * mant) < 2, n = 1 or 2.
+ *
+ * This root is therefore a properly formed mantissa for a floating
+ * point number. The exponent of sqrt(x) is either exp/2 or (exp-1)/2
+ * as above. This leaves us with the problem of finding the square root
+ * of a fixed-point number in the range [1..4).
+ *
+ * Though it may not be instantly obvious, the following square root
+ * algorithm works for any integer x of an even number of bits, provided
+ * that no overflows occur:
+ *
+ * let q = 0
+ * for k = NBITS-1 to 0 step -1 do -- for each digit in the answer...
+ * x *= 2 -- multiply by radix, for next digit
+ * if x >= 2q + 2^k then -- if adding 2^k does not
+ * x -= 2q + 2^k -- exceed the correct root,
+ * q += 2^k -- add 2^k and adjust x
+ * fi
+ * done
+ * sqrt = q / 2^(NBITS/2) -- (and any remainder is in x)
+ *
+ * If NBITS is odd (so that k is initially even), we can just add another
+ * zero bit at the top of x. Doing so means that q is not going to acquire
+ * a 1 bit in the first trip around the loop (since x0 < 2^NBITS). If the
+ * final value in x is not needed, or can be off by a factor of 2, this is
+ * equivalant to moving the `x *= 2' step to the bottom of the loop:
+ *
+ * for k = NBITS-1 to 0 step -1 do if ... fi; x *= 2; done
+ *
+ * and the result q will then be sqrt(x0) * 2^floor(NBITS / 2).
+ * (Since the algorithm is destructive on x, we will call x's initial
+ * value, for which q is some power of two times its square root, x0.)
+ *
+ * If we insert a loop invariant y = 2q, we can then rewrite this using
+ * C notation as:
+ *
+ * q = y = 0; x = x0;
+ * for (k = NBITS; --k >= 0;) {
+ * #if (NBITS is even)
+ * x *= 2;
+ * #endif
+ * t = y + (1 << k);
+ * if (x >= t) {
+ * x -= t;
+ * q += 1 << k;
+ * y += 1 << (k + 1);
+ * }
+ * #if (NBITS is odd)
+ * x *= 2;
+ * #endif
+ * }
+ *
+ * If x0 is fixed point, rather than an integer, we can simply alter the
+ * scale factor between q and sqrt(x0). As it happens, we can easily arrange
+ * for the scale factor to be 2**0 or 1, so that sqrt(x0) == q.
+ *
+ * In our case, however, x0 (and therefore x, y, q, and t) are multiword
+ * integers, which adds some complication. But note that q is built one
+ * bit at a time, from the top down, and is not used itself in the loop
+ * (we use 2q as held in y instead). This means we can build our answer
+ * in an integer, one word at a time, which saves a bit of work. Also,
+ * since 1 << k is always a `new' bit in q, 1 << k and 1 << (k+1) are
+ * `new' bits in y and we can set them with an `or' operation rather than
+ * a full-blown multiword add.
+ *
+ * We are almost done, except for one snag. We must prove that none of our
+ * intermediate calculations can overflow. We know that x0 is in [1..4)
+ * and therefore the square root in q will be in [1..2), but what about x,
+ * y, and t?
+ *
+ * We know that y = 2q at the beginning of each loop. (The relation only
+ * fails temporarily while y and q are being updated.) Since q < 2, y < 4.
+ * The sum in t can, in our case, be as much as y+(1<<1) = y+2 < 6, and.
+ * Furthermore, we can prove with a bit of work that x never exceeds y by
+ * more than 2, so that even after doubling, 0 <= x < 8. (This is left as
+ * an exercise to the reader, mostly because I have become tired of working
+ * on this comment.)
+ *
+ * If our floating point mantissas (which are of the form 1.frac) occupy
+ * B+1 bits, our largest intermediary needs at most B+3 bits, or two extra.
+ * In fact, we want even one more bit (for a carry, to avoid compares), or
+ * three extra. There is a comment in fpu_emu.h reminding maintainers of
+ * this, so we have some justification in assuming it.
+ */
+struct fpn *
+fpu_sqrt(fe)
+ struct fpemu *fe;
+{
+ register struct fpn *x = &fe->fe_f2;
+ register u_int bit, q, tt;
+ register u_int x0, x1, x2, x3;
+ register u_int y0, y1, y2, y3;
+ register u_int d0, d1, d2, d3;
+ register int e;
+ FPU_DECL_CARRY
+
+ /*
+ * Take care of special cases first. In order:
+ *
+ * sqrt(NaN) = NaN
+ * sqrt(+0) = +0
+ * sqrt(-0) = -0
+ * sqrt(x < 0) = NaN (including sqrt(-Inf))
+ * sqrt(+Inf) = +Inf
+ *
+ * Then all that remains are numbers with mantissas in [1..2).
+ */
+ if (ISNAN(x) || ISZERO(x))
+ return (x);
+ if (x->fp_sign)
+ return (fpu_newnan(fe));
+ if (ISINF(x))
+ return (x);
+
+ /*
+ * Calculate result exponent. As noted above, this may involve
+ * doubling the mantissa. We will also need to double x each
+ * time around the loop, so we define a macro for this here, and
+ * we break out the multiword mantissa.
+ */
+#ifdef FPU_SHL1_BY_ADD
+#define DOUBLE_X { \
+ FPU_ADDS(x3, x3, x3); FPU_ADDCS(x2, x2, x2); \
+ FPU_ADDCS(x1, x1, x1); FPU_ADDC(x0, x0, x0); \
+}
+#else
+#define DOUBLE_X { \
+ x0 = (x0 << 1) | (x1 >> 31); x1 = (x1 << 1) | (x2 >> 31); \
+ x2 = (x2 << 1) | (x3 >> 31); x3 <<= 1; \
+}
+#endif
+#if (FP_NMANT & 1) != 0
+# define ODD_DOUBLE DOUBLE_X
+# define EVEN_DOUBLE /* nothing */
+#else
+# define ODD_DOUBLE /* nothing */
+# define EVEN_DOUBLE DOUBLE_X
+#endif
+ x0 = x->fp_mant[0];
+ x1 = x->fp_mant[1];
+ x2 = x->fp_mant[2];
+ x3 = x->fp_mant[3];
+ e = x->fp_exp;
+ if (e & 1) /* exponent is odd; use sqrt(2mant) */
+ DOUBLE_X;
+ /* THE FOLLOWING ASSUMES THAT RIGHT SHIFT DOES SIGN EXTENSION */
+ x->fp_exp = e >> 1; /* calculates (e&1 ? (e-1)/2 : e/2 */
+
+ /*
+ * Now calculate the mantissa root. Since x is now in [1..4),
+ * we know that the first trip around the loop will definitely
+ * set the top bit in q, so we can do that manually and start
+ * the loop at the next bit down instead. We must be sure to
+ * double x correctly while doing the `known q=1.0'.
+ *
+ * We do this one mantissa-word at a time, as noted above, to
+ * save work. To avoid `(1 << 31) << 1', we also do the top bit
+ * outside of each per-word loop.
+ *
+ * The calculation `t = y + bit' breaks down into `t0 = y0, ...,
+ * t3 = y3, t? |= bit' for the appropriate word. Since the bit
+ * is always a `new' one, this means that three of the `t?'s are
+ * just the corresponding `y?'; we use `#define's here for this.
+ * The variable `tt' holds the actual `t?' variable.
+ */
+
+ /* calculate q0 */
+#define t0 tt
+ bit = FP_1;
+ EVEN_DOUBLE;
+ /* if (x >= (t0 = y0 | bit)) { */ /* always true */
+ q = bit;
+ x0 -= bit;
+ y0 = bit << 1;
+ /* } */
+ ODD_DOUBLE;
+ while ((bit >>= 1) != 0) { /* for remaining bits in q0 */
+ EVEN_DOUBLE;
+ t0 = y0 | bit; /* t = y + bit */
+ if (x0 >= t0) { /* if x >= t then */
+ x0 -= t0; /* x -= t */
+ q |= bit; /* q += bit */
+ y0 |= bit << 1; /* y += bit << 1 */
+ }
+ ODD_DOUBLE;
+ }
+ x->fp_mant[0] = q;
+#undef t0
+
+ /* calculate q1. note (y0&1)==0. */
+#define t0 y0
+#define t1 tt
+ q = 0;
+ y1 = 0;
+ bit = 1 << 31;
+ EVEN_DOUBLE;
+ t1 = bit;
+ FPU_SUBS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0); /* d = x - t */
+ if ((int)d0 >= 0) { /* if d >= 0 (i.e., x >= t) then */
+ x0 = d0, x1 = d1; /* x -= t */
+ q = bit; /* q += bit */
+ y0 |= 1; /* y += bit << 1 */
+ }
+ ODD_DOUBLE;
+ while ((bit >>= 1) != 0) { /* for remaining bits in q1 */
+ EVEN_DOUBLE; /* as before */
+ t1 = y1 | bit;
+ FPU_SUBS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1;
+ q |= bit;
+ y1 |= bit << 1;
+ }
+ ODD_DOUBLE;
+ }
+ x->fp_mant[1] = q;
+#undef t1
+
+ /* calculate q2. note (y1&1)==0; y0 (aka t0) is fixed. */
+#define t1 y1
+#define t2 tt
+ q = 0;
+ y2 = 0;
+ bit = 1 << 31;
+ EVEN_DOUBLE;
+ t2 = bit;
+ FPU_SUBS(d2, x2, t2);
+ FPU_SUBCS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2;
+ q |= bit;
+ y1 |= 1; /* now t1, y1 are set in concrete */
+ }
+ ODD_DOUBLE;
+ while ((bit >>= 1) != 0) {
+ EVEN_DOUBLE;
+ t2 = y2 | bit;
+ FPU_SUBS(d2, x2, t2);
+ FPU_SUBCS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2;
+ q |= bit;
+ y2 |= bit << 1;
+ }
+ ODD_DOUBLE;
+ }
+ x->fp_mant[2] = q;
+#undef t2
+
+ /* calculate q3. y0, t0, y1, t1 all fixed; y2, t2, almost done. */
+#define t2 y2
+#define t3 tt
+ q = 0;
+ y3 = 0;
+ bit = 1 << 31;
+ EVEN_DOUBLE;
+ t3 = bit;
+ FPU_SUBS(d3, x3, t3);
+ FPU_SUBCS(d2, x2, t2);
+ FPU_SUBCS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ ODD_DOUBLE;
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2;
+ q |= bit;
+ y2 |= 1;
+ }
+ while ((bit >>= 1) != 0) {
+ EVEN_DOUBLE;
+ t3 = y3 | bit;
+ FPU_SUBS(d3, x3, t3);
+ FPU_SUBCS(d2, x2, t2);
+ FPU_SUBCS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2;
+ q |= bit;
+ y3 |= bit << 1;
+ }
+ ODD_DOUBLE;
+ }
+ x->fp_mant[3] = q;
+
+ /*
+ * The result, which includes guard and round bits, is exact iff
+ * x is now zero; any nonzero bits in x represent sticky bits.
+ */
+ x->fp_sticky = x0 | x1 | x2 | x3;
+ return (x);
+}
--- /dev/null
+/* $NetBSD: fpu_subr.c,v 1.1 1995/11/03 04:47:19 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_subr.c 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * FPU subroutines.
+ */
+
+#include <sys/types.h>
+
+#include <machine/reg.h>
+
+#include "fpu_emulate.h"
+#include "fpu_arith.h"
+
+/*
+ * Shift the given number right rsh bits. Any bits that `fall off' will get
+ * shoved into the sticky field; we return the resulting sticky. Note that
+ * shifting NaNs is legal (this will never shift all bits out); a NaN's
+ * sticky field is ignored anyway.
+ */
+int
+fpu_shr(register struct fpn *fp, register int rsh)
+{
+ register u_int m0, m1, m2, m3, s;
+ register int lsh;
+
+#ifdef DIAGNOSTIC
+ if (rsh <= 0 || (fp->fp_class != FPC_NUM && !ISNAN(fp)))
+ panic("fpu_rightshift 1");
+#endif
+
+ m0 = fp->fp_mant[0];
+ m1 = fp->fp_mant[1];
+ m2 = fp->fp_mant[2];
+ m3 = fp->fp_mant[3];
+
+ /* If shifting all the bits out, take a shortcut. */
+ if (rsh >= FP_NMANT) {
+#ifdef DIAGNOSTIC
+ if ((m0 | m1 | m2 | m3) == 0)
+ panic("fpu_rightshift 2");
+#endif
+ fp->fp_mant[0] = 0;
+ fp->fp_mant[1] = 0;
+ fp->fp_mant[2] = 0;
+ fp->fp_mant[3] = 0;
+#ifdef notdef
+ if ((m0 | m1 | m2 | m3) == 0)
+ fp->fp_class = FPC_ZERO;
+ else
+#endif
+ fp->fp_sticky = 1;
+ return (1);
+ }
+
+ /* Squish out full words. */
+ s = fp->fp_sticky;
+ if (rsh >= 32 * 3) {
+ s |= m3 | m2 | m1;
+ m3 = m0, m2 = 0, m1 = 0, m0 = 0;
+ } else if (rsh >= 32 * 2) {
+ s |= m3 | m2;
+ m3 = m1, m2 = m0, m1 = 0, m0 = 0;
+ } else if (rsh >= 32) {
+ s |= m3;
+ m3 = m2, m2 = m1, m1 = m0, m0 = 0;
+ }
+
+ /* Handle any remaining partial word. */
+ if ((rsh &= 31) != 0) {
+ lsh = 32 - rsh;
+ s |= m3 << lsh;
+ m3 = (m3 >> rsh) | (m2 << lsh);
+ m2 = (m2 >> rsh) | (m1 << lsh);
+ m1 = (m1 >> rsh) | (m0 << lsh);
+ m0 >>= rsh;
+ }
+ fp->fp_mant[0] = m0;
+ fp->fp_mant[1] = m1;
+ fp->fp_mant[2] = m2;
+ fp->fp_mant[3] = m3;
+ fp->fp_sticky = s;
+ return (s);
+}
+
+/*
+ * Force a number to be normal, i.e., make its fraction have all zero
+ * bits before FP_1, then FP_1, then all 1 bits. This is used for denorms
+ * and (sometimes) for intermediate results.
+ *
+ * Internally, this may use a `supernormal' -- a number whose fp_mant
+ * is greater than or equal to 2.0 -- so as a side effect you can hand it
+ * a supernormal and it will fix it (provided fp->fp_mant[3] == 0).
+ */
+void
+fpu_norm(register struct fpn *fp)
+{
+ register u_int m0, m1, m2, m3, top, sup, nrm;
+ register int lsh, rsh, exp;
+
+ exp = fp->fp_exp;
+ m0 = fp->fp_mant[0];
+ m1 = fp->fp_mant[1];
+ m2 = fp->fp_mant[2];
+ m3 = fp->fp_mant[3];
+
+ /* Handle severe subnormals with 32-bit moves. */
+ if (m0 == 0) {
+ if (m1)
+ m0 = m1, m1 = m2, m2 = m3, m3 = 0, exp -= 32;
+ else if (m2)
+ m0 = m2, m1 = m3, m2 = 0, m3 = 0, exp -= 2 * 32;
+ else if (m3)
+ m0 = m3, m1 = 0, m2 = 0, m3 = 0, exp -= 3 * 32;
+ else {
+ fp->fp_class = FPC_ZERO;
+ return;
+ }
+ }
+
+ /* Now fix any supernormal or remaining subnormal. */
+ nrm = FP_1;
+ sup = nrm << 1;
+ if (m0 >= sup) {
+ /*
+ * We have a supernormal number. We need to shift it right.
+ * We may assume m3==0.
+ */
+ for (rsh = 1, top = m0 >> 1; top >= sup; rsh++) /* XXX slow */
+ top >>= 1;
+ exp += rsh;
+ lsh = 32 - rsh;
+ m3 = m2 << lsh;
+ m2 = (m2 >> rsh) | (m1 << lsh);
+ m1 = (m1 >> rsh) | (m0 << lsh);
+ m0 = top;
+ } else if (m0 < nrm) {
+ /*
+ * We have a regular denorm (a subnormal number), and need
+ * to shift it left.
+ */
+ for (lsh = 1, top = m0 << 1; top < nrm; lsh++) /* XXX slow */
+ top <<= 1;
+ exp -= lsh;
+ rsh = 32 - lsh;
+ m0 = top | (m1 >> rsh);
+ m1 = (m1 << lsh) | (m2 >> rsh);
+ m2 = (m2 << lsh) | (m3 >> rsh);
+ m3 <<= lsh;
+ }
+
+ fp->fp_exp = exp;
+ fp->fp_mant[0] = m0;
+ fp->fp_mant[1] = m1;
+ fp->fp_mant[2] = m2;
+ fp->fp_mant[3] = m3;
+}
+
+/*
+ * Concoct a `fresh' Quiet NaN per Appendix N.
+ * As a side effect, we set OPERR for the current exceptions.
+ */
+struct fpn *
+fpu_newnan(register struct fpemu *fe)
+{
+ register struct fpn *fp;
+
+ fe->fe_fpsr |= FPSR_OPERR;
+ fp = &fe->fe_f3;
+ fp->fp_class = FPC_QNAN;
+ fp->fp_sign = 0;
+ fp->fp_mant[0] = FP_1 - 1;
+ fp->fp_mant[1] = fp->fp_mant[2] = fp->fp_mant[3] = ~0;
+ return (fp);
+}
--- /dev/null
+/* $NetBSD: fpu_trig.c,v 1.1 1995/11/03 04:47:20 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Ken Nakata
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_trig.c 10/24/95
+ */
+
+#include "fpu_emulate.h"
+
+struct fpn *
+fpu_acos(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_asin(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_atan(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_cos(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_sin(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_tan(fe)
+ struct fpemu *fe;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
+
+struct fpn *
+fpu_sincos(fe, regc)
+ struct fpemu *fe;
+ int regc;
+{
+ /* stub */
+ return &fe->fe_f2;
+}
--- /dev/null
+/* $NetBSD: ieee.h,v 1.1 1995/11/03 04:47:21 briggs Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ieee.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * ieee.h defines the machine-dependent layout of the machine's IEEE
+ * floating point. It does *not* define (yet?) any of the rounding
+ * mode bits, exceptions, and so forth.
+ */
+
+/*
+ * Define the number of bits in each fraction and exponent.
+ *
+ * k k+1
+ * Note that 1.0 x 2 == 0.1 x 2 and that denorms are represented
+ *
+ * (-exp_bias+1)
+ * as fractions that look like 0.fffff x 2 . This means that
+ *
+ * -126
+ * the number 0.10000 x 2 , for instance, is the same as the normalized
+ *
+ * -127 -128
+ * float 1.0 x 2 . Thus, to represent 2 , we need one leading zero
+ *
+ * -129
+ * in the fraction; to represent 2 , we need two, and so on. This
+ *
+ * (-exp_bias-fracbits+1)
+ * implies that the smallest denormalized number is 2
+ *
+ * for whichever format we are talking about: for single precision, for
+ *
+ * -126 -149
+ * instance, we get .00000000000000000000001 x 2 , or 1.0 x 2 , and
+ *
+ * -149 == -127 - 23 + 1.
+ */
+#define SNG_EXPBITS 8
+#define SNG_FRACBITS 23
+
+#define DBL_EXPBITS 11
+#define DBL_FRACBITS 52
+
+#define EXT_EXPBITS 15
+#define EXT_FRACBITS 64
+
+struct ieee_single {
+ u_int sng_sign:1;
+ u_int sng_exp:8;
+ u_int sng_frac:23;
+};
+
+struct ieee_double {
+ u_int dbl_sign:1;
+ u_int dbl_exp:11;
+ u_int dbl_frach:20;
+ u_int dbl_fracl;
+};
+
+struct ieee_ext {
+ u_int ext_sign:1;
+ u_int ext_exp:15;
+ u_int ext_zero:16;
+ u_int ext_int:1;
+ u_int ext_frach:31;
+ u_int ext_fracl;
+};
+
+/*
+ * Floats whose exponent is in [1..INFNAN) (of whatever type) are
+ * `normal'. Floats whose exponent is INFNAN are either Inf or NaN.
+ * Floats whose exponent is zero are either zero (iff all fraction
+ * bits are zero) or subnormal values.
+ *
+ * A NaN is a `signalling NaN' if its QUIETNAN bit is clear in its
+ * high fraction; if the bit is set, it is a `quiet NaN'.
+ */
+#define SNG_EXP_INFNAN 255
+#define DBL_EXP_INFNAN 2047
+#define EXT_EXP_INFNAN 32767
+
+#if 0
+#define SNG_QUIETNAN (1 << 22)
+#define DBL_QUIETNAN (1 << 19)
+#define EXT_QUIETNAN (1 << 15)
+#endif
+
+/*
+ * Exponent biases.
+ */
+#define SNG_EXP_BIAS 127
+#define DBL_EXP_BIAS 1023
+#define EXT_EXP_BIAS 16383