Thu Jul 22 01:39:18 2021 UTC ()
Various minor cleanups and bug fixes to the FP software completion code:
- Use __CTASSERT() instead of rolling our own compile-time assertion
  using cpp.
- Use __BIT() &c instead of rolling our own.
- Improve some comments.
- Define a default FP_C and FPCR value that is self-consistent, and
  initialize it properly at process creation time.
- Fix signal information when the trap shadow cannot be resolved.
- Use defined constants rather than magic numbers for the exception
  summary bits.
- Add a machdep sysctl to enable FP software-completion debugging.


(thorpej)
diff -r1.24 -r1.25 src/sys/arch/alpha/alpha/fp_complete.c
diff -r1.374 -r1.375 src/sys/arch/alpha/alpha/machdep.c
diff -r1.102 -r1.103 src/sys/arch/alpha/include/cpu.h
diff -r1.7 -r1.8 src/sys/arch/alpha/include/fpu.h

cvs diff -r1.24 -r1.25 src/sys/arch/alpha/alpha/fp_complete.c (expand / switch to context diff)
--- src/sys/arch/alpha/alpha/fp_complete.c 2020/09/01 08:22:36 1.24
+++ src/sys/arch/alpha/alpha/fp_complete.c 2021/07/22 01:39:18 1.25
@@ -1,4 +1,4 @@
-/* $NetBSD: fp_complete.c,v 1.24 2020/09/01 08:22:36 thorpej Exp $ */
+/* $NetBSD: fp_complete.c,v 1.25 2021/07/22 01:39:18 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2001 Ross Harvey
@@ -33,9 +33,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "opt_ddb.h"
+
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: fp_complete.c,v 1.24 2020/09/01 08:22:36 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fp_complete.c,v 1.25 2021/07/22 01:39:18 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -51,6 +53,30 @@
 
 #include <lib/libkern/softfloat.h>
 
+/*
+ * Validate our assumptions about bit positions.
+ */
+__CTASSERT(ALPHA_AESR_INV == (FP_X_INV << 1));
+__CTASSERT(ALPHA_AESR_DZE == (FP_X_DZ  << 1));
+__CTASSERT(ALPHA_AESR_OVF == (FP_X_OFL << 1));
+__CTASSERT(ALPHA_AESR_UNF == (FP_X_UFL << 1));
+__CTASSERT(ALPHA_AESR_INE == (FP_X_IMP << 1));
+__CTASSERT(ALPHA_AESR_IOV == (FP_X_IOV << 1));
+
+__CTASSERT(IEEE_TRAP_ENABLE_INV == (FP_X_INV << 1));
+__CTASSERT(IEEE_TRAP_ENABLE_DZE == (FP_X_DZ  << 1));
+__CTASSERT(IEEE_TRAP_ENABLE_OVF == (FP_X_OFL << 1));
+__CTASSERT(IEEE_TRAP_ENABLE_UNF == (FP_X_UFL << 1));
+__CTASSERT(IEEE_TRAP_ENABLE_INE == (FP_X_IMP << 1));
+
+__CTASSERT((uint64_t)FP_X_IMP << (61 - 3) == FPCR_INED);
+__CTASSERT((uint64_t)FP_X_UFL << (61 - 3) == FPCR_UNFD);
+__CTASSERT((uint64_t)FP_X_OFL << (49 - 0) == FPCR_OVFD);
+__CTASSERT((uint64_t)FP_X_DZ  << (49 - 0) == FPCR_DZED);
+__CTASSERT((uint64_t)FP_X_INV << (49 - 0) == FPCR_INVD);
+
+__CTASSERT(FP_C_ALLBITS == MDLWP_FP_C);
+
 #define	TSWINSIZE 4	/* size of trap shadow window in uint32_t units */
 
 /*	Set Name		Opcodes			AARM C.* Symbols  */
@@ -351,11 +377,12 @@
 	 * it is necessary to initially set a sticky bit.
 	 */
 
-	fpcr &= FPCR_DYN(3);
+	fpcr &= FPCR_DYN_RM;
 
 	/*
-	 * enable traps = case where flag bit is clear OR program wants a trap
-	 * enables = ~flags | mask
+	 * enable traps = case where flag bit is clear AND program wants a trap
+	 *
+	 * enables = ~flags & mask
 	 * disables = ~(~flags | mask)
 	 * disables = flags & ~mask. Thank you, Augustus De Morgan (1806-1871)
 	 */
@@ -364,18 +391,6 @@
 	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)
@@ -407,6 +422,11 @@
 		alpha_pal_wrfen(1);
 		fp_c_to_fpcr(l);
 		alpha_pal_wrfen(0);
+	} else {
+		struct pcb *pcb = l->l_addr;
+
+		pcb->pcb_fp.fpr_cr =
+		    fp_c_to_fpcr_1(pcb->pcb_fp.fpr_cr, l->l_md.md_flags);
 	}
 	kpreempt_enable();
 }
@@ -502,12 +522,47 @@
  */
 
 static void
+print_fp_instruction(alpha_instruction *pc, struct lwp *l, uint32_t bits)
+{
+#if defined(DDB)
+	char buf[32];
+	struct alpha_print_instruction_context ctx = {
+		.insn.bits = bits,
+		.pc = (unsigned long)pc,
+		.buf = buf,
+		.bufsize = sizeof(buf),
+	};
+
+	(void) alpha_print_instruction(&ctx);
+
+	printf("INSN [%s:%d] @0x%lx -> %s\n",
+	    l->l_proc->p_comm, l->l_proc->p_pid, ctx.pc, ctx.buf);
+#else
+	alpha_instruction insn = {
+		.bits = bits,
+	};
+	printf("INSN [%s:%d] @0x%lx -> opc=0x%x func=0x%x fa=%d fb=%d fc=%d\n",
+	    l->l_proc->p_comm, l->l_proc->p_pid, (unsigned long)pc,
+	    insn.float_format.opcode, insn.float_format.function,
+	    insn.float_format.fa, insn.float_format.fb, insn.float_format.fc);
+	printf("INSN [%s:%d] @0x%lx -> trp=0x%x rnd=0x%x src=0x%x fn=0x%x\n",
+	    l->l_proc->p_comm, l->l_proc->p_pid, (unsigned long)pc,
+	    insn.float_detail.trp, insn.float_detail.rnd,
+	    insn.float_detail.src, insn.float_detail.opclass);
+#endif /* DDB */
+}
+
+static void
 alpha_fp_interpret(alpha_instruction *pc, struct lwp *l, uint32_t bits)
 {
 	s_float sfa, sfb, sfc;
 	t_float tfa, tfb, tfc;
 	alpha_instruction inst;
 
+	if (alpha_fp_complete_debug) {
+		print_fp_instruction(pc, l, bits);
+	}
+
 	inst.bits = bits;
 	switch(inst.generic_format.opcode) {
 	default:
@@ -588,15 +643,21 @@
 	}
 	alpha_pal_wrfen(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.
+	 * Alpha FLOAT instructions can override the rounding mode on a
+	 * per-instruction basis.  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.
+	 *
+	 * N.B. the rounding mode field of the the FLOAT format instructions
+	 * matches that of the FPCR *except* for the value 3, which means
+	 * "dynamic" rounding mode (i.e. what is programmed into the FPCR).
 	 */
 	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);
+	if (__predict_false(rm != 3 /* dynamic */ &&
+			    rm != __SHIFTOUT(fpcr, FPCR_DYN_RM))) {
+		fpcr = (fpcr & ~FPCR_DYN_RM) | __SHIFTIN(rm, FPCR_DYN_RM);
 		alpha_write_fpcr(fpcr);
 	}
 	orig_flags = FP_C_TO_NETBSD_FLAG(l->l_md.md_flags);
@@ -630,20 +691,33 @@
 	alpha_instruction *trigger_pc, *usertrap_pc;
 	alpha_instruction *pc, *win_begin, tsw[TSWINSIZE];
 
-	sig = SIGFPE;
+	if (alpha_fp_complete_debug) {
+		printf("%s: [%s:%d] a0[AESR]=0x%lx a1[regmask]=0x%lx "
+		       "FPCR=0x%lx FP_C=0x%lx\n",
+		    __func__, l->l_proc->p_comm, l->l_proc->p_pid,
+		    a0, a1, alpha_read_fpcr(),
+		    l->l_md.md_flags & (MDLWP_FP_C|MDLWP_FPACTIVE));
+	}
+
 	pc = (alpha_instruction *)l->l_md.md_tf->tf_regs[FRAME_PC];
 	trigger_pc = pc - 1;	/* for ALPHA_AMASK_PAT case */
+
+	/*
+	 * Start out with the code mirroring the exception flags
+	 * (FP_X_*).  Shift right 1 bit to discard SWC to achive
+	 * this.
+	 */
+	*ucode = a0 >> 1;
+
 	if (cpu_amask & ALPHA_AMASK_PAT) {
-		/* SWC | INV */
-		if (a0 & 3 || alpha_fp_sync_complete) {
+		if ((a0 & (ALPHA_AESR_SWC | ALPHA_AESR_INV)) != 0 ||
+		    alpha_fp_sync_complete) {
 			sig = alpha_fp_complete_at(trigger_pc, l, ucode);
-			goto done;
+			goto resolved;
 		}
 	}
-	*ucode = a0;
-	/* SWC | INV */
-	if (!(a0 & 3))
-		return sig;
+	if ((a0 & (ALPHA_AESR_SWC | ALPHA_AESR_INV)) == 0)
+		goto unresolved;
 /*
  * At this point we are somewhere in the trap shadow of one or more instruc-
  * tions that have trapped with software completion specified.  We have a mask
@@ -666,8 +740,13 @@
 			if (copyin(win_begin, tsw, sizeof tsw)) {
 				/* sigh, try to get just one */
 				win_begin = pc;
-				if (copyin(win_begin, tsw, 4))
+				if (copyin(win_begin, tsw, 4)) {
+					/*
+					 * We're off the rails here; don't
+					 * bother updating the FP_C.
+					 */
 					return SIGSEGV;
+				}
 			}
 		}
 		assert(win_begin <= pc && !((long)pc  & 3));
@@ -695,17 +774,48 @@
 	if (__predict_true(trigger_pc != 0 && a1 == 0)) {
 		++alpha_shadow.resolved;
 		sig = alpha_fp_complete_at(trigger_pc, l, ucode);
+		goto resolved;
 	} else {
 		++alpha_shadow.unresolved;
-		return sig;
 	}
-done:
+
+ unresolved: /* obligatory statement */;
+	/*
+	 * *ucode contains the exception bits (FP_X_*).  We need to
+	 * update the FP_C and FPCR, and send a signal for any new
+	 * trap that is enabled.
+	 */
+	uint64_t orig_flags = FP_C_TO_NETBSD_FLAG(l->l_md.md_flags);
+	uint64_t new_flags = orig_flags | *ucode;
+	uint64_t changed_flags = orig_flags ^ new_flags;
+	KASSERT((orig_flags | changed_flags) == new_flags); /* panic on 1->0 */
+
+	l->l_md.md_flags |= NETBSD_FLAG_TO_FP_C(new_flags);
+
+	kpreempt_disable();
+	if ((curlwp->l_md.md_flags & MDLWP_FPACTIVE) == 0) {
+		fpu_load();
+	}
+	alpha_pal_wrfen(1);
+	uint64_t orig_fpcr = alpha_read_fpcr();
+	alpha_write_fpcr(fp_c_to_fpcr_1(orig_fpcr, l->l_md.md_flags));
+	uint64_t needsig =
+	    changed_flags & FP_C_TO_NETBSD_MASK(l->l_md.md_flags);
+	alpha_pal_wrfen(0);
+	kpreempt_enable();
+
+	if (__predict_false(needsig)) {
+		*ucode = needsig;
+		return SIGFPE;
+	}
+	return 0;
+
+ resolved:
 	if (sig) {
 		usertrap_pc = trigger_pc + 1;
 		l->l_md.md_tf->tf_regs[FRAME_PC] = (unsigned long)usertrap_pc;
-		return sig;
 	}
-	return 0;
+	return sig;
 }
 
 /*
@@ -746,6 +856,11 @@
 		atomic_inc_ulong(&fpevent_reuse.ev_count);
 	}
 
+	if (alpha_fp_complete_debug) {
+		printf("%s: [%s:%d] loading FPCR=0x%lx\n",
+		    __func__, l->l_proc->p_comm, l->l_proc->p_pid,
+		    pcb->pcb_fp.fpr_cr);
+	}
 	alpha_pal_wrfen(1);
 	restorefpstate(&pcb->pcb_fp);
 	alpha_pal_wrfen(0);
@@ -765,6 +880,11 @@
 	alpha_pal_wrfen(1);
 	savefpstate(&pcb->pcb_fp);
 	alpha_pal_wrfen(0);
+	if (alpha_fp_complete_debug) {
+		printf("%s: [%s:%d] saved FPCR=0x%lx\n",
+		    __func__, l->l_proc->p_comm, l->l_proc->p_pid,
+		    pcb->pcb_fp.fpr_cr);
+	}
 }
 
 /*

cvs diff -r1.374 -r1.375 src/sys/arch/alpha/alpha/machdep.c (expand / switch to context diff)
--- src/sys/arch/alpha/alpha/machdep.c 2021/07/11 01:58:41 1.374
+++ src/sys/arch/alpha/alpha/machdep.c 2021/07/22 01:39:18 1.375
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.374 2021/07/11 01:58:41 thorpej Exp $ */
+/* $NetBSD: machdep.c,v 1.375 2021/07/22 01:39:18 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2019, 2020 The NetBSD Foundation, Inc.
@@ -65,11 +65,11 @@
 #include "opt_dec_3000_500.h"
 #include "opt_execfmt.h"
 
-#define	__RWLOCK_PRIVATE 
+#define	__RWLOCK_PRIVATE
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.374 2021/07/11 01:58:41 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.375 2021/07/22 01:39:18 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -195,6 +195,7 @@
 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 */
+int	alpha_fp_complete_debug = 0;	/* fp completion debug enabled */
 
 /*
  * XXX This should be dynamically sized, but we have the chicken-egg problem!
@@ -1646,6 +1647,11 @@
 		       CTLTYPE_BOOL, "is_qemu", NULL,
 		       NULL, 0, &alpha_is_qemu, 0,
 		       CTL_MACHDEP, CPU_IS_QEMU, CTL_EOL);
+	sysctl_createv(clog, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		       CTLTYPE_INT, "fp_complete_debug", NULL,
+		       NULL, 0, &alpha_fp_complete_debug, 0,
+		       CTL_MACHDEP, CPU_FP_COMPLETE_DEBUG, CTL_EOL);
 }
 
 /*
@@ -1687,8 +1693,10 @@
 	tfp->tf_regs[FRAME_T12] = tfp->tf_regs[FRAME_PC];	/* a.k.a. PV */
 
 	if (__predict_true((l->l_md.md_flags & IEEE_INHERIT) == 0)) {
-		l->l_md.md_flags &= ~MDLWP_FP_C;
-		pcb->pcb_fp.fpr_cr = FPCR_DYN(FP_RN);
+		l->l_md.md_flags =
+		    (l->l_md.md_flags & ~(MDLWP_FP_C | MDLWP_FPACTIVE)) |
+		    FP_C_DEFAULT;
+		pcb->pcb_fp.fpr_cr = FPCR_DEFAULT;
 	}
 }
 

cvs diff -r1.102 -r1.103 src/sys/arch/alpha/include/cpu.h (expand / switch to context diff)
--- src/sys/arch/alpha/include/cpu.h 2021/06/26 15:02:19 1.102
+++ src/sys/arch/alpha/include/cpu.h 2021/07/22 01:39:18 1.103
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.102 2021/06/26 15:02:19 skrll Exp $ */
+/* $NetBSD: cpu.h,v 1.103 2021/07/22 01:39:18 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -232,6 +232,7 @@
 #define	CPU_FP_SYNC_COMPLETE	7	/* int: always fixup sync fp traps */
 #define	CPU_CCTR		8	/* int: using CC timecounter */
 #define	CPU_IS_QEMU		9	/* int: running under Qemu */
+#define	CPU_FP_COMPLETE_DEBUG	10	/* int: enable FP completion debug */
 
 
 #ifdef _KERNEL

cvs diff -r1.7 -r1.8 src/sys/arch/alpha/include/fpu.h (expand / switch to context diff)
--- src/sys/arch/alpha/include/fpu.h 2017/10/17 00:26:35 1.7
+++ src/sys/arch/alpha/include/fpu.h 2021/07/22 01:39:18 1.8
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu.h,v 1.7 2017/10/17 00:26:35 maya Exp $ */
+/* $NetBSD: fpu.h,v 1.8 2021/07/22 01:39:18 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2001 Ross Harvey
@@ -38,35 +38,50 @@
 #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)
+/*
+ * Bits in the Alpha Floating Point Control register.  This is the hardware
+ * register, and should not be directly manipulated by application software.
+ */
+#define	FPCR_SUM	__BIT(63)	/* Summary (OR of all exception bits) */
+#define	FPCR_INED	__BIT(62)	/* Inexact trap Disable */
+#define	FPCR_UNFD	__BIT(61)	/* Underflow trap Disable */
+#define	FPCR_UNDZ	__BIT(60)	/* Underflow to Zero */
+#define	FPCR_DYN_RM	__BITS(58,59)	/* Dynamic Rounding Mode */
+					/* 00 Chopped */
+					/* 01 Minus Infinity */
+					/* 10 Normal (round nearest) */
+					/* 11 Plus Infinity */
+#define	FPCR_IOV	__BIT(57)	/* Integer Overflow */
+#define	FPCR_INE	__BIT(56)	/* Inexact Result */
+#define	FPCR_UNF	__BIT(55)	/* Underflow */
+#define	FPCR_OVF	__BIT(54)	/* Overflow */
+#define	FPCR_DZE	__BIT(53)	/* Division By Zero */
+#define	FPCR_INV	__BIT(52)	/* Invalid Operation */
+#define	FPCR_OVFD	__BIT(51)	/* Overflow trap Disable */
+#define	FPCR_DZED	__BIT(50)	/* Division By Zero trap Disable */
+#define	FPCR_INVD	__BIT(49)	/* Invalid Operation trap Disable */
+#define	FPCR_DNZ	__BIT(48)	/* Denormal Operands to Zero */
+#define	FPCR_DNOD	__BIT(47)	/* Denormal Operation tap Disable */
 
 #define	FPCR_MIRRORED (FPCR_INE | FPCR_UNF | FPCR_OVF | FPCR_DZE | FPCR_INV)
 #define FPCR_MIR_START 52
 
+/* NetBSD default - no traps enabled, round-to-nearest */
+#define	FPCR_DEFAULT	(__SHIFTIN(FP_RN, FPCR_DYN_RM) |		\
+			 FPCR_INED | FPCR_UNFD | FPCR_OVFD |		\
+			 FPCR_DZED | FPCR_INVD | FPCR_DNOD)
+
 /*
+ * IEEE Floating Point Control (FP_C) Quadword.  This is a software
+ * virtual register that abstracts the FPCR and software complation
+ * performed by the kernel.
+ *
  * 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
@@ -74,30 +89,41 @@
  * the definition prefix can easily be determined from public domain
  * programs written to either the Compaq or Linux interfaces, which
  * appear to be identical.
+ *
+ * Bits 63-48 are reserved for implementation software.
+ * Bits 47-23 are reserved for future archiecture definition.
+ * Bits 16-12 are reserved for implementation software.
+ * Bits 11-7 are reserved for future architecture definition.
+ * Bit 0 is reserved for implementation software.
  */
 
-#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_STATUS_DNO __BIT(22)	/* Denormal Operand */
+#define	IEEE_STATUS_INE __BIT(21)	/* Inexact Result */
+#define	IEEE_STATUS_UNF __BIT(20)	/* Underflow */
+#define	IEEE_STATUS_OVF __BIT(19)	/* Overflow */
+#define	IEEE_STATUS_DZE __BIT(18)	/* Division By Zero */
+#define	IEEE_STATUS_INV __BIT(17)	/* Invalid Operation */
 
-#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_TRAP_ENABLE_DNO __BIT(6)	/* Denormal Operation trap */
+#define	IEEE_TRAP_ENABLE_INE __BIT(5)	/* Inexact Result trap */
+#define	IEEE_TRAP_ENABLE_UNF __BIT(4)	/* Underflow trap */
+#define	IEEE_TRAP_ENABLE_OVF __BIT(3)	/* Overflow trap */
+#define	IEEE_TRAP_ENABLE_DZE __BIT(2)	/* Division By Zero trap */
+#define	IEEE_TRAP_ENABLE_INV __BIT(1)	/* Invalid Operation trap */
 
-#define	IEEE_INHERIT _FP_C_DEF(14)
-#define	IEEE_MAP_UMZ _FP_C_DEF(13)	/* Map underflowed outputs to zero */
-#define	IEEE_MAP_DMZ _FP_C_DEF(12)	/* Map denormal inputs to zero */
+#define	IEEE_INHERIT __BIT(14)
+#define	IEEE_MAP_UMZ __BIT(13)		/* Map underflowed outputs to zero */
+#define	IEEE_MAP_DMZ __BIT(12)		/* Map denormal inputs to zero */
 
-#define FP_C_MIRRORED (IEEE_STATUS_INE | IEEE_STATUS_UNF | IEEE_STATUS_OVF\
-				| IEEE_STATUS_DZE | IEEE_STATUS_INV)
+#define	FP_C_ALLBITS	__BITS(1,22)
+
+#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
 
+/* NetBSD default - no traps enabled (see FPCR default) */
+#define	FP_C_DEFAULT	0
+
 #ifdef _KERNEL
 
 #define	FLD_MASK(len) ((1UL << (len)) - 1)
@@ -115,6 +141,6 @@
 #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 /* _KERNEL */
 
-#endif
+#endif /* _ALPHA_FPU_H_ */