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