root/arch/parisc/math-emu/decode_exc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. decode_fpu

   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 }

/* [<][>][^][v][top][bottom][index][help] */