2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1989, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A/*
2N/A * Portions of this source code were derived from Berkeley
2N/A * 4.3 BSD under license from the Regents of the University of
2N/A * California.
2N/A */
2N/A
2N/A/*
2N/A * Generic XDR routines impelmentation.
2N/A *
2N/A * These are the "floating point" xdr routines used to (de)serialize
2N/A * most common data items. See xdr.h for more info on the interface to
2N/A * xdr.
2N/A */
2N/A
2N/A#include "mt.h"
2N/A#include <sys/types.h>
2N/A#include <stdio.h>
2N/A#include <rpc/types.h>
2N/A#include <rpc/xdr.h>
2N/A
2N/A/*
2N/A * This routine works on Suns, 3b2, 68000s, 386 and Vaxen in a manner
2N/A * which is very efficient as bit twiddling is all that is needed. All
2N/A * other machines can use this code but the code is inefficient as
2N/A * various mathematical operations are used to generate the ieee format.
2N/A * In addition rounding errors may occur due to the calculations involved.
2N/A * To be most efficient, new machines should have their own ifdefs.
2N/A * The encoding routines will fail if the machines try to encode a
2N/A * float/double whose value can not be represented by the ieee format,
2N/A * e.g. the exponent is too big/small.
2N/A * ieee largest float = (2 ^ 128) * 0x1.fffff
2N/A * ieee smallest float = (2 ^ -127) * 0x1.00000
2N/A * ieee largest double = (2 ^ 1024) * 0x1.fffff
2N/A * ieee smallest double = (2 ^ -1023) * 0x1.00000
2N/A * The decoding routines assumes that the receiving machine can handle
2N/A * floats/doubles as large/small as the values stated above. If you
2N/A * use a machine which can not represent these values, you will need
2N/A * to put ifdefs in the decode sections to identify areas of failure.
2N/A */
2N/A
2N/A#if defined(vax)
2N/A
2N/A/*
2N/A * What IEEE single precision floating point looks like this on a
2N/A * vax.
2N/A */
2N/A
2N/Astruct ieee_single {
2N/A unsigned int mantissa: 23;
2N/A unsigned int exp : 8;
2N/A unsigned int sign : 1;
2N/A};
2N/A
2N/A#define IEEE_SNG_BIAS 0x7f
2N/A#define VAX_SNG_BIAS 0x81
2N/A
2N/A
2N/A/* Vax single precision floating point */
2N/Astruct vax_single {
2N/A unsigned int mantissa1 : 7;
2N/A unsigned int exp : 8;
2N/A unsigned int sign : 1;
2N/A unsigned int mantissa2 : 16;
2N/A};
2N/A
2N/A#define VAX_SNG_BIAS 0x81
2N/A
2N/Astatic struct sgl_limits {
2N/A struct vax_single s;
2N/A struct ieee_single ieee;
2N/A} sgl_limits[2] = {
2N/A {{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */
2N/A { 0x0, 0xff, 0x0 }}, /* Max IEEE */
2N/A {{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */
2N/A { 0x0, 0x0, 0x0 }} /* Min IEEE */
2N/A};
2N/A#endif /* vax */
2N/A
2N/Abool_t
2N/Axdr_float(XDR *xdrs, float *fp)
2N/A{
2N/A#if defined(vax)
2N/A struct ieee_single is;
2N/A struct vax_single vs, *vsp;
2N/A struct sgl_limits *lim;
2N/A size_t i;
2N/A#endif
2N/A
2N/A switch (xdrs->x_op) {
2N/A
2N/A case XDR_ENCODE:
2N/A#if defined(mc68000) || defined(sparc) || defined(u3b2) || \
2N/A defined(u3b15) || defined(i386) || defined(__amd64)
2N/A return (XDR_PUTINT32(xdrs, (int *)fp));
2N/A#else
2N/A#if defined(vax)
2N/A vs = *((struct vax_single *)fp);
2N/A if ((vs.exp == 1) || (vs.exp == 2)) {
2N/A /* map these to subnormals */
2N/A is.exp = 0;
2N/A is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
2N/A /* lose some precision */
2N/A is.mantissa >>= 3 - vs.exp;
2N/A is.mantissa += (1 << (20 + vs.exp));
2N/A goto shipit;
2N/A }
2N/A for (i = 0, lim = sgl_limits;
2N/A i < (int)(sizeof (sgl_limits) /
2N/A sizeof (struct sgl_limits));
2N/A i++, lim++) {
2N/A if ((vs.mantissa2 == lim->s.mantissa2) &&
2N/A (vs.exp == lim->s.exp) &&
2N/A (vs.mantissa1 == lim->s.mantissa1)) {
2N/A is = lim->ieee;
2N/A goto shipit;
2N/A }
2N/A }
2N/A is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
2N/A is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
2N/A shipit:
2N/A is.sign = vs.sign;
2N/A return (XDR_PUTINT32(xdrs, (int32_t *)&is));
2N/A#else
2N/A {
2N/A /*
2N/A * Every machine can do this, its just not very efficient.
2N/A * In addtion, some rounding errors may occur do to the
2N/A * calculations involved.
2N/A */
2N/A float f;
2N/A int neg = 0;
2N/A int exp = 0;
2N/A int32_t val;
2N/A
2N/A f = *fp;
2N/A if (f == 0) {
2N/A val = 0;
2N/A return (XDR_PUTINT32(xdrs, &val));
2N/A }
2N/A if (f < 0) {
2N/A f = 0 - f;
2N/A neg = 1;
2N/A }
2N/A while (f < 1) {
2N/A f = f * 2;
2N/A --exp;
2N/A }
2N/A while (f >= 2) {
2N/A f = f/2;
2N/A ++exp;
2N/A }
2N/A if ((exp > 128) || (exp < -127)) {
2N/A /* over or under flowing ieee exponent */
2N/A return (FALSE);
2N/A }
2N/A val = neg;
2N/A val = val << 8; /* for the exponent */
2N/A val += 127 + exp; /* 127 is the bias */
2N/A val = val << 23; /* for the mantissa */
2N/A val += (int32_t)((f - 1) * 8388608); /* 2 ^ 23 */
2N/A return (XDR_PUTINT32(xdrs, &val));
2N/A }
2N/A#endif
2N/A#endif
2N/A
2N/A case XDR_DECODE:
2N/A#if defined(mc68000) || defined(sparc) || defined(u3b2) || \
2N/A defined(u3b15) || defined(i386) || defined(__amd64)
2N/A return (XDR_GETINT32(xdrs, (int *)fp));
2N/A#else
2N/A#if defined(vax)
2N/A vsp = (struct vax_single *)fp;
2N/A if (!XDR_GETINT32(xdrs, (int32_t *)&is))
2N/A return (FALSE);
2N/A
2N/A for (i = 0, lim = sgl_limits;
2N/A i < (int)(sizeof (sgl_limits) /
2N/A sizeof (struct sgl_limits));
2N/A i++, lim++) {
2N/A if ((is.exp == lim->ieee.exp) &&
2N/A (is.mantissa == lim->ieee.mantissa)) {
2N/A *vsp = lim->s;
2N/A goto doneit;
2N/A } else if ((is.exp == 0) && (lim->ieee.exp == 0)) {
2N/A /* Special Case */
2N/A unsigned tmp = is.mantissa >> 20;
2N/A if (tmp >= 4) {
2N/A vsp->exp = 2;
2N/A } else if (tmp >= 2) {
2N/A vsp->exp = 1;
2N/A } else {
2N/A *vsp = min.s;
2N/A break;
2N/A } /* else */
2N/A tmp = is.mantissa - (1 << (20 + vsp->exp));
2N/A tmp <<= 3 - vsp->exp;
2N/A vsp->mantissa2 = tmp;
2N/A vsp->mantissa1 = (tmp >> 16);
2N/A goto doneit;
2N/A }
2N/A vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
2N/A vsp->mantissa2 = is.mantissa;
2N/A vsp->mantissa1 = (is.mantissa >> 16);
2N/A doneit:
2N/A vsp->sign = is.sign;
2N/A return (TRUE);
2N/A#else
2N/A {
2N/A /*
2N/A * Every machine can do this, its just not very
2N/A * efficient. It assumes that the decoding machine's
2N/A * float can represent any value in the range of
2N/A * ieee largest float = (2 ^ 128) * 0x1.fffff
2N/A * to
2N/A * ieee smallest float = (2 ^ -127) * 0x1.00000
2N/A * In addtion, some rounding errors may occur do to the
2N/A * calculations involved.
2N/A */
2N/A float f;
2N/A int neg = 0;
2N/A int exp = 0;
2N/A int32_t val;
2N/A
2N/A if (!XDR_GETINT32(xdrs, (int32_t *)&val))
2N/A return (FALSE);
2N/A neg = val & 0x80000000;
2N/A exp = (val & 0x7f800000) >> 23;
2N/A exp -= 127; /* subtract exponent base */
2N/A f = (val & 0x007fffff) * 0.00000011920928955078125;
2N/A /* 2 ^ -23 */
2N/A f++;
2N/A while (exp != 0) {
2N/A if (exp < 0) {
2N/A f = f/2.0;
2N/A ++exp;
2N/A } else {
2N/A f = f * 2.0;
2N/A --exp;
2N/A }
2N/A }
2N/A if (neg)
2N/A f = 0 - f;
2N/A *fp = f;
2N/A }
2N/A return (TRUE);
2N/A#endif
2N/A#endif
2N/A
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * This routine works on Suns (Sky / 68000's) and Vaxen.
2N/A */
2N/A
2N/A#if defined(vax)
2N/A/* What IEEE double precision floating point looks like on a Vax */
2N/Astruct ieee_double {
2N/A unsigned int mantissa1 : 20;
2N/A unsigned int exp : 11;
2N/A unsigned int sign : 1;
2N/A unsigned int mantissa2 : 32;
2N/A};
2N/A
2N/A/* Vax double precision floating point */
2N/Astruct vax_double {
2N/A unsigned int mantissa1 : 7;
2N/A unsigned int exp : 8;
2N/A unsigned int sign : 1;
2N/A unsigned int mantissa2 : 16;
2N/A unsigned int mantissa3 : 16;
2N/A unsigned int mantissa4 : 16;
2N/A};
2N/A
2N/A#define VAX_DBL_BIAS 0x81
2N/A#define IEEE_DBL_BIAS 0x3ff
2N/A#define MASK(nbits) ((1 << nbits) - 1)
2N/A
2N/Astatic struct dbl_limits {
2N/A struct vax_double d;
2N/A struct ieee_double ieee;
2N/A} dbl_limits[2] = {
2N/A {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */
2N/A { 0x0, 0x7ff, 0x0, 0x0 }}, /* Max IEEE */
2N/A {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */
2N/A { 0x0, 0x0, 0x0, 0x0 }} /* Min IEEE */
2N/A};
2N/A
2N/A#endif /* vax */
2N/A
2N/A
2N/Abool_t
2N/Axdr_double(XDR *xdrs, double *dp)
2N/A{
2N/A int *lp;
2N/A#if defined(vax)
2N/A struct ieee_double id;
2N/A struct vax_double vd;
2N/A struct dbl_limits *lim;
2N/A size_t i;
2N/A#endif
2N/A
2N/A switch (xdrs->x_op) {
2N/A
2N/A case XDR_ENCODE:
2N/A#if defined(mc68000) || defined(u3b2) || defined(u3b15) || \
2N/A defined(_LONG_LONG_HTOL)
2N/A lp = (int *)dp;
2N/A return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
2N/A#else
2N/A#if defined(_LONG_LONG_LTOH)
2N/A lp = (int *)dp;
2N/A lp++;
2N/A return (XDR_PUTINT32(xdrs, lp--) && XDR_PUTINT32(xdrs, lp));
2N/A#else
2N/A#if defined(vax)
2N/A vd = *((struct vax_double *)dp);
2N/A for (i = 0, lim = dbl_limits;
2N/A i < (int)(sizeof (dbl_limits) /
2N/A sizeof (struct dbl_limits));
2N/A i++, lim++) {
2N/A if ((vd.mantissa4 == lim->d.mantissa4) &&
2N/A (vd.mantissa3 == lim->d.mantissa3) &&
2N/A (vd.mantissa2 == lim->d.mantissa2) &&
2N/A (vd.mantissa1 == lim->d.mantissa1) &&
2N/A (vd.exp == lim->d.exp)) {
2N/A id = lim->ieee;
2N/A goto shipit;
2N/A }
2N/A }
2N/A id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
2N/A id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
2N/A id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
2N/A (vd.mantissa3 << 13) |
2N/A ((vd.mantissa4 >> 3) & MASK(13));
2N/A shipit:
2N/A id.sign = vd.sign;
2N/A lp = (int32_t *)&id;
2N/A#else
2N/A {
2N/A /*
2N/A * Every machine can do this, its just not very efficient.
2N/A * In addtion, some rounding errors may occur do to the
2N/A * calculations involved.
2N/A */
2N/A double d;
2N/A int neg = 0;
2N/A int exp = 0;
2N/A int32_t val[2];
2N/A
2N/A d = *dp;
2N/A if (d == 0) {
2N/A val[0] = 0;
2N/A val[1] = 0;
2N/A lp = val;
2N/A return (XDR_PUTINT32(xdrs, lp++) &&
2N/A XDR_PUTINT32(xdrs, lp));
2N/A }
2N/A if (d < 0) {
2N/A d = 0 - d;
2N/A neg = 1;
2N/A }
2N/A while (d < 1) {
2N/A d = d * 2;
2N/A --exp;
2N/A }
2N/A while (d >= 2) {
2N/A d = d/2;
2N/A ++exp;
2N/A }
2N/A if ((exp > 1024) || (exp < -1023)) {
2N/A /* over or under flowing ieee exponent */
2N/A return (FALSE);
2N/A }
2N/A val[0] = neg;
2N/A val[0] = val[0] << 11; /* for the exponent */
2N/A val[0] += 1023 + exp; /* 1023 is the bias */
2N/A val[0] = val[0] << 20; /* for the mantissa */
2N/A val[0] += (int32_t)((d - 1) * 1048576); /* 2 ^ 20 */
2N/A val[1] += (int32_t)((((d - 1) * 1048576) - val[0])
2N/A * 4294967296);
2N/A /* 2 ^ 32 */
2N/A lp = val;
2N/A }
2N/A#endif
2N/A return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
2N/A#endif
2N/A#endif
2N/A
2N/A case XDR_DECODE:
2N/A#if defined(mc68000) || defined(u3b2) || defined(u3b15) || \
2N/A defined(_LONG_LONG_HTOL)
2N/A lp = (int *)dp;
2N/A return (XDR_GETINT32(xdrs, lp++) && XDR_GETINT32(xdrs, lp));
2N/A#else
2N/A#if defined(_LONG_LONG_LTOH)
2N/A lp = (int *)dp;
2N/A lp++;
2N/A return (XDR_GETINT32(xdrs, lp--) && XDR_GETINT32(xdrs, lp));
2N/A#else
2N/A#if defined(vax)
2N/A lp = (int32_t *)&id;
2N/A if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
2N/A return (FALSE);
2N/A for (i = 0, lim = dbl_limits;
2N/A i < sizeof (dbl_limits) /
2N/A sizeof (struct dbl_limits);
2N/A i++, lim++) {
2N/A if ((id.mantissa2 == lim->ieee.mantissa2) &&
2N/A (id.mantissa1 == lim->ieee.mantissa1) &&
2N/A (id.exp == lim->ieee.exp)) {
2N/A vd = lim->d;
2N/A goto doneit;
2N/A }
2N/A }
2N/A vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
2N/A vd.mantissa1 = (id.mantissa1 >> 13);
2N/A vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
2N/A (id.mantissa2 >> 29);
2N/A vd.mantissa3 = (id.mantissa2 >> 13);
2N/A vd.mantissa4 = (id.mantissa2 << 3);
2N/A doneit:
2N/A vd.sign = id.sign;
2N/A *dp = *((double *)&vd);
2N/A return (TRUE);
2N/A#else
2N/A {
2N/A /*
2N/A * Every machine can do this, its just not very
2N/A * efficient. It assumes that the decoding machine's
2N/A * double can represent any value in the range of
2N/A * ieee largest double = (2 ^ 1024) * 0x1.fffffffffffff
2N/A * to
2N/A * ieee smallest double = (2 ^ -1023) * 0x1.0000000000000
2N/A * In addtion, some rounding errors may occur do to the
2N/A * calculations involved.
2N/A */
2N/A double d;
2N/A int neg = 0;
2N/A int exp = 0;
2N/A int32_t val[2];
2N/A
2N/A lp = val;
2N/A if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
2N/A return (FALSE);
2N/A neg = val[0] & 0x80000000;
2N/A exp = (val[0] & 0x7ff00000) >> 20;
2N/A exp -= 1023; /* subtract exponent base */
2N/A d = (val[0] & 0x000fffff) * 0.00000095367431640625;
2N/A /* 2 ^ -20 */
2N/A d += (val[1] * 0.0000000000000002220446049250313);
2N/A /* 2 ^ -52 */
2N/A d++;
2N/A while (exp != 0) {
2N/A if (exp < 0) {
2N/A d = d/2.0;
2N/A ++exp;
2N/A } else {
2N/A d = d * 2.0;
2N/A --exp;
2N/A }
2N/A }
2N/A if (neg)
2N/A d = 0 - d;
2N/A *dp = d;
2N/A }
2N/A#endif
2N/A#endif
2N/A#endif
2N/A
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Abool_t
2N/Axdr_quadruple(XDR *xdrs, long double *fp)
2N/A{
2N/A/*
2N/A * The Sparc uses IEEE FP encoding, so just do a byte copy
2N/A */
2N/A
2N/A#if !defined(sparc)
2N/A return (FALSE);
2N/A#else
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A return (XDR_PUTBYTES(xdrs, (char *)fp, sizeof (long double)));
2N/A case XDR_DECODE:
2N/A return (XDR_GETBYTES(xdrs, (char *)fp, sizeof (long double)));
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A#endif
2N/A}