1 /*- 2 * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/msun/alpha/fenv.c,v 1.2 2005/03/16 19:03:44 das Exp $ 27 */ 28 29 #include <sys/cdefs.h> 30 #include <machine/sysarch.h> 31 #include <fenv.h> 32 33 const fenv_t __fe_dfl_env = 0x680e000000000000ULL; 34 35 struct mask_args { 36 fenv_t mask; 37 }; 38 39 /* 40 * The lower 49 bits of the FPCR are unused by the hardware, so we use 41 * the lower order bits to store the kernel's idea of the FP mask as 42 * described in the Alpha Architecture Manual. 43 */ 44 int 45 fegetenv(fenv_t *envp) 46 { 47 struct mask_args p; 48 union __fpcr r; 49 50 /* 51 * The syscall acts as an implicit exception barrier, so we 52 * only need to issue an excb after the mf_fpcr to ensure that 53 * the read is executed before any subsequent FP ops. 54 */ 55 sysarch(ALPHA_GET_FPMASK, (char *)&p); 56 __mf_fpcr(&r.__d); 57 *envp = r.__bits | p.mask; 58 __excb(); 59 return (0); 60 } 61 62 int 63 feholdexcept(fenv_t *envp) 64 { 65 struct mask_args p; 66 union __fpcr r; 67 68 sysarch(ALPHA_GET_FPMASK, (char *)&p); 69 __mf_fpcr(&r.__d); 70 *envp = r.__bits | p.mask; 71 r.__bits &= ~((fenv_t)FE_ALL_EXCEPT << _FPUSW_SHIFT); 72 __mt_fpcr(r.__d); 73 if (p.mask & FE_ALL_EXCEPT) { 74 p.mask = 0; 75 sysarch(ALPHA_SET_FPMASK, &p); 76 } 77 __excb(); 78 return (0); 79 } 80 81 int 82 fesetenv(const fenv_t *envp) 83 { 84 struct mask_args p; 85 union __fpcr r; 86 87 p.mask = *envp & FE_ALL_EXCEPT; 88 sysarch(ALPHA_SET_FPMASK, &p); 89 r.__bits = *envp & ~FE_ALL_EXCEPT; 90 __mt_fpcr(r.__d); 91 __excb(); 92 return (0); 93 } 94 95 int 96 feupdateenv(const fenv_t *envp) 97 { 98 struct mask_args p; 99 union __fpcr oldr, newr; 100 101 p.mask = *envp & FE_ALL_EXCEPT; 102 sysarch(ALPHA_SET_FPMASK, &p); 103 __mf_fpcr(&oldr.__d); 104 newr.__bits = *envp & ~FE_ALL_EXCEPT; 105 __excb(); 106 __mt_fpcr(newr.__d); 107 feraiseexcept((oldr.__bits >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 108 return (0); 109 } 110 111 int 112 __feenableexcept(int mask) 113 { 114 struct mask_args p; 115 116 sysarch(ALPHA_GET_FPMASK, &p); 117 p.mask |= (mask & FE_ALL_EXCEPT); 118 sysarch(ALPHA_SET_FPMASK, &p); 119 return (p.mask); 120 } 121 122 int 123 __fedisableexcept(int mask) 124 { 125 struct mask_args p; 126 127 sysarch(ALPHA_GET_FPMASK, &p); 128 p.mask &= ~(mask & FE_ALL_EXCEPT); 129 sysarch(ALPHA_SET_FPMASK, &p); 130 return (p.mask); 131 } 132 133 int 134 __fegetexcept(void) 135 { 136 struct mask_args p; 137 138 sysarch(ALPHA_GET_FPMASK, &p); 139 return (p.mask); 140 } 141 142 __weak_reference(__feenableexcept, feenableexcept); 143 __weak_reference(__fedisableexcept, fedisableexcept); 144 __weak_reference(__fegetexcept, fegetexcept); 145