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