Blame ieee-utils/fp-darwin86.c

Packit 67cb25
/* ieee-utils/fp-darwin86.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 2006 Erik Schnetter
Packit 67cb25
 * 
Packit 67cb25
 * This program is free software; you can redistribute it and/or modify
Packit 67cb25
 * it under the terms of the GNU General Public License as published by
Packit 67cb25
 * the Free Software Foundation; either version 3 of the License, or (at
Packit 67cb25
 * your option) any later version.
Packit 67cb25
 * 
Packit 67cb25
 * This program is distributed in the hope that it will be useful, but
Packit 67cb25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 67cb25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 67cb25
 * General Public License for more details.
Packit 67cb25
 * 
Packit 67cb25
 * You should have received a copy of the GNU General Public License
Packit 67cb25
 * along with this program; if not, write to the Free Software
Packit 67cb25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
#include <config.h>
Packit 67cb25
#include <gsl/gsl_ieee_utils.h>
Packit 67cb25
#include <gsl/gsl_errno.h>
Packit 67cb25
Packit 67cb25
/* Here is the dirty part. Set up your 387 through the control word
Packit 67cb25
 * (cw) register.
Packit 67cb25
 *
Packit 67cb25
 *     15-13    12  11-10  9-8     7-6     5    4    3    2    1    0
Packit 67cb25
 * | reserved | IC | RC  | PC | reserved | PM | UM | OM | ZM | DM | IM
Packit 67cb25
 *
Packit 67cb25
 * IM: Invalid operation mask
Packit 67cb25
 * DM: Denormalized operand mask
Packit 67cb25
 * ZM: Zero-divide mask
Packit 67cb25
 * OM: Overflow mask
Packit 67cb25
 * UM: Underflow mask
Packit 67cb25
 * PM: Precision (inexact result) mask
Packit 67cb25
 *
Packit 67cb25
 * Mask bit is 1 means no interrupt.
Packit 67cb25
 *
Packit 67cb25
 * PC: Precision control
Packit 67cb25
 * 11 - round to extended precision
Packit 67cb25
 * 10 - round to double precision
Packit 67cb25
 * 00 - round to single precision
Packit 67cb25
 *
Packit 67cb25
 * RC: Rounding control
Packit 67cb25
 * 00 - rounding to nearest
Packit 67cb25
 * 01 - rounding down (toward - infinity)
Packit 67cb25
 * 10 - rounding up (toward + infinity)
Packit 67cb25
 * 11 - rounding toward zero
Packit 67cb25
 *
Packit 67cb25
 * IC: Infinity control
Packit 67cb25
 * That is for 8087 and 80287 only.
Packit 67cb25
 *
Packit 67cb25
 * The hardware default is 0x037f which we use.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
/* masking of interrupts */
Packit 67cb25
#define _FPU_MASK_IM  0x01
Packit 67cb25
#define _FPU_MASK_DM  0x02
Packit 67cb25
#define _FPU_MASK_ZM  0x04
Packit 67cb25
#define _FPU_MASK_OM  0x08
Packit 67cb25
#define _FPU_MASK_UM  0x10
Packit 67cb25
#define _FPU_MASK_PM  0x20
Packit 67cb25
Packit 67cb25
/* precision control */
Packit 67cb25
#define _FPU_EXTENDED 0x300	/* libm requires double extended precision.  */
Packit 67cb25
#define _FPU_DOUBLE   0x200
Packit 67cb25
#define _FPU_SINGLE   0x0
Packit 67cb25
Packit 67cb25
/* rounding control */
Packit 67cb25
#define _FPU_RC_NEAREST 0x0    /* RECOMMENDED */
Packit 67cb25
#define _FPU_RC_DOWN    0x400
Packit 67cb25
#define _FPU_RC_UP      0x800
Packit 67cb25
#define _FPU_RC_ZERO    0xC00
Packit 67cb25
Packit 67cb25
#define _FPU_RESERVED 0xF0C0  /* Reserved bits in cw */
Packit 67cb25
Packit 67cb25
Packit 67cb25
/* The fdlibm code requires strict IEEE double precision arithmetic,
Packit 67cb25
   and no interrupts for exceptions, rounding to nearest.  */
Packit 67cb25
Packit 67cb25
#define _FPU_DEFAULT  0x037f
Packit 67cb25
Packit 67cb25
/* IEEE:  same as above.  */
Packit 67cb25
#define _FPU_IEEE     0x037f
Packit 67cb25
Packit 67cb25
/* Type of the control word.  */
Packit 67cb25
typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__)));
Packit 67cb25
Packit 67cb25
/* Macros for accessing the hardware control word.
Packit 67cb25
Packit 67cb25
   Note that the use of these macros is no sufficient anymore with
Packit 67cb25
   recent hardware.  Some floating point operations are executed in
Packit 67cb25
   the SSE/SSE2 engines which have their own control and status register.  */
Packit 67cb25
#define _FPU_GETCW(cw) __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw))
Packit 67cb25
#define _FPU_SETCW(cw) __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw))
Packit 67cb25
Packit 67cb25
/* Default control word set at startup.  */
Packit 67cb25
extern fpu_control_t __fpu_control;
Packit 67cb25
Packit 67cb25
Packit 67cb25
Packit 67cb25
#define _FPU_GETMXCSR(cw_sse) asm volatile ("stmxcsr %0" : "=m" (cw_sse))
Packit 67cb25
#define _FPU_SETMXCSR(cw_sse) asm volatile ("ldmxcsr %0" : : "m" (cw_sse))
Packit 67cb25
Packit 67cb25
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_ieee_set_mode (int precision, int rounding, int exception_mask)
Packit 67cb25
{
Packit 67cb25
  fpu_control_t mode, mode_sse;
Packit 67cb25
Packit 67cb25
  _FPU_GETCW (mode) ;
Packit 67cb25
  mode &= _FPU_RESERVED ;
Packit 67cb25
Packit 67cb25
  switch (precision)
Packit 67cb25
    {
Packit 67cb25
    case GSL_IEEE_SINGLE_PRECISION:
Packit 67cb25
      mode |= _FPU_SINGLE ;
Packit 67cb25
      break ;
Packit 67cb25
    case GSL_IEEE_DOUBLE_PRECISION:
Packit 67cb25
      mode |= _FPU_DOUBLE ;
Packit 67cb25
      break ;
Packit 67cb25
    case GSL_IEEE_EXTENDED_PRECISION:
Packit 67cb25
      mode |= _FPU_EXTENDED ;
Packit 67cb25
      break ;
Packit 67cb25
    default:
Packit 67cb25
      mode |= _FPU_EXTENDED ;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  switch (rounding)
Packit 67cb25
    {
Packit 67cb25
    case GSL_IEEE_ROUND_TO_NEAREST:
Packit 67cb25
      mode |= _FPU_RC_NEAREST ;
Packit 67cb25
      break ;
Packit 67cb25
    case GSL_IEEE_ROUND_DOWN:
Packit 67cb25
      mode |= _FPU_RC_DOWN ;
Packit 67cb25
      break ;
Packit 67cb25
    case GSL_IEEE_ROUND_UP:
Packit 67cb25
      mode |= _FPU_RC_UP ;
Packit 67cb25
      break ;
Packit 67cb25
    case GSL_IEEE_ROUND_TO_ZERO:
Packit 67cb25
      mode |= _FPU_RC_ZERO ;
Packit 67cb25
      break ;
Packit 67cb25
    default:
Packit 67cb25
      mode |= _FPU_RC_NEAREST ;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_INVALID)
Packit 67cb25
    mode |= _FPU_MASK_IM ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_DENORMALIZED)
Packit 67cb25
    mode |= _FPU_MASK_DM ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_DIVISION_BY_ZERO)
Packit 67cb25
    mode |= _FPU_MASK_ZM ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_OVERFLOW)
Packit 67cb25
    mode |= _FPU_MASK_OM ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_UNDERFLOW)
Packit 67cb25
    mode |= _FPU_MASK_UM ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_TRAP_INEXACT)
Packit 67cb25
    {
Packit 67cb25
      mode &= ~ _FPU_MASK_PM ;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      mode |= _FPU_MASK_PM ;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  _FPU_SETCW (mode) ;
Packit 67cb25
Packit 67cb25
  _FPU_GETMXCSR (mode_sse) ;
Packit 67cb25
  mode_sse &= 0xFFFF0000 ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_INVALID)
Packit 67cb25
    mode_sse |= _FPU_MASK_IM << 7 ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_DENORMALIZED)
Packit 67cb25
    mode_sse |= _FPU_MASK_DM << 7 ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_DIVISION_BY_ZERO)
Packit 67cb25
    mode_sse |= _FPU_MASK_ZM << 7 ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_OVERFLOW)
Packit 67cb25
    mode_sse |= _FPU_MASK_OM << 7 ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_MASK_UNDERFLOW)
Packit 67cb25
    mode_sse |= _FPU_MASK_UM << 7 ;
Packit 67cb25
Packit 67cb25
  if (exception_mask & GSL_IEEE_TRAP_INEXACT)
Packit 67cb25
    {
Packit 67cb25
      mode_sse &= ~ _FPU_MASK_PM << 7 ;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      mode_sse |= _FPU_MASK_PM << 7 ;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  _FPU_SETMXCSR (mode_sse) ;
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS ;
Packit 67cb25
}