linux/arch/parisc/math-emu/decode_exc.c
<<
>>
Prefs
   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 fmtbits         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 : fmtbits) & 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
  90u_int
  91decode_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