[BACK]Return to ieee_invop.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / pc532 / fpu

File: [cvs.NetBSD.org] / src / sys / arch / pc532 / fpu / Attic / ieee_invop.c (download)

Revision 1.5, Tue Apr 1 16:35:22 1997 UTC (24 years ago) by matthias
Branch: MAIN
CVS Tags: wrstuden-devbsize-base, wrstuden-devbsize-19991221, wrstuden-devbsize, thorpej_scsipi_nbase, thorpej_scsipi_beforemerge, thorpej_scsipi_base, thorpej_scsipi, thorpej-signal-base, thorpej-signal, thorpej-mips-cache-base, thorpej-mips-cache, thorpej-devvp-base3, thorpej-devvp-base2, thorpej-devvp-base, thorpej-devvp, pre-chs-ubcperf, post-chs-ubcperf, newlock-base, newlock, netbsd-1-6-base, netbsd-1-6-RELEASE, netbsd-1-6-RC3, netbsd-1-6-RC2, netbsd-1-6-RC1, netbsd-1-6-PATCH002-RELEASE, netbsd-1-6-PATCH002-RC4, netbsd-1-6-PATCH002-RC3, netbsd-1-6-PATCH002-RC2, netbsd-1-6-PATCH002-RC1, netbsd-1-6-PATCH002, netbsd-1-6-PATCH001-RELEASE, netbsd-1-6-PATCH001-RC3, netbsd-1-6-PATCH001-RC2, netbsd-1-6-PATCH001-RC1, netbsd-1-6-PATCH001, netbsd-1-6, netbsd-1-5-base, netbsd-1-5-RELEASE, netbsd-1-5-PATCH003, netbsd-1-5-PATCH002, netbsd-1-5-PATCH001, netbsd-1-5-BETA2, netbsd-1-5-BETA, netbsd-1-5-ALPHA2, netbsd-1-5, netbsd-1-4-base, netbsd-1-4-RELEASE, netbsd-1-4-PATCH003, netbsd-1-4-PATCH002, netbsd-1-4-PATCH001, netbsd-1-4, netbsd-1-3-base, netbsd-1-3-RELEASE, netbsd-1-3-PATCH003-CANDIDATE2, netbsd-1-3-PATCH003-CANDIDATE1, netbsd-1-3-PATCH003-CANDIDATE0, netbsd-1-3-PATCH003, netbsd-1-3-PATCH002, netbsd-1-3-PATCH001, netbsd-1-3-BETA, netbsd-1-3, nathanw_sa_before_merge, minoura-xpg4dl-base, minoura-xpg4dl, marc-pcmcia-bp, marc-pcmcia-base, marc-pcmcia, kqueue-beforemerge, kqueue-base, kqueue-aftermerge, kqueue, kenh-if-detach-base, kenh-if-detach, kame_14_19990705, kame_14_19990628, kame_141_19991130, kame, ifpoll-base, gmcgarry_ucred_base, gmcgarry_ucred, gmcgarry_ctxsw_base, gmcgarry_ctxsw, gehenna-devsw-base, gehenna-devsw, fvdl_fs64_base, fvdl-softdep-base, fvdl-softdep, eeh-paddr_t-base, eeh-paddr_t, eeh-devprop-base, eeh-devprop, comdex-fall-1999-base, comdex-fall-1999, chs-ubc2-newbase, chs-ubc2-base, chs-ubc2, chs-ubc-base, chs-ubc, bouyer-scsipi
Branch point for: ktrace-lwp
Changes since 1.4: +2 -2 lines

* Fixes from Ian Dall. Make the ieee handler compile with the new gcc warning
  options, make it compile into a user mode library again and update the
  README.

/*	$NetBSD: ieee_invop.c,v 1.5 1997/04/01 16:35:22 matthias Exp $	*/

/* 
 * IEEE floating point support for NS32081 and NS32381 fpus.
 * Copyright (c) 1995 Ian Dall
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
 * IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
 * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 */
/* 
 *	File:	ieee_invop.c
 *	Author:	Ian Dall
 *	Date:	November 1995
 *
 *	Handle operations which generated reserved operand traps.
 *
 * HISTORY
 * 23-Apr-96  Ian Dall (Ian.Dall@dsto.defence.gov.au)
 *	Don't change sign of NaN operands of NEGF and SUBF.
 *
 * 23-Apr-96  Ian Dall (Ian.Dall@dsto.defence.gov.au)
 *	Operations on signaling NaN's always produce a quiet NaN.
 *
 * 08-Apr-96  Ian Dall (Ian.Dall@dsto.defence.gov.au)
 *	Generate correct return value so flags get set properly.
 *
 * 05-Apr-96  Ian Dall (Ian.Dall@dsto.defence.gov.au)
 *	Get subnormal number divided by subnormal number right.
 *	Get infinty multiplied by zero right.
 *
 * 02-Apr-96  Ian Dall (Ian.Dall@dsto.defence.gov.au)
 *	Make 0/0 produce NaN.
 *
 * 14-Dec-95  Ian Dall (Ian.Dall@dsto.defence.gov.au)
 *	First release.
 *
 */
#include "ieee_internal.h"
#include <machine/psl.h>
#if defined(__NetBSD__) && defined(_KERNEL)
#include <machine/limits.h>
#else
#include <limits.h>
#endif

static int nan_2(union t_conv data1, union t_conv *data2)
{
  int nans = (ISNAN(data1)? 1: 0) + (ISNAN(*data2)? 2: 0);
  switch (nans) {
  case 0:
    return 0;
  case 1:
    *data2 = data1;
    break;
  case 2:
    break;
  case 3:
    if((data1.d_bits.mantissa > data2->d_bits.mantissa)
       || (data1.d_bits.mantissa == data1.d_bits.mantissa
	   && data1.d_bits.mantissa2 > data2->d_bits.mantissa2)) {
      *data2 = data1;
    }
    break;
  }
  data2->d_bits.mantissa |= 0x80000; /* Make sure it is a quiet NaN */
  return 1;
}

static int add_iv (struct operand *op1, struct operand *op2)
{
  int inftys;
  int ret = FPC_TT_NONE;
  if(nan_2(op1->data, &op2->data)) {
    return ret;
  }
  inftys = (ISINFTY(op1->data)? 1: 0) + (ISINFTY(op2->data)? 2:0);
  switch (inftys) {
  case 0:
    break;
  case 1:
    op2->data = op1->data;
    return ret;
  case 2:
    return ret;
  case 3:
    if(op1->data.d_bits.sign != op2->data.d_bits.sign) {
      op2->data = qnan;
      return FPC_TT_INVOP;
    }
    return ret;
  }
  /* Must be subnormals */
  return ieee_add(op1->data.d, &op2->data.d);
}

static int div_iv (struct operand *op1, struct operand *op2)
{
  int inftys, sign1, sign2;
  int ret = FPC_TT_NONE;
  if(nan_2(op1->data, &op2->data)) {
    return ret;
  }
  inftys = (ISINFTY(op1->data)? 1: 0) + (ISINFTY(op2->data)? 2:0);
  sign1 = op1->data.d_bits.sign;
  sign2 = op2->data.d_bits.sign;
  switch (inftys) {
  case 0:
    break;
  case 1:			/* n/oo */
    {
      op2->data.d = 0.0;
      op2->data.d_bits.sign = sign1 ^ sign2;
      return ret;
    }
  case 2:			/* oo/n */
    op2->data.d_bits.sign = sign1 ^ sign2;
    return ret;
  case 3:
    op2->data = qnan;
    return FPC_TT_INVOP;
  }
  if(ISZERO(op1->data)) {
    if (ISZERO(op2->data)) {
      /* Must be 0/0 */
      op2->data = qnan;
      return FPC_TT_INVOP;
    }
    else {
      /* Must be subnorm/0 */
      op2->data = infty;
      op2->data.d_bits.sign = sign1 ^ sign2;
      return FPC_TT_DIV0;
    }
  }
  /* Must be subnorm/subnorm */
  return ieee_div(op1->data.d, &op2->data.d);
}

static int mul_iv (struct operand *op1, struct operand *op2)
{
  int inftys, sign1, sign2;
  int ret = FPC_TT_NONE;
  if(nan_2(op1->data, &op2->data)) {
    return ret;
  }
  inftys = (ISINFTY(op1->data)? 1: 0) + (ISINFTY(op2->data)? 2:0);
  sign1 = op1->data.d_bits.sign;
  sign2 = op2->data.d_bits.sign;
  switch (inftys) {
  case 0:
    break;
  case 1:			/* oo * n */
    if (ISZERO(op2->data)) {
      op2->data = qnan;
      return FPC_TT_INVOP;
    }
    else {
      op2->data = op1->data;
      op2->data.d_bits.sign = sign1 ^ sign2;
      return ret;
    }
  case 2:			/* n * oo */
    if (ISZERO(op1->data)) {
      op2->data = qnan;
      return FPC_TT_INVOP;
    }
    /* Fall through */
  case 3:			/* oo * oo */
    op2->data.d_bits.sign = sign1 ^ sign2;
    return ret;
  }
  /* Must be subnormals */
  return ieee_mul(op1->data.d, &op2->data.d);
}

static int dot_iv (struct operand *op1, struct operand *op2, struct operand *op3)
{
  int inftys;
  int ret = FPC_TT_NONE;
  union t_conv t = op2->data;
  if(nan_2(op1->data, &t)) {
    if(nan_2(t, &op3->data)) 
      return ret;
  }
  inftys = ((ISINFTY(op1->data)? 1: 0) + (ISINFTY(op2->data)? 2:0)
	    + (ISINFTY(op3->data)? 4: 0));
  switch (inftys) {
  case 0:
    break;
  case 1: case 2: case 3:	/* oo * n + m or n * oo + m or oo * oo + m */
    op3->data = op2->data;
    return mul_iv(op1, op3);
  case 4:			/* n * m + oo */
    return ret;
  case 5: case 6: case 7:
    {
      struct operand t = *op2;
      mul_iv(op1, &t);
      add_iv(&t, op3);
      return ret;
    }
  }
  /* Must be subnormals */
  return ieee_dot(op1->data.d, op2->data.d, &op3->data.d);
}

static int poly_iv (struct operand *op1, struct operand *op2, struct operand *op3)
{
  int ret;
  struct operand t = *op2;
  ret = dot_iv(op3, op1, &t);
  *op3 = t;
  return ret;
}

static int round_iv (struct operand *op1, struct operand *op2, int xopcode)
{
  int ret = FPC_TT_NONE;
  if(ISNAN(op1->data)) {
    /* XXX */
    op2->data.i = 0;
    return FPC_TT_INVOP;	/* Need a special code */
  }
  else if (ISINFTY(op1->data)) {
    op2->data.i = op1->data.d_bits.sign? INT_MIN: INT_MAX;
  } else {
    /* Must be a denorm */
    op2->data.i = 0;
  }
  return ret;
}

static int scalb_iv (struct operand *op1, struct operand *op2)
{
  int ret = FPC_TT_NONE;
  if(nan_2(op1->data, &op2->data)) {
    return ret;
  }
  return ieee_scalb(op1->data.d, &op2->data.d);
}

static int logb_iv (struct operand *op1, struct operand *op2)
{
  int ret = FPC_TT_NONE;
  if (ISNAN(op1->data))
    op2->data = op1->data;
  else if(ISINFTY(op1->data))
    op2->data = infty;
  else {
    /* Is a denormal */
    union t_conv t = op1->data;
    int norm = ieee_normalize(&t);
    op2->data.d = t.d_bits.exp + norm;
  }
  return ret;
}

static void cmp_iv(struct operand *op1, struct operand *op2, state *state)
{
  state->PSR &= ~(PSR_N | PSR_Z | PSR_L);
  
  if (ISNAN(op1->data) || ISNAN(op2->data)) {
    return;
  }
  ieee_cmp(op1->data.d, op2->data.d, state);
  return;
}

int ieee_invop(struct operand *op1, struct operand *op2,
	       struct operand *f0_op, int xopcode, state *state)
{
  int user_trap = FPC_TT_NONE;

  /* Don't fiddle with fsr. The FPC_TT_INVOP bit should only be set
   * if we attempt to *generate* a NaN. This is achieved by returning
   * FPC_TT_INVOP when we generate a NaN.
   */
  /*
   * Figure out right thing to do.
   */
  switch(xopcode) {
  case NEGF:
    if(! ISNAN(op1->data))
      op1->data.d_bits.sign ^= 1;
    /* Fall through */
  case MOVF:
  case MOVLF:
  case MOVFL:
    op2->data = op1->data;
    break;
  case CMPF:
    cmp_iv(op1, op2, state);
    break;
  case SUBF:
    if(! ISNAN(op1->data))
      op1->data.d_bits.sign ^= 1;
    /* Fall through */
  case ADDF:
    user_trap = add_iv(op1, op2);
    break;
  case MULF:
    user_trap = mul_iv(op1, op2);
    break;
  case DIVF:
    user_trap = div_iv(op1, op2);
    break;
  case ROUNDFI:
  case TRUNCFI:
  case FLOORFI:
    user_trap = round_iv(op1, op2, xopcode);
    break;
  case SCALBF:
    user_trap = scalb_iv(op1, op2);
    break;
  case LOGBF:
    user_trap = logb_iv(op1, op2);
    break;
  case DOTF:
    user_trap = dot_iv(op1, op2, f0_op);
    break;
  case POLYF:
    user_trap = poly_iv(op1, op2, f0_op);
    break;
  }
  return user_trap;
}