1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Linux/PA-RISC Project (http://www.parisc-linux.org/) 4 * 5 * Floating-point emulation code 6 * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 7 */ 8 /* 9 * BEGIN_DESC 10 * 11 * File: 12 * @(#) pa/fp/decode_exc.c $ Revision: $ 13 * 14 * Purpose: 15 * <<please update with a synopsis of the functionality provided by this file>> 16 * 17 * External Interfaces: 18 * <<the following list was autogenerated, please review>> 19 * decode_fpu(Fpu_register, trap_counts) 20 * 21 * Internal Interfaces: 22 * <<please update>> 23 * 24 * Theory: 25 * <<please update with a overview of the operation of this file>> 26 * 27 * END_DESC 28 */ 29 30 #include <linux/kernel.h> 31 #include "float.h" 32 #include "sgl_float.h" 33 #include "dbl_float.h" 34 #include "cnv_float.h" 35 /* #include "types.h" */ 36 #include <asm/signal.h> 37 #include <asm/siginfo.h> 38 /* #include <machine/sys/mdep_private.h> */ 39 40 #undef Fpustatus_register 41 #define Fpustatus_register Fpu_register[0] 42 43 /* General definitions */ 44 #define DOESTRAP 1 45 #define NOTRAP 0 46 #define SIGNALCODE(signal, code) ((signal) << 24 | (code)) 47 #define copropbit 1<<31-2 /* bit position 2 */ 48 #define opclass 9 /* bits 21 & 22 */ 49 #define fmt 11 /* bits 19 & 20 */ 50 #define df 13 /* bits 17 & 18 */ 51 #define twobits 3 /* mask low-order 2 bits */ 52 #define fivebits 31 /* mask low-order 5 bits */ 53 #define MAX_EXCP_REG 7 /* number of excpeption registers to check */ 54 55 /* Exception register definitions */ 56 #define Excp_type(index) Exceptiontype(Fpu_register[index]) 57 #define Excp_instr(index) Instructionfield(Fpu_register[index]) 58 #define Clear_excp_register(index) Allexception(Fpu_register[index]) = 0 59 #define Excp_format() \ 60 (current_ir >> ((current_ir>>opclass & twobits)==1 ? df : fmt) & twobits) 61 62 /* Miscellaneous definitions */ 63 #define Fpu_sgl(index) Fpu_register[index*2] 64 65 #define Fpu_dblp1(index) Fpu_register[index*2] 66 #define Fpu_dblp2(index) Fpu_register[(index*2)+1] 67 68 #define Fpu_quadp1(index) Fpu_register[index*2] 69 #define Fpu_quadp2(index) Fpu_register[(index*2)+1] 70 #define Fpu_quadp3(index) Fpu_register[(index*2)+2] 71 #define Fpu_quadp4(index) Fpu_register[(index*2)+3] 72 73 /* Single precision floating-point definitions */ 74 #ifndef Sgl_decrement 75 # define Sgl_decrement(sgl_value) Sall(sgl_value)-- 76 #endif 77 78 /* Double precision floating-point definitions */ 79 #ifndef Dbl_decrement 80 # define Dbl_decrement(dbl_valuep1,dbl_valuep2) \ 81 if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)-- 82 #endif 83 84 85 #define update_trap_counts(Fpu_register, aflags, bflags, trap_counts) { \ 86 aflags=(Fpu_register[0])>>27; /* assumes zero fill. 32 bit */ \ 87 Fpu_register[0] |= bflags; \ 88 } 89 90 u_int 91 decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[]) 92 { 93 unsigned int current_ir, excp; 94 int target, exception_index = 1; 95 boolean inexact; 96 unsigned int aflags; 97 unsigned int bflags; 98 unsigned int excptype; 99 100 101 /* Keep stats on how many floating point exceptions (based on type) 102 * that happen. Want to keep this overhead low, but still provide 103 * some information to the customer. All exits from this routine 104 * need to restore Fpu_register[0] 105 */ 106 107 bflags=(Fpu_register[0] & 0xf8000000); 108 Fpu_register[0] &= 0x07ffffff; 109 110 /* exception_index is used to index the exception register queue. It 111 * always points at the last register that contains a valid exception. A 112 * zero value implies no exceptions (also the initialized value). Setting 113 * the T-bit resets the exception_index to zero. 114 */ 115 116 /* 117 * Check for reserved-op exception. A reserved-op exception does not 118 * set any exception registers nor does it set the T-bit. If the T-bit 119 * is not set then a reserved-op exception occurred. 120 * 121 * At some point, we may want to report reserved op exceptions as 122 * illegal instructions. 123 */ 124 125 if (!Is_tbit_set()) { 126 update_trap_counts(Fpu_register, aflags, bflags, trap_counts); 127 return SIGNALCODE(SIGILL, ILL_COPROC); 128 } 129 130 /* 131 * Is a coprocessor op. 132 * 133 * Now we need to determine what type of exception occurred. 134 */ 135 for (exception_index=1; exception_index<=MAX_EXCP_REG; exception_index++) { 136 current_ir = Excp_instr(exception_index); 137 /* 138 * On PA89: there are 5 different unimplemented exception 139 * codes: 0x1, 0x9, 0xb, 0x3, and 0x23. PA-RISC 2.0 adds 140 * another, 0x2b. Only these have the low order bit set. 141 */ 142 excptype = Excp_type(exception_index); 143 if (excptype & UNIMPLEMENTEDEXCEPTION) { 144 /* 145 * Clear T-bit and exception register so that 146 * we can tell if a trap really occurs while 147 * emulating the instruction. 148 */ 149 Clear_tbit(); 150 Clear_excp_register(exception_index); 151 /* 152 * Now emulate this instruction. If a trap occurs, 153 * fpudispatch will return a non-zero number 154 */ 155 excp = fpudispatch(current_ir,excptype,0,Fpu_register); 156 /* accumulate the status flags, don't lose them as in hpux */ 157 if (excp) { 158 /* 159 * We now need to make sure that the T-bit and the 160 * exception register contain the correct values 161 * before continuing. 162 */ 163 /* 164 * Set t-bit since it might still be needed for a 165 * subsequent real trap (I don't understand fully -PB) 166 */ 167 Set_tbit(); 168 /* some of the following code uses 169 * Excp_type(exception_index) so fix that up */ 170 Set_exceptiontype_and_instr_field(excp,current_ir, 171 Fpu_register[exception_index]); 172 if (excp == UNIMPLEMENTEDEXCEPTION) { 173 /* 174 * it is really unimplemented, so restore the 175 * TIMEX extended unimplemented exception code 176 */ 177 excp = excptype; 178 update_trap_counts(Fpu_register, aflags, bflags, 179 trap_counts); 180 return SIGNALCODE(SIGILL, ILL_COPROC); 181 } 182 /* some of the following code uses excptype, so 183 * fix that up too */ 184 excptype = excp; 185 } 186 /* handle exceptions other than the real UNIMPLIMENTED the 187 * same way as if the hardware had caused them */ 188 if (excp == NOEXCEPTION) 189 /* For now use 'break', should technically be 'continue' */ 190 break; 191 } 192 193 /* 194 * In PA89, the underflow exception has been extended to encode 195 * additional information. The exception looks like pp01x0, 196 * where x is 1 if inexact and pp represent the inexact bit (I) 197 * and the round away bit (RA) 198 */ 199 if (excptype & UNDERFLOWEXCEPTION) { 200 /* check for underflow trap enabled */ 201 if (Is_underflowtrap_enabled()) { 202 update_trap_counts(Fpu_register, aflags, bflags, 203 trap_counts); 204 return SIGNALCODE(SIGFPE, FPE_FLTUND); 205 } else { 206 /* 207 * Isn't a real trap; we need to 208 * return the default value. 209 */ 210 target = current_ir & fivebits; 211 #ifndef lint 212 if (Ibit(Fpu_register[exception_index])) inexact = TRUE; 213 else inexact = FALSE; 214 #endif 215 switch (Excp_format()) { 216 case SGL: 217 /* 218 * If ra (round-away) is set, will 219 * want to undo the rounding done 220 * by the hardware. 221 */ 222 if (Rabit(Fpu_register[exception_index])) 223 Sgl_decrement(Fpu_sgl(target)); 224 225 /* now denormalize */ 226 sgl_denormalize(&Fpu_sgl(target),&inexact,Rounding_mode()); 227 break; 228 case DBL: 229 /* 230 * If ra (round-away) is set, will 231 * want to undo the rounding done 232 * by the hardware. 233 */ 234 if (Rabit(Fpu_register[exception_index])) 235 Dbl_decrement(Fpu_dblp1(target),Fpu_dblp2(target)); 236 237 /* now denormalize */ 238 dbl_denormalize(&Fpu_dblp1(target),&Fpu_dblp2(target), 239 &inexact,Rounding_mode()); 240 break; 241 } 242 if (inexact) Set_underflowflag(); 243 /* 244 * Underflow can generate an inexact 245 * exception. If inexact trap is enabled, 246 * want to do an inexact trap, otherwise 247 * set inexact flag. 248 */ 249 if (inexact && Is_inexacttrap_enabled()) { 250 /* 251 * Set exception field of exception register 252 * to inexact, parm field to zero. 253 * Underflow bit should be cleared. 254 */ 255 Set_exceptiontype(Fpu_register[exception_index], 256 INEXACTEXCEPTION); 257 Set_parmfield(Fpu_register[exception_index],0); 258 update_trap_counts(Fpu_register, aflags, bflags, 259 trap_counts); 260 return SIGNALCODE(SIGFPE, FPE_FLTRES); 261 } 262 else { 263 /* 264 * Exception register needs to be cleared. 265 * Inexact flag needs to be set if inexact. 266 */ 267 Clear_excp_register(exception_index); 268 if (inexact) Set_inexactflag(); 269 } 270 } 271 continue; 272 } 273 switch(Excp_type(exception_index)) { 274 case OVERFLOWEXCEPTION: 275 case OVERFLOWEXCEPTION | INEXACTEXCEPTION: 276 /* check for overflow trap enabled */ 277 update_trap_counts(Fpu_register, aflags, bflags, 278 trap_counts); 279 if (Is_overflowtrap_enabled()) { 280 update_trap_counts(Fpu_register, aflags, bflags, 281 trap_counts); 282 return SIGNALCODE(SIGFPE, FPE_FLTOVF); 283 } else { 284 /* 285 * Isn't a real trap; we need to 286 * return the default value. 287 */ 288 target = current_ir & fivebits; 289 switch (Excp_format()) { 290 case SGL: 291 Sgl_setoverflow(Fpu_sgl(target)); 292 break; 293 case DBL: 294 Dbl_setoverflow(Fpu_dblp1(target),Fpu_dblp2(target)); 295 break; 296 } 297 Set_overflowflag(); 298 /* 299 * Overflow always generates an inexact 300 * exception. If inexact trap is enabled, 301 * want to do an inexact trap, otherwise 302 * set inexact flag. 303 */ 304 if (Is_inexacttrap_enabled()) { 305 /* 306 * Set exception field of exception 307 * register to inexact. Overflow 308 * bit should be cleared. 309 */ 310 Set_exceptiontype(Fpu_register[exception_index], 311 INEXACTEXCEPTION); 312 update_trap_counts(Fpu_register, aflags, bflags, 313 trap_counts); 314 return SIGNALCODE(SIGFPE, FPE_FLTRES); 315 } 316 else { 317 /* 318 * Exception register needs to be cleared. 319 * Inexact flag needs to be set. 320 */ 321 Clear_excp_register(exception_index); 322 Set_inexactflag(); 323 } 324 } 325 break; 326 case INVALIDEXCEPTION: 327 case OPC_2E_INVALIDEXCEPTION: 328 update_trap_counts(Fpu_register, aflags, bflags, trap_counts); 329 return SIGNALCODE(SIGFPE, FPE_FLTINV); 330 case DIVISIONBYZEROEXCEPTION: 331 update_trap_counts(Fpu_register, aflags, bflags, trap_counts); 332 Clear_excp_register(exception_index); 333 return SIGNALCODE(SIGFPE, FPE_FLTDIV); 334 case INEXACTEXCEPTION: 335 update_trap_counts(Fpu_register, aflags, bflags, trap_counts); 336 return SIGNALCODE(SIGFPE, FPE_FLTRES); 337 default: 338 update_trap_counts(Fpu_register, aflags, bflags, trap_counts); 339 printk("%s(%d) Unknown FPU exception 0x%x\n", __FILE__, 340 __LINE__, Excp_type(exception_index)); 341 return SIGNALCODE(SIGILL, ILL_COPROC); 342 case NOEXCEPTION: /* no exception */ 343 /* 344 * Clear exception register in case 345 * other fields are non-zero. 346 */ 347 Clear_excp_register(exception_index); 348 break; 349 } 350 } 351 /* 352 * No real exceptions occurred. 353 */ 354 Clear_tbit(); 355 update_trap_counts(Fpu_register, aflags, bflags, trap_counts); 356 return(NOTRAP); 357 } 358