From 09375bd46c7f54d65aa54f9940346ccc5c92d31d Mon Sep 17 00:00:00 2001 From: deraadt Date: Thu, 14 Dec 1995 04:53:01 +0000 Subject: [PATCH] from netbsd: Still incomplete, but much more complete FPE from Ken Nakata . This emulator does not yet emulate the following functions: FSINH, FETOXM1, FTANH, FATAN, FASIN, FATANH, FSIN, FTAN, FETOX, FTWOTOX, FTENTOX, FCOSH, FACOS, FCOS, FSINCOS It is sufficient, however, to allow programs like df, w, and newfs, to run to completion with correct results. Portions of this code were based on the sparc fpe and on initial work by gwr. --- sys/arch/m68k/fpe/README | 167 +++ sys/arch/m68k/fpe/files.fpe | 24 + sys/arch/m68k/fpe/fpu_add.c | 211 ++++ sys/arch/m68k/fpe/fpu_arith.h | 153 +++ sys/arch/m68k/fpe/fpu_arith_proto.h | 94 ++ sys/arch/m68k/fpe/fpu_calcea.c | 710 ++++++++++++ sys/arch/m68k/fpe/fpu_div.c | 269 +++++ sys/arch/m68k/fpe/fpu_emulate.c | 1590 ++++++++++++++++++--------- sys/arch/m68k/fpe/fpu_emulate.h | 335 ++++++ sys/arch/m68k/fpe/fpu_exp.c | 70 ++ sys/arch/m68k/fpe/fpu_explode.c | 289 +++++ sys/arch/m68k/fpe/fpu_fmovecr.c | 117 ++ sys/arch/m68k/fpe/fpu_fscale.c | 329 ++++++ sys/arch/m68k/fpe/fpu_fstore.c | 127 +++ sys/arch/m68k/fpe/fpu_getexp.c | 76 ++ sys/arch/m68k/fpe/fpu_hyperb.c | 72 ++ sys/arch/m68k/fpe/fpu_implode.c | 483 ++++++++ sys/arch/m68k/fpe/fpu_int.c | 122 ++ sys/arch/m68k/fpe/fpu_log.c | 594 ++++++++++ sys/arch/m68k/fpe/fpu_mul.c | 226 ++++ sys/arch/m68k/fpe/fpu_rem.c | 235 ++++ sys/arch/m68k/fpe/fpu_sqrt.c | 398 +++++++ sys/arch/m68k/fpe/fpu_subr.c | 218 ++++ sys/arch/m68k/fpe/fpu_trig.c | 91 ++ sys/arch/m68k/fpe/ieee.h | 136 +++ 25 files changed, 6606 insertions(+), 530 deletions(-) create mode 100644 sys/arch/m68k/fpe/README create mode 100644 sys/arch/m68k/fpe/files.fpe create mode 100644 sys/arch/m68k/fpe/fpu_add.c create mode 100644 sys/arch/m68k/fpe/fpu_arith.h create mode 100644 sys/arch/m68k/fpe/fpu_arith_proto.h create mode 100644 sys/arch/m68k/fpe/fpu_calcea.c create mode 100644 sys/arch/m68k/fpe/fpu_div.c create mode 100644 sys/arch/m68k/fpe/fpu_emulate.h create mode 100644 sys/arch/m68k/fpe/fpu_exp.c create mode 100644 sys/arch/m68k/fpe/fpu_explode.c create mode 100644 sys/arch/m68k/fpe/fpu_fmovecr.c create mode 100644 sys/arch/m68k/fpe/fpu_fscale.c create mode 100644 sys/arch/m68k/fpe/fpu_fstore.c create mode 100644 sys/arch/m68k/fpe/fpu_getexp.c create mode 100644 sys/arch/m68k/fpe/fpu_hyperb.c create mode 100644 sys/arch/m68k/fpe/fpu_implode.c create mode 100644 sys/arch/m68k/fpe/fpu_int.c create mode 100644 sys/arch/m68k/fpe/fpu_log.c create mode 100644 sys/arch/m68k/fpe/fpu_mul.c create mode 100644 sys/arch/m68k/fpe/fpu_rem.c create mode 100644 sys/arch/m68k/fpe/fpu_sqrt.c create mode 100644 sys/arch/m68k/fpe/fpu_subr.c create mode 100644 sys/arch/m68k/fpe/fpu_trig.c create mode 100644 sys/arch/m68k/fpe/ieee.h diff --git a/sys/arch/m68k/fpe/README b/sys/arch/m68k/fpe/README new file mode 100644 index 00000000000..2605d310b80 --- /dev/null +++ b/sys/arch/m68k/fpe/README @@ -0,0 +1,167 @@ +* $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. diff --git a/sys/arch/m68k/fpe/files.fpe b/sys/arch/m68k/fpe/files.fpe new file mode 100644 index 00000000000..416fcc417d1 --- /dev/null +++ b/sys/arch/m68k/fpe/files.fpe @@ -0,0 +1,24 @@ +# $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 diff --git a/sys/arch/m68k/fpe/fpu_add.c b/sys/arch/m68k/fpe/fpu_add.c new file mode 100644 index 00000000000..48e332b3dcd --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_add.c @@ -0,0 +1,211 @@ +/* $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 + +#include + +#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); +} diff --git a/sys/arch/m68k/fpe/fpu_arith.h b/sys/arch/m68k/fpe/fpu_arith.h new file mode 100644 index 00000000000..e5f380708d6 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_arith.h @@ -0,0 +1,153 @@ +/* $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 diff --git a/sys/arch/m68k/fpe/fpu_arith_proto.h b/sys/arch/m68k/fpe/fpu_arith_proto.h new file mode 100644 index 00000000000..c85422c04a7 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_arith_proto.h @@ -0,0 +1,94 @@ +/* $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_ */ diff --git a/sys/arch/m68k/fpe/fpu_calcea.c b/sys/arch/m68k/fpe/fpu_calcea.c new file mode 100644 index 00000000000..6fe69572601 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_calcea.c @@ -0,0 +1,710 @@ +/* $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 +#include +#include +#include + +#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; +} diff --git a/sys/arch/m68k/fpe/fpu_div.c b/sys/arch/m68k/fpe/fpu_div.c new file mode 100644 index 00000000000..8b6ec222a69 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_div.c @@ -0,0 +1,269 @@ +/* $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 + +#include + +#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); +} diff --git a/sys/arch/m68k/fpe/fpu_emulate.c b/sys/arch/m68k/fpe/fpu_emulate.c index 7fd5cd3dfed..ed86855d09a 100644 --- a/sys/arch/m68k/fpe/fpu_emulate.c +++ b/sys/arch/m68k/fpe/fpu_emulate.c @@ -1,7 +1,8 @@ -/* $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 @@ -39,153 +40,390 @@ #include #include -#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 + * type 0: fmovem * Separated out of fpu_emul_type0 for efficiency. * In this function, we know: * (opcode & 0x01C0) == 0 @@ -194,455 +432,747 @@ int fpu_emulate(struct frame *frame, struct fpframe *fpf) * 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; } diff --git a/sys/arch/m68k/fpe/fpu_emulate.h b/sys/arch/m68k/fpe/fpu_emulate.h new file mode 100644 index 00000000000..ae31c2bfe15 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_emulate.h @@ -0,0 +1,335 @@ +/* $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 + +/* + * 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 + * or 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_ */ diff --git a/sys/arch/m68k/fpe/fpu_exp.c b/sys/arch/m68k/fpe/fpu_exp.c new file mode 100644 index 00000000000..5e7966bf966 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_exp.c @@ -0,0 +1,70 @@ +/* $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; +} diff --git a/sys/arch/m68k/fpe/fpu_explode.c b/sys/arch/m68k/fpe/fpu_explode.c new file mode 100644 index 00000000000..c5c8bd2c9d0 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_explode.c @@ -0,0 +1,289 @@ +/* $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 + +#include "ieee.h" +#include + +#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; +} diff --git a/sys/arch/m68k/fpe/fpu_fmovecr.c b/sys/arch/m68k/fpe/fpu_fmovecr.c new file mode 100644 index 00000000000..7c244b736ed --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_fmovecr.c @@ -0,0 +1,117 @@ +/* $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 +#include + +#include + +#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; +} diff --git a/sys/arch/m68k/fpe/fpu_fscale.c b/sys/arch/m68k/fpe/fpu_fscale.c new file mode 100644 index 00000000000..ad98d165345 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_fscale.c @@ -0,0 +1,329 @@ +/* $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 +#include +#include + +#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; +} diff --git a/sys/arch/m68k/fpe/fpu_fstore.c b/sys/arch/m68k/fpe/fpu_fstore.c new file mode 100644 index 00000000000..34de45f10fc --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_fstore.c @@ -0,0 +1,127 @@ +/* $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 +#include +#include + +#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; +} diff --git a/sys/arch/m68k/fpe/fpu_getexp.c b/sys/arch/m68k/fpe/fpu_getexp.c new file mode 100644 index 00000000000..c2fe60531ab --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_getexp.c @@ -0,0 +1,76 @@ +/* $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 + +#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; +} + diff --git a/sys/arch/m68k/fpe/fpu_hyperb.c b/sys/arch/m68k/fpe/fpu_hyperb.c new file mode 100644 index 00000000000..2405eff1f66 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_hyperb.c @@ -0,0 +1,72 @@ +/* $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; +} diff --git a/sys/arch/m68k/fpe/fpu_implode.c b/sys/arch/m68k/fpe/fpu_implode.c new file mode 100644 index 00000000000..2e47ca40494 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_implode.c @@ -0,0 +1,483 @@ +/* $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 + +#include "ieee.h" +#include + +#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"); + } +} diff --git a/sys/arch/m68k/fpe/fpu_int.c b/sys/arch/m68k/fpe/fpu_int.c new file mode 100644 index 00000000000..23a9b09f17c --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_int.c @@ -0,0 +1,122 @@ +/* $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 + +#include + +#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; +} diff --git a/sys/arch/m68k/fpe/fpu_log.c b/sys/arch/m68k/fpe/fpu_log.c new file mode 100644 index 00000000000..19788c39e97 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_log.c @@ -0,0 +1,594 @@ +/* $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 + +#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); +} diff --git a/sys/arch/m68k/fpe/fpu_mul.c b/sys/arch/m68k/fpe/fpu_mul.c new file mode 100644 index 00000000000..7f150478c3a --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_mul.c @@ -0,0 +1,226 @@ +/* $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 + +#include + +#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); +} diff --git a/sys/arch/m68k/fpe/fpu_rem.c b/sys/arch/m68k/fpe/fpu_rem.c new file mode 100644 index 00000000000..ddf24ec5725 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_rem.c @@ -0,0 +1,235 @@ +/* $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 +#include +#include + +#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); +} diff --git a/sys/arch/m68k/fpe/fpu_sqrt.c b/sys/arch/m68k/fpe/fpu_sqrt.c new file mode 100644 index 00000000000..23cdea6fab7 --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_sqrt.c @@ -0,0 +1,398 @@ +/* $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 + +#include + +#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); +} diff --git a/sys/arch/m68k/fpe/fpu_subr.c b/sys/arch/m68k/fpe/fpu_subr.c new file mode 100644 index 00000000000..fed1294ce2f --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_subr.c @@ -0,0 +1,218 @@ +/* $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 + +#include + +#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); +} diff --git a/sys/arch/m68k/fpe/fpu_trig.c b/sys/arch/m68k/fpe/fpu_trig.c new file mode 100644 index 00000000000..0358c84878e --- /dev/null +++ b/sys/arch/m68k/fpe/fpu_trig.c @@ -0,0 +1,91 @@ +/* $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; +} diff --git a/sys/arch/m68k/fpe/ieee.h b/sys/arch/m68k/fpe/ieee.h new file mode 100644 index 00000000000..07ac5130af2 --- /dev/null +++ b/sys/arch/m68k/fpe/ieee.h @@ -0,0 +1,136 @@ +/* $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 -- 2.20.1