o IEEE 754 floating-point completion code.

o Implement the architected FP_C "Floating Point Control Quadword"
This commit is contained in:
ross 2001-04-26 03:10:44 +00:00
parent 8032753ad3
commit 2df695b1e4
23 changed files with 8398 additions and 164 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_instruction.h,v 1.6 2000/03/20 02:54:45 thorpej Exp $ */
/* $NetBSD: db_instruction.h,v 1.7 2001/04/26 03:10:44 ross Exp $ */
/*
* Copyright (c) 1999 Christopher G. Demetriou. All rights reserved.
@ -184,6 +184,16 @@ typedef union {
opcode : 6;
} float_format;
struct {
unsigned fc : 5,
opclass : 4,
src : 2,
rnd : 2,
trp : 3,
fb : 5,
fa : 5,
opcode : 6;
} float_detail;
/*
* PAL instructions just define the major opcode
@ -221,7 +231,7 @@ typedef union {
#define op_logical 0x11 /* see LOGICAL sub-table */
#define op_bit 0x12 /* see BIT sub-table */
#define op_mul 0x13 /* see MUL sub-table */
/* reserved */
#define op_fix_float 0x14 /* if ALPHA_AMASK_FIX */
#define op_vax_float 0x15 /* see FLOAT sub-table */
#define op_ieee_float 0x16 /* see FLOAT sub-table */
#define op_any_float 0x17 /* see FLOAT sub-table */
@ -411,6 +421,12 @@ typedef union {
* Load and store operations use opcodes op_ldf..op_stt
*/
/* src encoding from function, 9..10 */
#define op_src_sf 0
#define op_src_xd 1
#define op_src_tg 2
#define op_src_qq 3
/* any FLOAT, "function" opcodes (bits 5..11) */
#define op_cvtlq 0x010
@ -427,7 +443,7 @@ typedef union {
#define op_fcmovgt 0x02f
#define op_cvtql 0x030
#define op_cvtql_v 0x130
#define op_cvtql_sv 0x330
#define op_cvtql_sv 0x530
/* ieee FLOAT, "function" opcodes (bits 5..11) */
@ -520,6 +536,7 @@ typedef union {
#define op_mult_ud 0x1e2
#define op_divt_ud 0x1e3
#define op_cvtts_ud 0x1ec
#define op_cvtst 0x2ac
#define op_adds_suc 0x500
#define op_subs_suc 0x501
#define op_muls_suc 0x502
@ -562,6 +579,7 @@ typedef union {
#define op_mult_sud 0x5e2
#define op_divt_sud 0x5e3
#define op_cvtts_sud 0x5ec
#define op_cvtst_u 0x6ac
#define op_adds_suic 0x700
#define op_subs_suic 0x701
#define op_muls_suic 0x702

View File

@ -1 +1,714 @@
/* $NetBSD: fp_complete.c,v 1.1 2001/04/22 20:47:22 ross Exp $ */
/* $NetBSD: fp_complete.c,v 1.2 2001/04/26 03:10:44 ross Exp $ */
/*-
* Copyright (c) 2001 Ross Harvey
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: fp_complete.c,v 1.2 2001/04/26 03:10:44 ross Exp $");
#include "opt_compat_osf1.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#ifdef COMPAT_OSF1
#include <compat/osf1/osf1_exec.h>
#endif
#include <machine/cpu.h>
#include <machine/fpu.h>
#include <machine/reg.h>
#include <machine/alpha.h>
#include <alpha/alpha/db_instruction.h>
#include <lib/libkern/softfloat.h>
#define TSWINSIZE 4 /* size of trap shadow window in u_int32_t units */
/* Set Name Opcodes AARM C.* Symbols */
#define CPUREG_CLASS (0xfUL << 0x10) /* INT[ALSM] */
#define FPUREG_CLASS (0xfUL << 0x14) /* ITFP, FLT[ILV] */
#define CHECKFUNCTIONCODE (1UL << 0x18) /* MISC */
#define TRAPSHADOWBOUNDARY (1UL << 0x00 | /* PAL */\
1UL << 0x19 | /* \PAL\ */\
1UL << 0x1a | /* JSR */\
1UL << 0x1b | /* \PAL\ */\
1UL << 0x1d | /* \PAL\ */\
1UL << 0x1e | /* \PAL\ */\
1UL << 0x1f | /* \PAL\ */\
0xffffUL << 0x30 | /* branch ops */\
CHECKFUNCTIONCODE)
#define MAKE_FLOATXX(width, expwidth, sign, exp, msb, rest_of_frac) \
(u_int ## width ## _t)(sign) << ((width) - 1) |\
(u_int ## width ## _t)(exp) << ((width) - 1 - (expwidth)) |\
(u_int ## width ## _t)(msb) << ((width) - 1 - (expwidth) - 1) |\
(u_int ## width ## _t)(rest_of_frac)
#define FLOAT32QNAN MAKE_FLOATXX(32, 8, 0, 0xff, 1, 0)
#define FLOAT64QNAN MAKE_FLOATXX(64, 11, 0, 0x7ff, 1, 0)
#define IS_SUBNORMAL(v) ((v)->exp == 0 && (v)->frac != 0)
#define PREFILTER_SUBNORMAL(p,v) if ((p)->p_md.md_flags & IEEE_MAP_DMZ \
&& IS_SUBNORMAL(v)) \
(v)->frac = 0; else
#define POSTFILTER_SUBNORMAL(p,v) if ((p)->p_md.md_flags & IEEE_MAP_UMZ \
&& IS_SUBNORMAL(v)) \
(v)->frac = 0; else
/* Alpha returns 2.0 for true, all zeroes for false. */
#define CMP_RESULT(flag) ((flag) ? 4UL << 60 : 0L)
/* Move bits from sw fp_c to hw fpcr. */
#define CRBLIT(sw, hw, m, offs) (((sw) & ~(m)) | ((hw) >> (offs) & (m)))
/*
* Temporary trap shadow instrumentation. The [un]resolved counters
* could be kept permanently, as they provide information on whether
* user code has met AARM trap shadow generation requirements.
*/
struct alpha_shadow {
u_int64_t resolved; /* cases trigger pc found */
u_int64_t unresolved; /* cases it wasn't, code problems? */
u_int64_t scans; /* trap shadow scans */
u_int64_t len; /* number of instructions examined */
u_int64_t uop; /* bit mask of unexpected opcodes */
u_int64_t sqrts; /* ev6+ square root single count */
u_int64_t sqrtt; /* ev6+ square root double count */
u_int32_t ufunc; /* bit mask of unexpected functions */
u_int32_t max; /* max trap shadow scan */
u_int32_t nilswop; /* unexpected op codes */
u_int32_t nilswfunc; /* unexpected function codes */
u_int32_t nilanyop; /* this "cannot happen" */
u_int32_t vax; /* sigs from vax fp opcodes */
} alpha_shadow, alpha_shadow_zero;
static float64 float64_unk(float64, float64);
static float64 compare_un(float64, float64);
static float64 compare_eq(float64, float64);
static float64 compare_lt(float64, float64);
static float64 compare_le(float64, float64);
static void cvt_qs_ts_st_gf_qf(u_int32_t, struct proc *);
static void cvt_gd(u_int32_t, struct proc *);
static void cvt_qt_dg_qg(u_int32_t, struct proc *);
static void cvt_tq_gq(u_int32_t, struct proc *);
static float32 (*swfp_s[])(float32, float32) = {
float32_add, float32_sub, float32_mul, float32_div,
};
static float64 (*swfp_t[])(float64, float64) = {
float64_add, float64_sub, float64_mul, float64_div,
compare_un, compare_eq, compare_lt, compare_le,
float64_unk, float64_unk, float64_unk, float64_unk
};
static void (*swfp_cvt[])(u_int32_t, struct proc *) = {
cvt_qs_ts_st_gf_qf, cvt_gd, cvt_qt_dg_qg, cvt_tq_gq
};
static void
this_cannot_happen(int what_cannot_happen, int64_t bits)
{
static int total;
alpha_instruction inst;
static u_int64_t reported;
inst.bits = bits;
++alpha_shadow.nilswfunc;
if (bits != -1)
alpha_shadow.uop |= 1UL << inst.generic_format.opcode;
if (1UL << what_cannot_happen & reported)
return;
reported |= 1UL << what_cannot_happen;
if (total >= 1000)
return; /* right now, this return "cannot happen" */
++total;
if (bits)
printf("FP instruction %x\n", (unsigned int)bits);
printf("FP event %d/%lx/%lx\n", what_cannot_happen, reported,
alpha_shadow.uop);
printf("Please report this to port-alpha-maintainer@netbsd.org\n");
}
static __inline void
sts(unsigned int rn, s_float *v, struct proc *p)
{
alpha_sts(rn, v);
PREFILTER_SUBNORMAL(p, v);
}
static __inline void
stt(unsigned int rn, t_float *v, struct proc *p)
{
alpha_stt(rn, v);
PREFILTER_SUBNORMAL(p, v);
}
static __inline void
lds(unsigned int rn, s_float *v, struct proc *p)
{
POSTFILTER_SUBNORMAL(p, v);
alpha_lds(rn, v);
}
static __inline void
ldt(unsigned int rn, t_float *v, struct proc *p)
{
POSTFILTER_SUBNORMAL(p, v);
alpha_ldt(rn, v);
}
static float64
compare_lt(float64 a, float64 b)
{
return CMP_RESULT(float64_lt(a, b));
}
static float64
compare_le(float64 a, float64 b)
{
return CMP_RESULT(float64_le(a, b));
}
static float64
compare_un(float64 a, float64 b)
{
if (float64_is_nan(a) | float64_is_nan(b)) {
if (float64_is_signaling_nan(a) | float64_is_signaling_nan(b))
float_set_invalid();
return CMP_RESULT(1);
}
return CMP_RESULT(0);
}
static float64
compare_eq(float64 a, float64 b)
{
return CMP_RESULT(float64_eq(a, b));
}
/*
* A note regarding the VAX FP ops.
*
* The AARM gives us completely leeway to set or not set status flags on VAX
* ops, but we do any subnorm, NaN and dirty zero fixups anyway, and we set
* flags by IEEE rules. Many ops are common to d/f/g and s/t source types.
* For the purely vax ones, it's hard to imagine ever running them.
* (Generated VAX fp ops with completion flags? Hmm.) We are careful never
* to panic, assert, or print unlimited output based on a path through the
* decoder, so wierd cases don't become security issues.
*/
static void
cvt_qs_ts_st_gf_qf(u_int32_t inst_bits, struct proc *p)
{
t_float tfb, tfc;
s_float sfb, sfc;
alpha_instruction inst;
inst.bits = inst_bits;
/*
* cvtst and cvtts have the same opcode, function, and source. The
* distinction for cvtst is hidden in the illegal modifier combinations.
* We decode even the non-/s modifier, so that the fix-up-always mode
* works on ev6 and later. The rounding bits are unused and fixed for
* cvtst, so we check those too.
*/
switch(inst.float_format.function) {
case op_cvtst:
case op_cvtst_u:
sts(inst.float_detail.fb, &sfb, p);
tfc.i = float32_to_float64(sfb.i);
ldt(inst.float_detail.fc, &tfc, p);
return;
}
if(inst.float_detail.src == 2) {
stt(inst.float_detail.fb, &tfb, p);
sfc.i = float64_to_float32(tfb.i);
lds(inst.float_detail.fc, &sfc, p);
return;
}
/* 0: S/F */
/* 1: /D */
/* 3: Q/Q */
this_cannot_happen(5, inst.generic_format.opcode);
tfc.i = FLOAT64QNAN;
ldt(inst.float_detail.fc, &tfc, p);
return;
}
static void
cvt_gd(u_int32_t inst_bits, struct proc *p)
{
t_float tfb, tfc;
alpha_instruction inst;
inst.bits = inst_bits;
stt(inst.float_detail.fb, &tfb, p);
(void) float64_to_float32(tfb.i);
p->p_md.md_flags &= ~NETBSD_FLAG_TO_FP_C(FP_X_IMP);
tfc.i = float64_add(tfb.i, (float64)0);
ldt(inst.float_detail.fc, &tfc, p);
}
static void
cvt_qt_dg_qg(u_int32_t inst_bits, struct proc *p)
{
t_float tfb, tfc;
alpha_instruction inst;
inst.bits = inst_bits;
switch(inst.float_detail.src) {
case 0: /* S/F */
this_cannot_happen(3, inst.bits);
/* fall thru */
case 1: /* D */
/* VAX dirty 0's and reserved ops => UNPREDICTABLE */
/* We've done what's important by just not trapping */
tfc.i = 0;
break;
case 2: /* T/G */
this_cannot_happen(4, inst.bits);
tfc.i = 0;
break;
case 3: /* Q/Q */
stt(inst.float_detail.fb, &tfb, p);
tfc.i = int64_to_float64(tfb.i);
break;
}
alpha_ldt(inst.float_detail.fc, &tfc);
}
/*
* XXX: AARM and 754 seem to disagree here, also, beware of softfloat's
* unfortunate habit of always returning the nontrapping result.
* XXX: there are several apparent AARM/AAH disagreements, as well as
* the issue of trap handler pc and trapping results.
*/
static void
cvt_tq_gq(u_int32_t inst_bits, struct proc *p)
{
t_float tfb, tfc;
alpha_instruction inst;
inst.bits = inst_bits;
stt(inst.float_detail.fb, &tfb, p);
tfc.i = float64_to_int64(tfb.i);
alpha_ldt(inst.float_detail.fc, &tfc); /* yes, ldt */
}
static u_int64_t
fp_c_to_fpcr_1(u_int64_t fpcr, u_int64_t fp_c)
{
u_int64_t disables;
/*
* It's hard to arrange for conforming bit fields, because the FP_C
* and the FPCR are both architected, with specified (and relatively
* scrambled) bit numbers. Defining an internal unscrambled FP_C
* wouldn't help much, because every user exception requires the
* architected bit order in the sigcontext.
*
* Programs that fiddle with the fpcr exception bits (instead of fp_c)
* will lose, because those bits can be and usually are subsetted;
* the official home is in the fp_c. Furthermore, the kernel puts
* phony enables (it lies :-) in the fpcr in order to get control when
* it is necessary to initially set a sticky bit.
*/
fpcr &= FPCR_DYN(3);
/*
* enable traps = case where flag bit is clear OR program wants a trap
* enables = ~flags | mask
* disables = ~(~flags | mask)
* disables = flags & ~mask. Thank you, Augustus De Morgan (1806-1871)
*/
disables = FP_C_TO_NETBSD_FLAG(fp_c) & ~FP_C_TO_NETBSD_MASK(fp_c);
fpcr |= (disables & (FP_X_IMP | FP_X_UFL)) << (61 - 3);
fpcr |= (disables & (FP_X_OFL | FP_X_DZ | FP_X_INV)) << (49 - 0);
# if !(FP_X_INV == 1 && FP_X_DZ == 2 && FP_X_OFL == 4 && \
FP_X_UFL == 8 && FP_X_IMP == 16 && FP_X_IOV == 32 && \
FP_X_UFL << (61 - 3) == FPCR_UNFD && \
FP_X_IMP << (61 - 3) == FPCR_INED && \
FP_X_OFL << (49 - 0) == FPCR_OVFD)
# error "Assertion failed"
/*
* We don't care about the other built-in bit numbers because they
* have been architecturally specified.
*/
# endif
fpcr |= fp_c & FP_C_MIRRORED << (FPCR_MIR_START - FP_C_MIR_START);
fpcr |= (fp_c & IEEE_MAP_DMZ) << 36;
if (fp_c & FP_C_MIRRORED)
fpcr |= FPCR_SUM;
if (fp_c & IEEE_MAP_UMZ)
fpcr |= FPCR_UNDZ | FPCR_UNFD;
fpcr |= (~fp_c & IEEE_TRAP_ENABLE_DNO) << 41;
return fpcr;
}
static void
fp_c_to_fpcr(struct proc *p)
{
alpha_write_fpcr(fp_c_to_fpcr_1(alpha_read_fpcr(), p->p_md.md_flags));
}
void
alpha_write_fp_c(struct proc *p, u_int64_t fp_c)
{
u_int64_t md_flags;
fp_c &= MDP_FP_C;
md_flags = p->p_md.md_flags;
if ((md_flags & MDP_FP_C) == fp_c)
return;
p->p_md.md_flags = (md_flags & ~MDP_FP_C) | fp_c;
alpha_enable_fp(p, 1);
fp_c_to_fpcr(p);
alpha_pal_wrfen(0);
}
u_int64_t
alpha_read_fp_c(struct proc *p)
{
/*
* A possibly-desireable EV6-specific optimization would deviate from
* the Alpha Architecture spec and keep some FP_C bits in the FPCR,
* but in a transparent way. Some of the code for that would need to
* go right here.
*/
return p->p_md.md_flags & MDP_FP_C;
}
static float64
float64_unk(float64 a, float64 b)
{
return 0;
}
/*
* The real function field encodings for IEEE and VAX FP instructions.
*
* Since there is only one operand type field, the cvtXX instructions
* require a variety of special cases, and these have to be analyzed as
* they don't always fit into the field descriptions in AARM section I.
*
* Lots of staring at bits in the appendix shows what's really going on.
*
* | |
* 15 14 13|12 11 10 09|08 07 06 05
* --------======------============
* TRAP : RND : SRC : FUNCTION :
* 0 0 0:. . .:. . . . . . . . . . . . Imprecise
* 0 0 1|. . .:. . . . . . . . . . . ./U underflow enable (if FP output)
* | /V overfloat enable (if int output)
* 0 1 0:. . .:. . . . . . . . . . . ."Unsupported", but used for CVTST
* 0 1 1|. . .:. . . . . . . . . . . . Unsupported
* 1 0 0:. . .:. . . . . . . . . . . ./S software completion (VAX only)
* 1 0 1|. . .:. . . . . . . . . . . ./SU
* | /SV
* 1 1 0:. . .:. . . . . . . . . . . ."Unsupported", but used for CVTST/S
* 1 1 1|. . .:. . . . . . . . . . . ./SUI (if FP output) (IEEE only)
* | /SVI (if int output) (IEEE only)
* S I UV: In other words: bits 15:13 are S:I:UV, except that _usually_
* | not all combinations are valid.
* | |
* 15 14 13|12 11 10 09|08 07 06 05
* --------======------============
* TRAP : RND : SRC : FUNCTION :
* | 0 0 . . . . . . . . . . . ./C Chopped
* : 0 1 . . . . . . . . . . . ./M Minus Infinity
* | 1 0 . . . . . . . . . . . . Normal
* : 1 1 . . . . . . . . . . . ./D Dynamic (in FPCR: Plus Infinity)
* | |
* 15 14 13|12 11 10 09|08 07 06 05
* --------======------============
* TRAP : RND : SRC : FUNCTION :
* 0 0. . . . . . . . . . S/F
* 0 1. . . . . . . . . . -/D
* 1 0. . . . . . . . . . T/G
* 1 1. . . . . . . . . . Q/Q
* | |
* 15 14 13|12 11 10 09|08 07 06 05
* --------======------============
* TRAP : RND : SRC : FUNCTION :
* 0 0 0 0 . . . addX
* 0 0 0 1 . . . subX
* 0 0 1 0 . . . mulX
* 0 0 1 1 . . . divX
* 0 1 0 0 . . . cmpXun
* 0 1 0 1 . . . cmpXeq
* 0 1 1 0 . . . cmpXlt
* 0 1 1 1 . . . cmpXle
* 1 0 0 0 . . . reserved
* 1 0 0 1 . . . reserved
* 1 0 1 0 . . . sqrt[fg] (op_fix, not exactly "vax")
* 1 0 1 1 . . . sqrt[st] (op_fix, not exactly "ieee")
* 1 1 0 0 . . . cvtXs/f (cvt[qt]s, cvtst(!), cvt[gq]f)
* 1 1 0 1 . . . cvtXd (vax only)
* 1 1 1 0 . . . cvtXt/g (cvtqt, cvt[dq]g only)
* 1 1 1 1 . . . cvtXq/q (cvttq, cvtgq)
* | |
* 15 14 13|12 11 10 09|08 07 06 05 the twilight zone
* --------======------============
* TRAP : RND : SRC : FUNCTION :
* /s /i /u x x 1 0 1 1 0 0 . . . cvtts, /siu only 0, 1, 5, 7
* 0 1 0 1 0 1 0 1 1 0 0 . . . cvtst (src == T (!)) 2ac NOT /S
* 1 1 0 1 0 1 0 1 1 0 0 . . . cvtst/s (src == T (!)) 6ac
* x 0 x x x x 0 1 1 1 1 . . . cvttq/_ (src == T)
*/
static void
alpha_fp_interpret(alpha_instruction *pc, struct proc *p, u_int64_t bits)
{
s_float sfa, sfb, sfc;
t_float tfa, tfb, tfc;
alpha_instruction inst;
inst.bits = bits;
switch(inst.generic_format.opcode) {
default:
/* this "cannot happen" */
this_cannot_happen(2, inst.bits);
return;
case op_any_float:
/* HW supplies result, we supply sticky bit and maybe trap */
if (inst.float_format.function == op_cvtql_sv ||
inst.float_format.function == op_cvtql_v) {
alpha_stt(inst.float_detail.fb, &tfb);
sfc.i = (int64_t)tfb.i >= 0L ? INT_MAX : INT_MIN;
alpha_lds(inst.float_detail.fc, &sfc);
float_raise(FP_X_INV);
} else {
++alpha_shadow.nilanyop;
this_cannot_happen(3, inst.bits);
}
break;
case op_vax_float:
++alpha_shadow.vax; /* fall thru */
case op_ieee_float:
case op_fix_float:
switch(inst.float_detail.src) {
case op_src_sf:
sts(inst.float_detail.fb, &sfb, p);
if (inst.float_detail.opclass == 10)
sfc.i = float32_sqrt(sfb.i);
else if (inst.float_detail.opclass & ~3) {
this_cannot_happen(1, inst.bits);
sfc.i = FLOAT32QNAN;
} else {
sts(inst.float_detail.fa, &sfa, p);
sfc.i = (*swfp_s[inst.float_detail.opclass])(
sfa.i, sfb.i);
}
lds(inst.float_detail.fc, &sfc, p);
break;
case op_src_xd:
case op_src_tg:
if (inst.float_detail.opclass >= 12)
(*swfp_cvt[inst.float_detail.opclass - 12])(
inst.bits, p);
else {
stt(inst.float_detail.fb, &tfb, p);
if (inst.float_detail.opclass == 10)
tfc.i = float64_sqrt(tfb.i);
else {
stt(inst.float_detail.fa, &tfa, p);
tfc.i = (*swfp_t[inst.float_detail
.opclass])(tfa.i, tfb.i);
}
ldt(inst.float_detail.fc, &tfc, p);
}
break;
case op_src_qq:
float_raise(FP_X_IMP);
break;
}
}
}
static int
alpha_fp_complete_at(alpha_instruction *trigger_pc, struct proc *p,
u_int64_t *ucode)
{
int needsig;
alpha_instruction inst;
u_int64_t rm, fpcr, orig_fpcr;
u_int64_t orig_flags, new_flags, changed_flags, md_flags;
if (__predict_false(copyin(trigger_pc, &inst, sizeof inst))) {
this_cannot_happen(6, -1);
return SIGSEGV;
}
alpha_enable_fp(p, 1);
/*
* If necessary, lie about the dynamic rounding mode so emulation
* software need go to only one place for it, and so we don't have to
* lock any memory locations or pass a third parameter to every
* SoftFloat entry point.
*/
orig_fpcr = fpcr = alpha_read_fpcr();
rm = inst.float_detail.rnd;
if (__predict_false(rm != 3 /* dynamic */ && rm != (fpcr >> 58 & 3))) {
fpcr = (fpcr & ~FPCR_DYN(3)) | FPCR_DYN(rm);
alpha_write_fpcr(fpcr);
}
orig_flags = FP_C_TO_NETBSD_FLAG(p->p_md.md_flags);
alpha_fp_interpret(trigger_pc, p, inst.bits);
md_flags = p->p_md.md_flags;
new_flags = FP_C_TO_NETBSD_FLAG(md_flags);
changed_flags = orig_flags ^ new_flags;
KASSERT((orig_flags | changed_flags) == new_flags); /* panic on 1->0 */
alpha_write_fpcr(fp_c_to_fpcr_1(orig_fpcr, md_flags));
needsig = changed_flags & FP_C_TO_NETBSD_MASK(md_flags);
alpha_pal_wrfen(0);
if (__predict_false(needsig)) {
*ucode = needsig;
return SIGFPE;
}
return 0;
}
int
alpha_fp_complete(u_long a0, u_long a1, struct proc *p, u_int64_t *ucode)
{
int t;
int sig;
u_int64_t op_class;
alpha_instruction inst;
/* "trigger_pc" is Compaq's term for the earliest faulting op */
alpha_instruction *trigger_pc, *usertrap_pc;
alpha_instruction *pc, *win_begin, tsw[TSWINSIZE];
sig = SIGFPE;
pc = (alpha_instruction *)p->p_md.md_tf->tf_regs[FRAME_PC];
trigger_pc = pc - 1; /* for ALPHA_AMASK_PAT case */
if (cpu_amask & ALPHA_AMASK_PAT) {
if (a0 & 1 || alpha_fp_sync_complete) {
sig = alpha_fp_complete_at(trigger_pc, p, ucode);
goto done;
}
}
*ucode = a0;
if (!(a0 & 1))
return sig;
/*
* At this point we are somwhere in the trap shadow of one or more instruc-
* tions that have trapped with software completion specified. We have a mask
* of the registers written by trapping instructions.
*
* Now step backwards through the trap shadow, clearing bits in the
* destination write mask until the trigger instruction is found, and
* interpret this one instruction in SW. If a SIGFPE is not required, back up
* the PC until just after this instruction and restart. This will execute all
* trap shadow instructions between the trigger pc and the trap pc twice.
*
* If a SIGFPE is generated from the OSF1 emulation, back up one more
* instruction to the trigger pc itself. Native binaries don't because it
* completely defeats the intended purpose of IEEE traps -- for example,
* to count the number of exponent wraps for a later correction -- and it's
* terribly non-portable, you would have to determine for every platform the
* instruction length in bytes in order to continue. Fortunately, trapping
* SIGFPE is rare, or there might be a difficult compatibility issue for
* programs incrementing trap PC's conditionally for alphas. (Now, we could
* detect that...) The NetBSD native behavior matches all other alpha freenix
* kernels.
*/
trigger_pc = 0;
win_begin = pc;
++alpha_shadow.scans;
t = alpha_shadow.len;
for (--pc; a1; --pc) {
++alpha_shadow.len;
if (pc < win_begin) {
win_begin = pc - TSWINSIZE + 1;
if (copyin(win_begin, tsw, sizeof tsw)) {
/* sigh, try to get just one */
win_begin = pc;
if (copyin(win_begin, tsw, 4))
return SIGSEGV;
}
}
assert(win_begin <= pc && !((long)pc & 3));
inst = tsw[pc - win_begin];
op_class = 1UL << inst.generic_format.opcode;
if (op_class & FPUREG_CLASS) {
a1 &= ~(1UL << (inst.operate_generic_format.rc + 32));
trigger_pc = pc;
} else if (op_class & CPUREG_CLASS) {
a1 &= ~(1UL << inst.operate_generic_format.rc);
trigger_pc = pc;
} else if (op_class & TRAPSHADOWBOUNDARY) {
if (op_class & CHECKFUNCTIONCODE) {
if (inst.mem_format.displacement == op_trapb ||
inst.mem_format.displacement == op_excb)
break; /* code breaks AARM rules */
} else
break; /* code breaks AARM rules */
}
/* Some shadow-safe op, probably load, store, or FPTI class */
}
t = alpha_shadow.len - t;
if (t > alpha_shadow.max)
alpha_shadow.max = t;
if (__predict_true(trigger_pc != 0 && a1 == 0)) {
++alpha_shadow.resolved;
sig = alpha_fp_complete_at(trigger_pc, p, ucode);
} else {
++alpha_shadow.unresolved;
return sig;
}
done:
if (sig) {
usertrap_pc = trigger_pc + 1;
#ifdef COMPAT_OSF1
if (p->p_emul == &emul_osf1)
usertrap_pc = trigger_pc;
#endif
p->p_md.md_tf->tf_regs[FRAME_PC] = (unsigned long)usertrap_pc;
}
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore.s,v 1.93 2001/04/21 22:03:21 ross Exp $ */
/* $NetBSD: locore.s,v 1.94 2001/04/26 03:10:44 ross Exp $ */
/*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -72,7 +72,7 @@
#include <machine/asm.h>
__KERNEL_RCSID(0, "$NetBSD: locore.s,v 1.93 2001/04/21 22:03:21 ross Exp $");
__KERNEL_RCSID(0, "$NetBSD: locore.s,v 1.94 2001/04/26 03:10:44 ross Exp $");
#include "assym.h"
@ -1851,4 +1851,57 @@ longjmp_botchmsg:
.text
END(longjmp)
/**************************************************************************/
/*
* void sts(int rn, u_int32_t *rval);
* void stt(int rn, u_int64_t *rval);
* void lds(int rn, u_int32_t *rval);
* void ldt(int rn, u_int64_t *rval);
*/
.macro make_freg_util name, op
LEAF(alpha_\name, 2)
and a0, 0x1f, a0
s8addq a0, pv, pv
addq pv, 1f - alpha_\name, pv
jmp (pv)
1:
rn = 0
.rept 32
\op $f0 + rn, 0(a1)
RET
rn = rn + 1
.endr
END(alpha_\name)
.endm
/*
LEAF(alpha_sts, 2)
LEAF(alpha_stt, 2)
LEAF(alpha_lds, 2)
LEAF(alpha_ldt, 2)
*/
make_freg_util sts, sts
make_freg_util stt, stt
make_freg_util lds, lds
make_freg_util ldt, ldt
LEAF(alpha_read_fpcr, 0); f30save = 0; rettmp = 8; framesz = 16
lda sp, -framesz(sp)
stt $f30, f30save(sp)
mf_fpcr $f30
stt $f30, rettmp(sp)
ldt $f30, f30save(sp)
ldq v0, rettmp(sp)
lda sp, framesz(sp)
RET
END(alpha_read_fpcr)
LEAF(alpha_write_fpcr, 1); f30save = 0; fpcrtmp = 8; framesz = 16
lda sp, -framesz(sp)
stq a0, fpcrtmp(sp)
stt $f30, f30save(sp)
ldt $f30, fpcrtmp(sp)
mt_fpcr $f30
ldt $f30, f30save(sp)
lda sp, framesz(sp)
RET
END(alpha_write_fpcr)

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.240 2001/04/24 04:30:50 thorpej Exp $ */
/* $NetBSD: machdep.c,v 1.241 2001/04/26 03:10:44 ross Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
@ -73,7 +73,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.240 2001/04/24 04:30:50 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.241 2001/04/26 03:10:44 ross Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -98,6 +98,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.240 2001/04/24 04:30:50 thorpej Exp $"
#include <sys/core.h>
#include <sys/kcore.h>
#include <machine/kcore.h>
#include <machine/fpu.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
@ -188,6 +189,7 @@ void *ksym_start, *ksym_end;
int alpha_unaligned_print = 1; /* warn about unaligned accesses */
int alpha_unaligned_fix = 1; /* fix up unaligned accesses */
int alpha_unaligned_sigbus = 0; /* don't SIGBUS on fixed-up accesses */
int alpha_fp_sync_complete = 0; /* fp fixup if sync even without /s */
/*
* XXX This should be dynamically sized, but we have the chicken-egg problem!
@ -1540,7 +1542,7 @@ sendsig(catcher, sig, mask, code)
ksc.sc_ownedfp = p->p_md.md_flags & MDP_FPUSED;
bcopy(&p->p_addr->u_pcb.pcb_fp, (struct fpreg *)ksc.sc_fpregs,
sizeof(struct fpreg));
ksc.sc_fp_control = 0; /* XXX ? */
ksc.sc_fp_control = alpha_read_fp_c(p);
bzero(ksc.sc_reserved, sizeof ksc.sc_reserved); /* XXX */
bzero(ksc.sc_xxx, sizeof ksc.sc_xxx); /* XXX */
@ -1667,7 +1669,8 @@ sys___sigreturn14(p, v, retval)
fpusave_proc(p, 0);
bcopy((struct fpreg *)ksc.sc_fpregs, &p->p_addr->u_pcb.pcb_fp,
sizeof(struct fpreg));
/* XXX ksc.sc_fp_control ? */
p->p_addr->u_pcb.pcb_fp.fpr_cr = ksc.sc_fpcr;
p->p_md.md_flags = ksc.sc_fp_control & MDP_FP_C;
/* Restore signal stack. */
if (ksc.sc_onstack & SS_ONSTACK)
@ -1733,6 +1736,10 @@ cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
return (sysctl_rdstring(oldp, oldlenp, newp,
bootinfo.booted_kernel));
case CPU_FP_SYNC_COMPLETE:
return (sysctl_int(oldp, oldlenp, newp, newlen,
&alpha_fp_sync_complete));
default:
return (EOPNOTSUPP);
}
@ -1768,14 +1775,6 @@ setregs(p, pack, stack)
bzero(tfp->tf_regs, FRAME_SIZE * sizeof tfp->tf_regs[0]);
#endif
bzero(&p->p_addr->u_pcb.pcb_fp, sizeof p->p_addr->u_pcb.pcb_fp);
p->p_addr->u_pcb.pcb_fp.fpr_cr = FPCR_INED
| FPCR_UNFD
| FPCR_UNDZ
| FPCR_DYN(FP_RN)
| FPCR_OVFD
| FPCR_DZED
| FPCR_INVD
| FPCR_DNZ;
alpha_pal_wrusp(stack);
tfp->tf_regs[FRAME_PS] = ALPHA_PSL_USERSET;
tfp->tf_regs[FRAME_PC] = pack->ep_entry & ~3;
@ -1787,6 +1786,10 @@ setregs(p, pack, stack)
tfp->tf_regs[FRAME_T12] = tfp->tf_regs[FRAME_PC]; /* a.k.a. PV */
p->p_md.md_flags &= ~MDP_FPUSED;
if (__predict_true((p->p_md.md_flags & IEEE_INHERIT) == 0)) {
p->p_md.md_flags &= ~MDP_FP_C;
p->p_addr->u_pcb.pcb_fp.fpr_cr = FPCR_DYN(FP_RN);
}
if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
fpusave_proc(p, 0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: sys_machdep.c,v 1.12 2001/01/03 22:15:38 thorpej Exp $ */
/* $NetBSD: sys_machdep.c,v 1.13 2001/04/26 03:10:45 ross Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -65,15 +65,17 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.12 2001/01/03 22:15:38 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.13 2001/04/26 03:10:45 ross Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <machine/fpu.h>
#include <machine/sysarch.h>
#include <dev/pci/pcivar.h>
@ -96,11 +98,33 @@ sys_sysarch(struct proc *p, void *v, register_t *retval)
switch(SCARG(uap, op)) {
case ALPHA_FPGETMASK:
*retval = FP_C_TO_NETBSD_MASK(p->p_md.md_flags);
break;
case ALPHA_FPGETSTICKY:
*retval = FP_C_TO_NETBSD_FLAG(p->p_md.md_flags);
break;
case ALPHA_FPSETMASK:
case ALPHA_FPSETSTICKY:
/* XXX kernel Magick required here */
break;
{
fp_except m;
u_int64_t md_flags;
struct alpha_fp_except_args args;
error = copyin(SCARG(uap, parms), &args, sizeof args);
if (error)
return error;
m = args.mask;
md_flags = p->p_md.md_flags;
if (SCARG(uap, op) == ALPHA_FPSETMASK) {
*retval = FP_C_TO_NETBSD_MASK(md_flags);
md_flags = SET_FP_C_MASK(md_flags, m);
} else {
*retval = FP_C_TO_NETBSD_FLAG(md_flags);
md_flags = SET_FP_C_FLAG(md_flags, m);
}
alpha_write_fp_c(p, md_flags);
break;
}
case ALPHA_BUS_GET_WINDOW_COUNT:
{
struct alpha_bus_get_window_count_args args;

View File

@ -1,4 +1,4 @@
/* $NetBSD: trap.c,v 1.69 2001/04/20 18:00:50 thorpej Exp $ */
/* $NetBSD: trap.c,v 1.70 2001/04/26 03:10:45 ross Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -6,7 +6,7 @@
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center, and by Charles M. Hannum.
* NASA Ames Research Center, by Charles M. Hannum, and by Ross Harvey.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -95,12 +95,11 @@
*/
#include "opt_fix_unaligned_vax_fp.h"
#include "opt_compat_osf1.h"
#include "opt_ddb.h"
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.69 2001/04/20 18:00:50 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.70 2001/04/26 03:10:45 ross Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -118,12 +117,11 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.69 2001/04/20 18:00:50 thorpej Exp $");
#ifdef DDB
#include <machine/db_machdep.h>
#endif
#include <alpha/alpha/db_instruction.h> /* for handle_opdec() */
#include <alpha/alpha/db_instruction.h>
#include <machine/userret.h>
int unaligned_fixup(unsigned long, unsigned long,
unsigned long, struct proc *);
int handle_opdec(struct proc *p, u_int64_t *ucodep);
static int unaligned_fixup(u_long, u_long, u_long, struct proc *);
static int handle_opdec(struct proc *p, u_int64_t *ucodep);
/*
* Initialize the trap vectors for the current processor.
@ -262,21 +260,16 @@ trap(const u_long a0, const u_long a1, const u_long a2, const u_long entry,
goto dopanic;
case ALPHA_KENTRY_ARITH:
/*
* If user-land, just give a SIGFPE. Should do
* software completion and IEEE handling, if the
* user has requested that.
/*
* Resolve trap shadows, interpret FP ops requiring infinities,
* NaNs, or denorms, and maintain FPCR corrections.
*/
if (user) {
#ifdef COMPAT_OSF1
extern struct emul emul_osf1;
/* just punt on OSF/1. XXX THIS IS EVIL */
if (p->p_emul == &emul_osf1)
KERNEL_PROC_LOCK(p);
i = alpha_fp_complete(a0, a1, p, &ucode);
KERNEL_PROC_UNLOCK(p);
if (i == 0)
goto out;
#endif
i = SIGFPE;
ucode = a0; /* exception summary */
break;
}
@ -329,48 +322,9 @@ trap(const u_long a0, const u_long a1, const u_long a2, const u_long entry,
break;
case ALPHA_IF_CODE_FEN:
{
struct cpu_info *ci = curcpu();
#if defined(MULTIPROCESSOR)
int s;
#endif
/*
* on exit from the kernel, if proc == fpcurproc,
* FP is enabled.
*/
if (ci->ci_fpcurproc == p) {
printf("trap: fp disabled for fpcurproc == %p",
p);
goto dopanic;
}
if (ci->ci_fpcurproc != NULL)
fpusave_cpu(ci, 1);
KDASSERT(ci->ci_fpcurproc == NULL);
#if defined(MULTIPROCESSOR)
if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
fpusave_proc(p, 1);
#else
KDASSERT(p->p_addr->u_pcb.pcb_fpcpu == NULL);
#endif
FPCPU_LOCK(&p->p_addr->u_pcb, s);
p->p_addr->u_pcb.pcb_fpcpu = ci;
ci->ci_fpcurproc = p;
FPCPU_UNLOCK(&p->p_addr->u_pcb, s);
alpha_pal_wrfen(1);
restorefpstate(&p->p_addr->u_pcb.pcb_fp);
alpha_enable_fp(p, 0);
alpha_pal_wrfen(0);
p->p_md.md_flags |= MDP_FPUSED;
goto out;
}
default:
printf("trap: unknown IF type 0x%lx\n", a0);
@ -568,6 +522,50 @@ dopanic:
panic("trap");
}
/*
* Set the float-point enable for the current process, and return
* the FPU context to the named process. If check == 0, it is an
* error for the named process to already be fpcurproc.
*/
void
alpha_enable_fp(struct proc *p, int check)
{
#if defined(MULTIPROCESSOR)
int s;
#endif
struct cpu_info *ci = curcpu();
if (check && ci->ci_fpcurproc == p) {
alpha_pal_wrfen(1);
return;
}
if (ci->ci_fpcurproc == p)
panic("trap: fp disabled for fpcurproc == %p", p);
if (ci->ci_fpcurproc != NULL)
fpusave_cpu(ci, 1);
KDASSERT(ci->ci_fpcurproc == NULL);
#if defined(MULTIPROCESSOR)
if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
fpusave_proc(p, 1);
#else
KDASSERT(p->p_addr->u_pcb.pcb_fpcpu == NULL);
#endif
FPCPU_LOCK(&p->p_addr->u_pcb, s);
p->p_addr->u_pcb.pcb_fpcpu = ci;
ci->ci_fpcurproc = p;
FPCPU_UNLOCK(&p->p_addr->u_pcb, s);
p->p_md.md_flags |= MDP_FPUSED;
alpha_pal_wrfen(1);
restorefpstate(&p->p_addr->u_pcb.pcb_fp);
}
/*
* Process an asynchronous software trap.
* This is relatively easy.
@ -775,9 +773,6 @@ Gfloat_reg_cvt(u_long input)
}
#endif /* FIX_UNALIGNED_VAX_FP */
extern int alpha_unaligned_print, alpha_unaligned_fix;
extern int alpha_unaligned_sigbus;
struct unaligned_fixup_data {
const char *type; /* opcode name */
int fixable; /* fixable, 0 if fixup not supported */

View File

@ -1,4 +1,4 @@
/* $NetBSD: vm_machdep.c,v 1.67 2001/04/24 04:30:50 thorpej Exp $ */
/* $NetBSD: vm_machdep.c,v 1.68 2001/04/26 03:10:45 ross Exp $ */
/*
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
@ -29,7 +29,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.67 2001/04/24 04:30:50 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.68 2001/04/26 03:10:45 ross Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -143,7 +143,8 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
struct user *up = p2->p_addr;
p2->p_md.md_tf = p1->p_md.md_tf;
p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED;
p2->p_md.md_flags = p1->p_md.md_flags & (MDP_FPUSED | MDP_FP_C);
/*
* Cache the physical address of the pcb, so we can

View File

@ -1,4 +1,4 @@
# $NetBSD: files.alpha,v 1.135 2001/04/19 17:48:46 thorpej Exp $
# $NetBSD: files.alpha,v 1.136 2001/04/26 03:10:45 ross Exp $
#
# alpha-specific configuration info
@ -495,6 +495,7 @@ file arch/alpha/alpha/support.c
file arch/alpha/alpha/sys_machdep.c
file arch/alpha/alpha/syscall.c
file arch/alpha/alpha/trap.c
file arch/alpha/alpha/fp_complete.c
file arch/alpha/alpha/vm_machdep.c
file arch/alpha/alpha/disksubr.c
file arch/alpha/common/bus_dma.c

View File

@ -1,4 +1,4 @@
/* $NetBSD: alpha.h,v 1.14 2000/12/13 03:16:38 mycroft Exp $ */
/* $NetBSD: alpha.h,v 1.15 2001/04/26 03:10:46 ross Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@ -44,6 +44,21 @@
#ifndef _ALPHA_H_
#define _ALPHA_H_
typedef union alpha_s_float {
u_int32_t i;
u_int32_t frac: 23,
exp: 8,
sign: 1;
} s_float;
typedef union alpha_t_float {
u_int64_t i;
u_int64_t frac: 52,
exp: 11,
sign: 1;
} t_float;
#ifdef _KERNEL
#include <machine/bus.h>
@ -54,7 +69,11 @@ struct reg;
struct rpb;
struct trapframe;
extern u_long cpu_implver; /* from IMPLVER instruction */
extern u_long cpu_amask; /* from AMASK instruction */
extern int bootdev_debug;
extern int alpha_fp_sync_complete;
extern int alpha_unaligned_print, alpha_unaligned_fix, alpha_unaligned_sigbus;
void XentArith(u_int64_t, u_int64_t, u_int64_t); /* MAGIC */
void XentIF(u_int64_t, u_int64_t, u_int64_t); /* MAGIC */
@ -110,5 +129,21 @@ void cpu_resume(unsigned long);
void cpu_debug_dump(void);
#endif
/* IEEE and VAX FP completion */
void alpha_sts(int, s_float *); /* MAGIC */
void alpha_stt(int, t_float *); /* MAGIC */
void alpha_lds(int, s_float *); /* MAGIC */
void alpha_ldt(int, t_float *); /* MAGIC */
uint64_t alpha_read_fpcr(void); /* MAGIC */
void alpha_write_fpcr(u_int64_t); /* MAGIC */
u_int64_t alpha_read_fp_c(struct proc *);
void alpha_write_fp_c(struct proc *, u_int64_t);
void alpha_enable_fp(struct proc *, int);
int alpha_fp_complete(u_long, u_long, struct proc *, u_int64_t *);
#endif /* _KERNEL */
#endif /* _ALPHA_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.h,v 1.54 2001/04/21 16:27:11 thorpej Exp $ */
/* $NetBSD: cpu.h,v 1.55 2001/04/26 03:10:46 ross Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
@ -169,9 +169,6 @@ void cpu_pause_resume_all(int);
#define fpcurproc curcpu()->ci_fpcurproc
#define curpcb curcpu()->ci_curpcb
extern u_long cpu_implver; /* from IMPLVER instruction */
extern u_long cpu_amask; /* from AMASK instruction */
/*
* definitions of cpu-dependent requirements
* referenced in generic code
@ -252,7 +249,8 @@ do { \
#define CPU_UNALIGNED_FIX 4 /* int: fix unaligned accesses */
#define CPU_UNALIGNED_SIGBUS 5 /* int: SIGBUS unaligned accesses */
#define CPU_BOOTED_KERNEL 6 /* string: booted kernel name */
#define CPU_MAXID 7 /* 6 valid machdep IDs */
#define CPU_FP_SYNC_COMPLETE 7 /* int: always fixup sync fp traps */
#define CPU_MAXID 8 /* 7 valid machdep IDs */
#define CTL_MACHDEP_NAMES { \
{ 0, 0 }, \
@ -262,6 +260,7 @@ do { \
{ "unaligned_fix", CTLTYPE_INT }, \
{ "unaligned_sigbus", CTLTYPE_INT }, \
{ "booted_kernel", CTLTYPE_STRING }, \
{ "fp_sync_complete", CTLTYPE_INT }, \
}
#ifdef _KERNEL

View File

@ -0,0 +1,120 @@
/* $NetBSD: fpu.h,v 1.4 2001/04/26 03:10:46 ross Exp $ */
/*-
* Copyright (c) 2001 Ross Harvey
* All rights reserved.
*
* This software was written for NetBSD.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifndef _ALPHA_FPU_H_
#define _ALPHA_FPU_H_
#define _FP_C_DEF(n) (1UL << (n))
/*
* Most of these next definitions were moved from <ieeefp.h>. Apparently the
* names happen to match those exported by Compaq and Linux from their fpu.h
* files.
*/
#define FPCR_SUM _FP_C_DEF(63)
#define FPCR_INED _FP_C_DEF(62)
#define FPCR_UNFD _FP_C_DEF(61)
#define FPCR_UNDZ _FP_C_DEF(60)
#define FPCR_DYN(rm) ((unsigned long)(rm) << 58)
#define FPCR_IOV _FP_C_DEF(57)
#define FPCR_INE _FP_C_DEF(56)
#define FPCR_UNF _FP_C_DEF(55)
#define FPCR_OVF _FP_C_DEF(54)
#define FPCR_DZE _FP_C_DEF(53)
#define FPCR_INV _FP_C_DEF(52)
#define FPCR_OVFD _FP_C_DEF(51)
#define FPCR_DZED _FP_C_DEF(50)
#define FPCR_INVD _FP_C_DEF(49)
#define FPCR_DNZ _FP_C_DEF(48)
#define FPCR_DNOD _FP_C_DEF(47)
#define FPCR_MIRRORED (FPCR_INE | FPCR_UNF | FPCR_OVF | FPCR_DZE | FPCR_INV)
#define FPCR_MIR_START 52
/*
* The AARM specifies the bit positions of the software word used for
* user mode interface to the control and status of the kernel completion
* routines. Although it largely just redefines the FPCR, it shuffles
* the bit order. The names of the bits are defined in the AARM, and
* the definition prefix can easily be determined from public domain
* programs written to either the Compaq or Linux interfaces, which
* appear to be identical.
*/
#define IEEE_STATUS_DNO _FP_C_DEF(22)
#define IEEE_STATUS_INE _FP_C_DEF(21)
#define IEEE_STATUS_UNF _FP_C_DEF(20)
#define IEEE_STATUS_OVF _FP_C_DEF(19)
#define IEEE_STATUS_DZE _FP_C_DEF(18)
#define IEEE_STATUS_INV _FP_C_DEF(17)
#define IEEE_TRAP_ENABLE_DNO _FP_C_DEF(6)
#define IEEE_TRAP_ENABLE_INE _FP_C_DEF(5)
#define IEEE_TRAP_ENABLE_UNF _FP_C_DEF(4)
#define IEEE_TRAP_ENABLE_OVF _FP_C_DEF(3)
#define IEEE_TRAP_ENABLE_DZE _FP_C_DEF(2)
#define IEEE_TRAP_ENABLE_INV _FP_C_DEF(1)
#define IEEE_INHERIT _FP_C_DEF(14)
#define IEEE_MAP_UMZ _FP_C_DEF(13)
#define IEEE_MAP_DMZ _FP_C_DEF(12)
#define FP_C_MIRRORED (IEEE_STATUS_INE | IEEE_STATUS_UNF | IEEE_STATUS_OVF\
| IEEE_STATUS_DZE | IEEE_STATUS_INV)
#define FP_C_MIR_START 17
#ifdef _KERNEL
#define FLD_MASK(len) ((1UL << (len)) - 1)
#define FLD_CLEAR(obj, origin, len) \
((obj) & ~(FLD_MASK(len) << (origin)))
#define FLD_INSERT(obj, origin, len, value) \
(FLD_CLEAR(obj, origin, len) | (value) << origin)
#define FP_C_TO_NETBSD_MASK(fp_c) ((fp_c) >> 1 & 0x3f)
#define FP_C_TO_NETBSD_FLAG(fp_c) ((fp_c) >> 17 & 0x3f)
#define NETBSD_MASK_TO_FP_C(m) (((m) & 0x3f) << 1)
#define NETBSD_FLAG_TO_FP_C(s) (((s) & 0x3f) << 17)
#define CLEAR_FP_C_MASK(fp_c) ((fp_c) & ~(0x3f << 1))
#define CLEAR_FP_C_FLAG(fp_c) ((fp_c) & ~(0x3f << 17))
#define SET_FP_C_MASK(fp_c, m) (CLEAR_FP_C_MASK(fp_c) | NETBSD_MASK_TO_FP_C(m))
#define SET_FP_C_FLAG(fp_c, m) (CLEAR_FP_C_FLAG(fp_c) | NETBSD_FLAG_TO_FP_C(m))
#endif
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: ieeefp.h,v 1.3 1999/04/29 02:55:50 ross Exp $ */
/* $NetBSD: ieeefp.h,v 1.4 2001/04/26 03:10:46 ross Exp $ */
/*
* Written by J.T. Conklin, Apr 28, 1995
@ -9,37 +9,45 @@
#define _ALPHA_IEEEFP_H_
typedef int fp_except;
#ifdef _KERNEL
#include <sys/param.h>
#include <sys/proc.h>
#include <machine/fpu.h>
#include <machine/alpha.h>
/* FP_X_IOV is intentionally omitted from the architecture flags mask */
#define FP_AA_FLAGS (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
#define float_raise(f) \
do curproc->p_md.md_flags |= NETBSD_FLAG_TO_FP_C(f); \
while(0)
#define float_set_inexact() float_raise(FP_X_IMP)
#define float_set_invalid() float_raise(FP_X_INV)
#define fpgetround() (alpha_read_fpcr() >> 58 & 3)
#endif
#define FP_X_INV 0x01 /* invalid operation exception */
#define FP_X_DZ 0x02 /* divide-by-zero exception */
#define FP_X_OFL 0x04 /* overflow exception */
#define FP_X_UFL 0x08 /* underflow exception */
#define FP_X_IMP 0x10 /* imprecise (loss of precision; "inexact") */
#define FP_X_IOV 0x20 /* integer overflow XXX? */
#define FP_X_IOV 0x20 /* integer overflow */
/*
* fp_rnd bits match the fpcr, below, as well as bits 12:11
* in fp operate instructions
*/
typedef enum {
FP_RZ=0, /* round to zero (truncate) */
FP_RM=1, /* round toward negative infinity */
FP_RN=2, /* round to nearest representable number */
FP_RP=3 /* round toward positive infinity */
FP_RZ = 0, /* round to zero (truncate) */
FP_RM = 1, /* round toward negative infinity */
FP_RN = 2, /* round to nearest representable number */
FP_RP = 3, /* round toward positive infinity */
_FP_DYNAMIC=FP_RP
} fp_rnd;
#ifdef _KERNEL
#define FPCR_SUM (1UL << 63)
#define FPCR_INED (1UL << 62)
#define FPCR_UNFD (1UL << 61)
#define FPCR_UNDZ (1UL << 60)
#define FPCR_DYN(rm) ((unsigned long)(rm) << 58)
#define FPCR_IOV (1UL << 57)
#define FPCR_INE (1UL << 56)
#define FPCR_UNF (1UL << 55)
#define FPCR_OVF (1UL << 54)
#define FPCR_DZE (1UL << 53)
#define FPCR_INV (1UL << 52)
#define FPCR_OVFD (1UL << 51)
#define FPCR_DZED (1UL << 50)
#define FPCR_INVD (1UL << 49)
#define FPCR_DNZ (1UL << 48)
#define FPCR_DNOD (1UL << 47)
#endif
#endif /* _ALPHA_IEEEFP_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: proc.h,v 1.9 2001/01/19 18:51:18 thorpej Exp $ */
/* $NetBSD: proc.h,v 1.10 2001/04/26 03:10:46 ross Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
@ -41,5 +41,23 @@ struct mdproc {
void (*md_syscall)(struct proc *, u_int64_t, struct trapframe *);
__volatile int md_astpending; /* AST pending for this process */
};
/*
* md_flags usage
* --------------
* MDP_FPUSED
* A largely unused bit indicating the presence of FPU history.
* Cleared on exec. Set but not used by the fpu context switcher
* itself.
*
* MDP_FP_C
* The architected FP Control word. It should forever begin at bit 1,
* as the bits are AARM specified and this way it doesn't need to be
* shifted.
*
* Until C99 there was never an IEEE 754 API, making most of the
* standard useless. Because of overlapping AARM, OSF/1, NetBSD, and
* C99 API's, the use of the MDP_FP_C bits is defined variously in
* ieeefp.h and fpu.h.
*/
#define MDP_FPUSED 0x0001 /* Process used the FPU */
#define MDP_FP_C 0x7ffffe /* Extended FP_C Quadword bits */

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysarch.h,v 1.7 2001/04/20 23:52:23 ross Exp $ */
/* $NetBSD: sysarch.h,v 1.8 2001/04/26 03:10:46 ross Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -52,6 +52,7 @@
#define ALPHA_BUS_GET_WINDOW_COUNT 3
#define ALPHA_BUS_GET_WINDOW 4
#define ALPHA_PCI_CONF_READWRITE 5
#define ALPHA_FPGETSTICKY 6
struct alpha_fp_except_args {
fp_except mask;

View File

@ -1,4 +1,4 @@
/* $NetBSD: cia.c,v 1.56 2000/06/29 08:58:45 mrg Exp $ */
/* $NetBSD: cia.c,v 1.57 2001/04/26 03:10:46 ross Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@ -72,7 +72,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: cia.c,v 1.56 2000/06/29 08:58:45 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: cia.c,v 1.57 2001/04/26 03:10:46 ross Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -85,6 +85,7 @@ __KERNEL_RCSID(0, "$NetBSD: cia.c,v 1.56 2000/06/29 08:58:45 mrg Exp $");
#include <machine/autoconf.h>
#include <machine/rpb.h>
#include <machine/sysarch.h>
#include <machine/alpha.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
@ -219,8 +220,7 @@ cia_init(ccp, mallocsafe)
* - It hasn't been disbled by the user,
* - it's enabled in CNFG,
* - we're implementation version ev5,
* - BWX is enabled in the CPU's capabilities mask (yes,
* the bit is really cleared if the capability exists...)
* - BWX is enabled in the CPU's capabilities mask
*/
if ((pci_use_bwx || bus_use_bwx) &&
(ccp->cc_cnfg & CNFG_BWEN) != 0 &&

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_machdep.c,v 1.15 2001/01/26 19:45:58 manu Exp $ */
/* $NetBSD: linux_machdep.c,v 1.16 2001/04/26 03:10:47 ross Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -154,14 +154,10 @@ void setup_linux_rt_sigframe(tf, sig, mask)
frametoreg(tf, (struct reg *)sigframe.uc.uc_mcontext.sc_regs);
sigframe.uc.uc_mcontext.sc_regs[R_SP] = alpha_pal_rdusp();
if (p == fpcurproc) {
alpha_pal_wrfen(1);
savefpstate(&p->p_addr->u_pcb.pcb_fp);
alpha_pal_wrfen(0);
sigframe.uc.uc_mcontext.sc_fpcr = p->p_addr->u_pcb.pcb_fp.fpr_cr;
fpcurproc = NULL;
}
/* XXX ownedfp ? etc...? */
alpha_enable_fp(p, 1);
sigframe.uc.uc_mcontext.sc_fpcr = alpha_read_fpcr();
sigframe.uc.uc_mcontext.sc_fp_control = alpha_read_fp_c(p);
alpha_pal_wrfen(0);
sigframe.uc.uc_mcontext.sc_traparg_a0 = tf->tf_regs[FRAME_A0];
sigframe.uc.uc_mcontext.sc_traparg_a1 = tf->tf_regs[FRAME_A1];

View File

@ -1,4 +1,4 @@
/* $NetBSD: osf1_misc.c,v 1.62 2000/12/01 19:20:56 jdolecek Exp $ */
/* $NetBSD: osf1_misc.c,v 1.63 2001/04/26 03:10:47 ross Exp $ */
/*
* Copyright (c) 1999 Christopher G. Demetriou. All rights reserved.
@ -87,6 +87,7 @@
#include <machine/alpha.h>
#include <machine/cpuconf.h>
#include <machine/rpb.h>
#include <machine/fpu.h>
#include <compat/osf1/osf1.h>
#include <compat/osf1/osf1_syscallargs.h>
@ -163,6 +164,7 @@ osf1_sys_getsysinfo(struct proc *p, void *v, register_t *retval)
int unit;
long percpu;
long proctype;
u_int64_t fpflags;
struct osf1_cpu_info cpuinfo;
error = 0;
@ -184,14 +186,11 @@ osf1_sys_getsysinfo(struct proc *p, void *v, register_t *retval)
retval[0] = 1;
break;
case OSF_GET_IEEE_FP_CONTROL:
/*
* XXX This is not correct, but we don't keep track
* XXX of the fp_control. Return the fpcr just for fun.
*/
fpusave_proc(p, 1);
error = copyout(&p->p_addr->u_pcb.pcb_fp.fpr_cr,
SCARG(uap, buffer),
sizeof(p->p_addr->u_pcb.pcb_fp.fpr_cr));
if (((fpflags = alpha_read_fp_c(p)) & IEEE_INHERIT) != 0) {
fpflags |= 1UL << 63;
fpflags &= ~IEEE_INHERIT;
}
error = copyout(&fpflags, SCARG(uap, buffer), sizeof fpflags);
retval[0] = 1;
break;
case OSF_GET_CPU_INFO:
@ -262,30 +261,20 @@ osf1_sys_setsysinfo(p, v, retval)
register_t *retval;
{
struct osf1_sys_setsysinfo_args *uap = v;
u_int64_t temp;
int error;
error = 0;
switch(SCARG(uap, op))
{
case OSF_SET_IEEE_FP_CONTROL: {
u_int64_t temp;
/*
* XXX This is definitely not correct. This should instead
* XXX set the fp_control, but we don't keep track of it.
* XXX The fp_control is then used to reload the fpcr.
*/
#define FPCR_SETTABLE (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
switch(SCARG(uap, op)) {
case OSF_SET_IEEE_FP_CONTROL:
if ((error = copyin(SCARG(uap, buffer), &temp, sizeof(temp))))
break;
#if 0
synchronize_fpstate(p, 1);
p->p_addr->u_pcb.pcb_fp.fp_control = (temp & FPCR_SETTABLE);
/* Translate from fp_control => fpr_cr. */
#endif
if (temp >> 63 != 0)
temp |= IEEE_INHERIT;
alpha_write_fp_c(p, temp);
break;
}
default:
uprintf("osf1_setsysinfo called with op=%ld\n", SCARG(uap, op));
//error = EINVAL;

View File

@ -1,10 +1,11 @@
# $NetBSD: Makefile.inc,v 1.20 2000/11/01 19:37:18 thorpej Exp $
# $NetBSD: Makefile.inc,v 1.21 2001/04/26 03:10:48 ross Exp $
SRCS+= __main.c __assert.c _mcount.S \
imax.c imin.c lmax.c lmin.c max.c min.c ulmax.c ulmin.c \
byte_swap_2.S byte_swap_4.S bswap64.c \
bcmp.c bzero.S ffs.S \
memchr.c memcmp.c memcpy.S memmove.S memset.c \
softfloat.c \
strcat.c strcmp.c strcpy.c strlen.c strcasecmp.c \
strncasecmp.c strncmp.c strncpy.c \
scanc.c skpc.c \

160
sys/lib/libkern/milieu.h Normal file
View File

@ -0,0 +1,160 @@
/* $NetBSD: milieu.h,v 1.1 2001/04/26 03:10:47 ross Exp $ */
/* This is a derivative work. */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Ross Harvey.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
===============================================================================
This C header file is part of TestFloat, Release 2a, a package of programs
for testing the correctness of floating-point arithmetic complying to the
IEC/IEEE Standard for Floating-Point.
Written by John R. Hauser. More information is available through the Web
page `http://HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/TestFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these four paragraphs for those parts of
this code that are retained.
===============================================================================
*/
#ifndef MILIEU_H
#define MILIEU_H
#if !defined(_KERNEL) && !defined(_STANDALONE)
#include <inttypes.h>
#else
#include <sys/inttypes.h>
#endif
#include <sys/endian.h>
enum {
FALSE = 0,
TRUE = 1
};
/*
-------------------------------------------------------------------------------
One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
-------------------------------------------------------------------------------
*/
#if _BYTE_ORDER == _LITTLE_ENDIAN
#define LITTLEENDIAN
#else
#define BIGENDIAN
#endif
#define BITS64
/*
-------------------------------------------------------------------------------
Each of the following `typedef's defines the most convenient type that holds
integers of at least as many bits as specified. For example, `uint8' should
be the most convenient type that can hold unsigned integers of as many as
8 bits. The `flag' type must be able to hold either a 0 or 1. For most
implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
to the same as `int'.
-------------------------------------------------------------------------------
*/
typedef int flag;
typedef unsigned int uint8;
typedef signed int int8;
typedef unsigned int uint16;
typedef int int16;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef BITS64
typedef uint64_t uint64;
typedef int64_t int64;
#endif
/*
-------------------------------------------------------------------------------
Each of the following `typedef's defines a type that holds integers
of _exactly_ the number of bits specified. For instance, for most
implementation of C, `bits16' and `sbits16' should be `typedef'ed to
`unsigned short int' and `signed short int' (or `short int'), respectively.
-------------------------------------------------------------------------------
*/
typedef uint8_t bits8;
typedef int8_t sbits8;
typedef uint16_t bits16;
typedef int16_t sbits16;
typedef uint32_t bits32;
typedef int32_t sbits32;
#ifdef BITS64
typedef uint64_t bits64;
typedef int64_t sbits64;
#endif
#ifdef BITS64
/*
-------------------------------------------------------------------------------
The `LIT64' macro takes as its argument a textual integer literal and
if necessary ``marks'' the literal as having a 64-bit integer type.
For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
appended with the letters `LL' standing for `long long', which is `gcc's
name for the 64-bit integer type. Some compilers may allow `LIT64' to be
defined as the identity macro: `#define LIT64( a ) a'.
-------------------------------------------------------------------------------
*/
#define LIT64( a ) a##LL
#endif
/*
-------------------------------------------------------------------------------
The macro `INLINE' can be used before functions that should be inlined. If
a compiler does not support explicit inlining, this macro should be defined
to be `static'.
-------------------------------------------------------------------------------
*/
#define INLINE static inline
#endif

View File

@ -0,0 +1,745 @@
/* $NetBSD: softfloat-macros.h,v 1.1 2001/04/26 03:10:47 ross Exp $ */
/*
===============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2a.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these four paragraphs for those parts of
this code that are retained.
===============================================================================
*/
/*
-------------------------------------------------------------------------------
Shifts `a' right by the number of bits given in `count'. If any nonzero
bits are shifted off, they are ``jammed'' into the least significant bit of
the result by setting the least significant bit to 1. The value of `count'
can be arbitrarily large; in particular, if `count' is greater than 32, the
result will be either 0 or 1, depending on whether `a' is zero or nonzero.
The result is stored in the location pointed to by `zPtr'.
-------------------------------------------------------------------------------
*/
INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
{
bits32 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 32 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*
-------------------------------------------------------------------------------
Shifts `a' right by the number of bits given in `count'. If any nonzero
bits are shifted off, they are ``jammed'' into the least significant bit of
the result by setting the least significant bit to 1. The value of `count'
can be arbitrarily large; in particular, if `count' is greater than 64, the
result will be either 0 or 1, depending on whether `a' is zero or nonzero.
The result is stored in the location pointed to by `zPtr'.
-------------------------------------------------------------------------------
*/
INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
{
bits64 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 64 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*
-------------------------------------------------------------------------------
Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
_plus_ the number of bits given in `count'. The shifted result is at most
64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
bits shifted off form a second 64-bit result as follows: The _last_ bit
shifted off is the most-significant bit of the extra result, and the other
63 bits of the extra result are all zero if and only if _all_but_the_last_
bits shifted off were all zero. This extra result is stored in the location
pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
(This routine makes more sense if `a0' and `a1' are considered to form a
fixed-point value with binary point between `a0' and `a1'. This fixed-point
value is shifted right by the number of bits given in `count', and the
integer part of the result is returned at the location pointed to by
`z0Ptr'. The fractional part of the result may be slightly corrupted as
described above, and is returned at the location pointed to by `z1Ptr'.)
-------------------------------------------------------------------------------
*/
INLINE void
shift64ExtraRightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1 != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
number of bits given in `count'. Any bits shifted off are lost. The value
of `count' can be arbitrarily large; in particular, if `count' is greater
than 128, the result will be 0. The result is broken into two 64-bit pieces
which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
shift128Right(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
number of bits given in `count'. If any nonzero bits are shifted off, they
are ``jammed'' into the least significant bit of the result by setting the
least significant bit to 1. The value of `count' can be arbitrarily large;
in particular, if `count' is greater than 128, the result will be either
0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
nonzero. The result is broken into two 64-bit pieces which are stored at
the locations pointed to by `z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
shift128RightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else if ( count < 128 ) {
z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
by 64 _plus_ the number of bits given in `count'. The shifted result is
at most 128 nonzero bits; these are broken into two 64-bit pieces which are
stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
off form a third 64-bit result as follows: The _last_ bit shifted off is
the most-significant bit of the extra result, and the other 63 bits of the
extra result are all zero if and only if _all_but_the_last_ bits shifted off
were all zero. This extra result is stored in the location pointed to by
`z2Ptr'. The value of `count' can be arbitrarily large.
(This routine makes more sense if `a0', `a1', and `a2' are considered
to form a fixed-point value with binary point between `a1' and `a2'. This
fixed-point value is shifted right by the number of bits given in `count',
and the integer part of the result is returned at the locations pointed to
by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
corrupted as described above, and is returned at the location pointed to by
`z2Ptr'.)
-------------------------------------------------------------------------------
*/
INLINE void
shift128ExtraRightJamming(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z2 = a2;
z1 = a1;
z0 = a0;
}
else {
if ( count < 64 ) {
z2 = a1<<negCount;
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z2 = a1;
z1 = a0;
}
else {
a2 |= a1;
if ( count < 128 ) {
z2 = a0<<negCount;
z1 = a0>>( count & 63 );
}
else {
z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
z1 = 0;
}
}
z0 = 0;
}
z2 |= ( a2 != 0 );
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
number of bits given in `count'. Any bits shifted off are lost. The value
of `count' must be less than 64. The result is broken into two 64-bit
pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
shortShift128Left(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1<<count;
*z0Ptr =
( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
}
/*
-------------------------------------------------------------------------------
Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
by the number of bits given in `count'. Any bits shifted off are lost.
The value of `count' must be less than 64. The result is broken into three
64-bit pieces which are stored at the locations pointed to by `z0Ptr',
`z1Ptr', and `z2Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
shortShift192Left(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount;
z2 = a2<<count;
z1 = a1<<count;
z0 = a0<<count;
if ( 0 < count ) {
negCount = ( ( - count ) & 63 );
z1 |= a2>>negCount;
z0 |= a1>>negCount;
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
any carry out is lost. The result is broken into two 64-bit pieces which
are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
add128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z1;
z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + ( z1 < a1 );
}
/*
-------------------------------------------------------------------------------
Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
modulo 2^192, so any carry out is lost. The result is broken into three
64-bit pieces which are stored at the locations pointed to by `z0Ptr',
`z1Ptr', and `z2Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
add192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 carry0, carry1;
z2 = a2 + b2;
carry1 = ( z2 < a2 );
z1 = a1 + b1;
carry0 = ( z1 < a1 );
z0 = a0 + b0;
z1 += carry1;
z0 += ( z1 < carry1 );
z0 += carry0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
2^128, so any borrow out (carry out) is lost. The result is broken into two
64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
`z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
sub128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - ( a1 < b1 );
}
/*
-------------------------------------------------------------------------------
Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
result is broken into three 64-bit pieces which are stored at the locations
pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
sub192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 borrow0, borrow1;
z2 = a2 - b2;
borrow1 = ( a2 < b2 );
z1 = a1 - b1;
borrow0 = ( a1 < b1 );
z0 = a0 - b0;
z0 -= ( z1 < borrow1 );
z1 -= borrow1;
z0 -= borrow0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
into two 64-bit pieces which are stored at the locations pointed to by
`z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits32 aHigh, aLow, bHigh, bLow;
bits64 z0, zMiddleA, zMiddleB, z1;
aLow = a;
aHigh = a>>32;
bLow = b;
bHigh = b>>32;
z1 = ( (bits64) aLow ) * bLow;
zMiddleA = ( (bits64) aLow ) * bHigh;
zMiddleB = ( (bits64) aHigh ) * bLow;
z0 = ( (bits64) aHigh ) * bHigh;
zMiddleA += zMiddleB;
z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += ( z1 < zMiddleA );
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
`b' to obtain a 192-bit product. The product is broken into three 64-bit
pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
`z2Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
mul128By64To192(
bits64 a0,
bits64 a1,
bits64 b,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2, more1;
mul64To128( a1, b, &z1, &z2 );
mul64To128( a0, b, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
product. The product is broken into four 64-bit pieces which are stored at
the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
mul128To256(
bits64 a0,
bits64 a1,
bits64 b0,
bits64 b1,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr,
bits64 *z3Ptr
)
{
bits64 z0, z1, z2, z3;
bits64 more1, more2;
mul64To128( a1, b1, &z2, &z3 );
mul64To128( a1, b0, &z1, &more2 );
add128( z1, more2, 0, z2, &z1, &z2 );
mul64To128( a0, b0, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
mul64To128( a0, b1, &more1, &more2 );
add128( more1, more2, 0, z2, &more1, &z2 );
add128( z0, z1, 0, more1, &z0, &z1 );
*z3Ptr = z3;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Returns an approximation to the 64-bit integer quotient obtained by dividing
`b' into the 128-bit value formed by concatenating `a0' and `a1'. The
divisor `b' must be at least 2^63. If q is the exact quotient truncated
toward zero, the approximation returned lies between q and q + 2 inclusive.
If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
unsigned integer is returned.
-------------------------------------------------------------------------------
*/
static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
{
bits64 b0, b1;
bits64 rem0, rem1, term0, term1;
bits64 z;
if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
b0 = b>>32;
z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
mul64To128( b, z, &term0, &term1 );
sub128( a0, a1, term0, term1, &rem0, &rem1 );
while ( ( (sbits64) rem0 ) < 0 ) {
z -= LIT64( 0x100000000 );
b1 = b<<32;
add128( rem0, rem1, b0, b1, &rem0, &rem1 );
}
rem0 = ( rem0<<32 ) | ( rem1>>32 );
z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
return z;
}
#ifndef SOFTFLOAT_FOR_GCC /* Not used */
/*
-------------------------------------------------------------------------------
Returns an approximation to the square root of the 32-bit significand given
by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
`aExp' (the least significant bit) is 1, the integer returned approximates
2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
case, the approximation returned lies strictly within +/-2 of the exact
value.
-------------------------------------------------------------------------------
*/
static bits32 estimateSqrt32( int16 aExp, bits32 a )
{
static const bits16 sqrtOddAdjustments[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const bits16 sqrtEvenAdjustments[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
int8 index;
bits32 z;
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
z = ( ( a / z )<<14 ) + ( z<<15 );
a >>= 1;
}
else {
z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
z = a / z + z;
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
}
return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
}
#endif
/*
-------------------------------------------------------------------------------
Returns the number of leading 0 bits before the most-significant 1 bit of
`a'. If `a' is zero, 32 is returned.
-------------------------------------------------------------------------------
*/
static int8 countLeadingZeros32( bits32 a )
{
static const int8 countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int8 shiftCount;
shiftCount = 0;
if ( a < 0x10000 ) {
shiftCount += 16;
a <<= 16;
}
if ( a < 0x1000000 ) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZerosHigh[ a>>24 ];
return shiftCount;
}
/*
-------------------------------------------------------------------------------
Returns the number of leading 0 bits before the most-significant 1 bit of
`a'. If `a' is zero, 64 is returned.
-------------------------------------------------------------------------------
*/
static int8 countLeadingZeros64( bits64 a )
{
int8 shiftCount;
shiftCount = 0;
if ( a < ( (bits64) 1 )<<32 ) {
shiftCount += 32;
}
else {
a >>= 32;
}
shiftCount += countLeadingZeros32( a );
return shiftCount;
}
/*
-------------------------------------------------------------------------------
Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
is equal to the 128-bit value formed by concatenating `b0' and `b1'.
Otherwise, returns 0.
-------------------------------------------------------------------------------
*/
INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 == b0 ) && ( a1 == b1 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
Otherwise, returns 0.
-------------------------------------------------------------------------------
*/
INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
returns 0.
-------------------------------------------------------------------------------
*/
INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
not equal to the 128-bit value formed by concatenating `b0' and `b1'.
Otherwise, returns 0.
-------------------------------------------------------------------------------
*/
INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 != b0 ) || ( a1 != b1 );
}

View File

@ -0,0 +1,487 @@
/* $NetBSD: softfloat-specialize.h,v 1.1 2001/04/26 03:10:47 ross Exp $ */
/* This is a derivative work. */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Ross Harvey.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
===============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2a.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these four paragraphs for those parts of
this code that are retained.
===============================================================================
*/
/*
-------------------------------------------------------------------------------
Underflow tininess-detection mode, statically initialized to default value.
-------------------------------------------------------------------------------
*/
/* [ MP safe, does not change dynamically ] */
int float_detect_tininess = float_tininess_after_rounding;
/*
-------------------------------------------------------------------------------
Internal canonical NaN format.
-------------------------------------------------------------------------------
*/
typedef struct {
flag sign;
bits64 high, low;
} commonNaNT;
/*
-------------------------------------------------------------------------------
The pattern for a default generated single-precision NaN.
-------------------------------------------------------------------------------
*/
#define float32_default_nan 0xFFC00000
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is a NaN;
otherwise returns 0.
-------------------------------------------------------------------------------
*/
static flag float32_is_nan( float32 a )
{
return ( 0xFF000000 < (bits32) ( a<<1 ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is a signaling
NaN; otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag float32_is_signaling_nan( float32 a )
{
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point NaN
`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
exception is raised.
-------------------------------------------------------------------------------
*/
static commonNaNT float32ToCommonNaN( float32 a )
{
commonNaNT z;
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a>>31;
z.low = 0;
z.high = ( (bits64) a )<<41;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the canonical NaN `a' to the single-
precision floating-point format.
-------------------------------------------------------------------------------
*/
static float32 commonNaNToFloat32( commonNaNT a )
{
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
}
/*
-------------------------------------------------------------------------------
Takes two single-precision floating-point values `a' and `b', one of which
is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
signaling NaN, the invalid exception is raised.
-------------------------------------------------------------------------------
*/
static float32 propagateFloat32NaN( float32 a, float32 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float32_is_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
bIsNaN = float32_is_nan( b );
bIsSignalingNaN = float32_is_signaling_nan( b );
a |= 0x00400000;
b |= 0x00400000;
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b;
if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a;
return ( a < b ) ? a : b;
}
else {
return b;
}
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point NaN
`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
exception is raised.
-------------------------------------------------------------------------------
*/
static commonNaNT float64ToCommonNaN( float64 a )
{
commonNaNT z;
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a>>63;
z.low = 0;
z.high = a<<12;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the canonical NaN `a' to the double-
precision floating-point format.
-------------------------------------------------------------------------------
*/
static float64 commonNaNToFloat64( commonNaNT a )
{
return
( ( (bits64) a.sign )<<63 )
| LIT64( 0x7FF8000000000000 )
| ( a.high>>12 );
}
/*
-------------------------------------------------------------------------------
Takes two double-precision floating-point values `a' and `b', one of which
is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
signaling NaN, the invalid exception is raised.
-------------------------------------------------------------------------------
*/
static float64 propagateFloat64NaN( float64 a, float64 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float64_is_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsNaN = float64_is_nan( b );
bIsSignalingNaN = float64_is_signaling_nan( b );
a |= LIT64( 0x0008000000000000 );
b |= LIT64( 0x0008000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b;
if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a;
return ( a < b ) ? a : b;
}
else {
return b;
}
}
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
The pattern for a default generated extended double-precision NaN. The
`high' and `low' values hold the most- and least-significant bits,
respectively.
-------------------------------------------------------------------------------
*/
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is a
NaN; otherwise returns 0.
-------------------------------------------------------------------------------
*/
static flag floatx80_is_nan( floatx80 a )
{
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is a
signaling NaN; otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag floatx80_is_signaling_nan( floatx80 a )
{
bits64 aLow;
aLow = a.low & ~ LIT64( 0x4000000000000000 );
return
( ( a.high & 0x7FFF ) == 0x7FFF )
&& (bits64) ( aLow<<1 )
&& ( a.low == aLow );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
invalid exception is raised.
-------------------------------------------------------------------------------
*/
static commonNaNT floatx80ToCommonNaN( floatx80 a )
{
commonNaNT z;
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a.high>>15;
z.low = 0;
z.high = a.low<<1;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the canonical NaN `a' to the extended
double-precision floating-point format.
-------------------------------------------------------------------------------
*/
static floatx80 commonNaNToFloatx80( commonNaNT a )
{
floatx80 z;
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
return z;
}
/*
-------------------------------------------------------------------------------
Takes two extended double-precision floating-point values `a' and `b', one
of which is a NaN, and returns the appropriate NaN result. If either `a' or
`b' is a signaling NaN, the invalid exception is raised.
-------------------------------------------------------------------------------
*/
static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = floatx80_is_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsNaN = floatx80_is_nan( b );
bIsSignalingNaN = floatx80_is_signaling_nan( b );
a.low |= LIT64( 0xC000000000000000 );
b.low |= LIT64( 0xC000000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( a.low < b.low ) return b;
if ( b.low < a.low ) return a;
return ( a.high < b.high ) ? a : b;
}
else {
return b;
}
}
#endif
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
The pattern for a default generated quadruple-precision NaN. The `high' and
`low' values hold the most- and least-significant bits, respectively.
-------------------------------------------------------------------------------
*/
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
#define float128_default_nan_low LIT64( 0x0000000000000000 )
/*
-------------------------------------------------------------------------------
Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag float128_is_nan( float128 a )
{
return
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the quadruple-precision floating-point value `a' is a
signaling NaN; otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag float128_is_signaling_nan( float128 a )
{
return
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the quadruple-precision floating-point NaN
`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
exception is raised.
-------------------------------------------------------------------------------
*/
static commonNaNT float128ToCommonNaN( float128 a )
{
commonNaNT z;
if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a.high>>63;
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the canonical NaN `a' to the quadruple-
precision floating-point format.
-------------------------------------------------------------------------------
*/
static float128 commonNaNToFloat128( commonNaNT a )
{
float128 z;
shift128Right( a.high, a.low, 16, &z.high, &z.low );
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
return z;
}
/*
-------------------------------------------------------------------------------
Takes two quadruple-precision floating-point values `a' and `b', one of
which is a NaN, and returns the appropriate NaN result. If either `a' or
`b' is a signaling NaN, the invalid exception is raised.
-------------------------------------------------------------------------------
*/
static float128 propagateFloat128NaN( float128 a, float128 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float128_is_nan( a );
aIsSignalingNaN = float128_is_signaling_nan( a );
bIsNaN = float128_is_nan( b );
bIsSignalingNaN = float128_is_signaling_nan( b );
a.high |= LIT64( 0x0000800000000000 );
b.high |= LIT64( 0x0000800000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
return ( a.high < b.high ) ? a : b;
}
else {
return b;
}
}
#endif

5497
sys/lib/libkern/softfloat.c Normal file

File diff suppressed because it is too large Load Diff

370
sys/lib/libkern/softfloat.h Normal file
View File

@ -0,0 +1,370 @@
/* $NetBSD: softfloat.h,v 1.1 2001/04/26 03:10:48 ross Exp $ */
/* This is a derivative work. */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Ross Harvey.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
===============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2a.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these four paragraphs for those parts of
this code that are retained.
===============================================================================
*/
#include <sys/types.h>
#if !defined(_KERNEL) && !defined(_STANDALONE)
#include <inttypes.h>
#include <ieeefp.h>
#else
#include "sys/inttypes.h"
#include "machine/ieeefp.h"
#endif
#include <sys/endian.h>
/*
-------------------------------------------------------------------------------
The macro `FLOATX80' must be defined to enable the extended double-precision
floating-point format `floatx80'. If this macro is not defined, the
`floatx80' type will not be defined, and none of the functions that either
input or output the `floatx80' type will be defined. The same applies to
the `FLOAT128' macro and the quadruple-precision format `float128'.
-------------------------------------------------------------------------------
*/
/* #define FLOATX80 */
/* #define FLOAT128 */
/*
-------------------------------------------------------------------------------
Software IEC/IEEE floating-point types.
-------------------------------------------------------------------------------
*/
typedef u_int32_t float32;
typedef u_int64_t float64;
#ifdef FLOATX80
typedef struct {
#if BYTE_ORDER == BIG_ENDIAN
u_int16_t high;
u_int64_t low;
#else
u_int64_t low;
u_int16_t high;
#endif
} floatx80;
#endif
#ifdef FLOAT128
typedef struct {
u_int64_t high, low;
} float128;
#endif
/*
* Some of the global variables that used to be here have been removed for
* fairly obvious (defopt-MULTIPROCESSOR) reasons. The rest (which don't
* change dynamically) will be removed later. [ross]
*/
#define float_rounding_mode() fpgetround()
/*
-------------------------------------------------------------------------------
Software IEC/IEEE floating-point underflow tininess-detection mode.
-------------------------------------------------------------------------------
*/
extern int float_detect_tininess;
enum {
float_tininess_after_rounding = 1,
float_tininess_before_rounding = 0
};
/*
-------------------------------------------------------------------------------
Software IEC/IEEE floating-point rounding mode.
-------------------------------------------------------------------------------
*/
enum {
float_round_nearest_even = FP_RN,
float_round_to_zero = FP_RZ,
float_round_down = FP_RM,
float_round_up = FP_RP
};
/*
-------------------------------------------------------------------------------
Software IEC/IEEE floating-point exception flags.
-------------------------------------------------------------------------------
*/
enum {
float_flag_inexact = FP_X_IMP,
float_flag_underflow = FP_X_UFL,
float_flag_overflow = FP_X_OFL,
float_flag_divbyzero = FP_X_DZ,
float_flag_invalid = FP_X_INV
};
/*
-------------------------------------------------------------------------------
Software IEC/IEEE integer-to-floating-point conversion routines.
-------------------------------------------------------------------------------
*/
float32 int32_to_float32( int );
float64 int32_to_float64( int );
#ifdef FLOATX80
floatx80 int32_to_floatx80( int );
#endif
#ifdef FLOAT128
float128 int32_to_float128( int );
#endif
#ifndef SOFTFLOAT_FOR_GCC /* __floatdi?f is in libgcc2.c */
float32 int64_to_float32( int64_t );
float64 int64_to_float64( int64_t );
#ifdef FLOATX80
floatx80 int64_to_floatx80( int64_t );
#endif
#ifdef FLOAT128
float128 int64_to_float128( int64_t );
#endif
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE single-precision conversion routines.
-------------------------------------------------------------------------------
*/
int float32_to_int32( float32 );
int float32_to_int32_round_to_zero( float32 );
#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
int64_t float32_to_int64( float32 );
int64_t float32_to_int64_round_to_zero( float32 );
#endif
float64 float32_to_float64( float32 );
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 );
#endif
#ifdef FLOAT128
float128 float32_to_float128( float32 );
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE single-precision operations.
-------------------------------------------------------------------------------
*/
float32 float32_round_to_int( float32 );
float32 float32_add( float32, float32 );
float32 float32_sub( float32, float32 );
float32 float32_mul( float32, float32 );
float32 float32_div( float32, float32 );
float32 float32_rem( float32, float32 );
float32 float32_sqrt( float32 );
int float32_eq( float32, float32 );
int float32_le( float32, float32 );
int float32_lt( float32, float32 );
int float32_eq_signaling( float32, float32 );
int float32_le_quiet( float32, float32 );
int float32_lt_quiet( float32, float32 );
#ifndef SOFTFLOAT_FOR_GCC
int float32_is_signaling_nan( float32 );
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE double-precision conversion routines.
-------------------------------------------------------------------------------
*/
int float64_to_int32( float64 );
int float64_to_int32_round_to_zero( float64 );
#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
int64_t float64_to_int64( float64 );
int64_t float64_to_int64_round_to_zero( float64 );
#endif
float32 float64_to_float32( float64 );
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 );
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 );
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE double-precision operations.
-------------------------------------------------------------------------------
*/
#define float64_default_nan 0xFFF8000000000000LL
static __inline int
float64_is_nan(float64 a)
{
return 0xFFE0000000000000LL < a << 1;
}
static __inline int
float64_is_signaling_nan(float64 a)
{
return (a >> 51 & 0xFFF) == 0xFFE && (a & 0x0007FFFFFFFFFFFFLL);
}
float64 float64_round_to_int( float64 );
float64 float64_add( float64, float64 );
float64 float64_sub( float64, float64 );
float64 float64_mul( float64, float64 );
float64 float64_div( float64, float64 );
float64 float64_rem( float64, float64 );
float64 float64_sqrt( float64 );
int float64_eq( float64, float64 );
int float64_le( float64, float64 );
int float64_lt( float64, float64 );
int float64_eq_signaling( float64, float64 );
int float64_le_quiet( float64, float64 );
int float64_lt_quiet( float64, float64 );
#ifndef SOFTFLOAT_FOR_GCC
int float64_is_signaling_nan( float64 );
#endif
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Software IEC/IEEE extended double-precision conversion routines.
-------------------------------------------------------------------------------
*/
int floatx80_to_int32( floatx80 );
int floatx80_to_int32_round_to_zero( floatx80 );
int64_t floatx80_to_int64( floatx80 );
int64_t floatx80_to_int64_round_to_zero( floatx80 );
float32 floatx80_to_float32( floatx80 );
float64 floatx80_to_float64( floatx80 );
#ifdef FLOAT128
float128 floatx80_to_float128( floatx80 );
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE extended double-precision rounding precision. Valid
values are 32, 64, and 80.
-------------------------------------------------------------------------------
*/
extern int floatx80_rounding_precision;
/*
-------------------------------------------------------------------------------
Software IEC/IEEE extended double-precision operations.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_round_to_int( floatx80 );
floatx80 floatx80_add( floatx80, floatx80 );
floatx80 floatx80_sub( floatx80, floatx80 );
floatx80 floatx80_mul( floatx80, floatx80 );
floatx80 floatx80_div( floatx80, floatx80 );
floatx80 floatx80_rem( floatx80, floatx80 );
floatx80 floatx80_sqrt( floatx80 );
int floatx80_eq( floatx80, floatx80 );
int floatx80_le( floatx80, floatx80 );
int floatx80_lt( floatx80, floatx80 );
int floatx80_eq_signaling( floatx80, floatx80 );
int floatx80_le_quiet( floatx80, floatx80 );
int floatx80_lt_quiet( floatx80, floatx80 );
int floatx80_is_signaling_nan( floatx80 );
#endif
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
Software IEC/IEEE quadruple-precision conversion routines.
-------------------------------------------------------------------------------
*/
int float128_to_int32( float128 );
int float128_to_int32_round_to_zero( float128 );
int64_t float128_to_int64( float128 );
int64_t float128_to_int64_round_to_zero( float128 );
float32 float128_to_float32( float128 );
float64 float128_to_float64( float128 );
#ifdef FLOATX80
floatx80 float128_to_floatx80( float128 );
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE quadruple-precision operations.
-------------------------------------------------------------------------------
*/
float128 float128_round_to_int( float128 );
float128 float128_add( float128, float128 );
float128 float128_sub( float128, float128 );
float128 float128_mul( float128, float128 );
float128 float128_div( float128, float128 );
float128 float128_rem( float128, float128 );
float128 float128_sqrt( float128 );
int float128_eq( float128, float128 );
int float128_le( float128, float128 );
int float128_lt( float128, float128 );
int float128_eq_signaling( float128, float128 );
int float128_le_quiet( float128, float128 );
int float128_lt_quiet( float128, float128 );
int float128_is_signaling_nan( float128 );
#endif