Path: blob/master/arch/parisc/math-emu/decode_exc.c
10817 views
/*1* Linux/PA-RISC Project (http://www.parisc-linux.org/)2*3* Floating-point emulation code4* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>5*6* This program is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License as published by8* the Free Software Foundation; either version 2, or (at your option)9* any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA19*/20/*21* BEGIN_DESC22*23* File:24* @(#) pa/fp/decode_exc.c $ Revision: $25*26* Purpose:27* <<please update with a synopsis of the functionality provided by this file>>28*29* External Interfaces:30* <<the following list was autogenerated, please review>>31* decode_fpu(Fpu_register, trap_counts)32*33* Internal Interfaces:34* <<please update>>35*36* Theory:37* <<please update with a overview of the operation of this file>>38*39* END_DESC40*/4142#include <linux/kernel.h>43#include "float.h"44#include "sgl_float.h"45#include "dbl_float.h"46#include "cnv_float.h"47/* #include "types.h" */48#include <asm/signal.h>49#include <asm/siginfo.h>50/* #include <machine/sys/mdep_private.h> */5152#undef Fpustatus_register53#define Fpustatus_register Fpu_register[0]5455/* General definitions */56#define DOESTRAP 157#define NOTRAP 058#define SIGNALCODE(signal, code) ((signal) << 24 | (code));59#define copropbit 1<<31-2 /* bit position 2 */60#define opclass 9 /* bits 21 & 22 */61#define fmt 11 /* bits 19 & 20 */62#define df 13 /* bits 17 & 18 */63#define twobits 3 /* mask low-order 2 bits */64#define fivebits 31 /* mask low-order 5 bits */65#define MAX_EXCP_REG 7 /* number of excpeption registers to check */6667/* Exception register definitions */68#define Excp_type(index) Exceptiontype(Fpu_register[index])69#define Excp_instr(index) Instructionfield(Fpu_register[index])70#define Clear_excp_register(index) Allexception(Fpu_register[index]) = 071#define Excp_format() \72(current_ir >> ((current_ir>>opclass & twobits)==1 ? df : fmt) & twobits)7374/* Miscellaneous definitions */75#define Fpu_sgl(index) Fpu_register[index*2]7677#define Fpu_dblp1(index) Fpu_register[index*2]78#define Fpu_dblp2(index) Fpu_register[(index*2)+1]7980#define Fpu_quadp1(index) Fpu_register[index*2]81#define Fpu_quadp2(index) Fpu_register[(index*2)+1]82#define Fpu_quadp3(index) Fpu_register[(index*2)+2]83#define Fpu_quadp4(index) Fpu_register[(index*2)+3]8485/* Single precision floating-point definitions */86#ifndef Sgl_decrement87# define Sgl_decrement(sgl_value) Sall(sgl_value)--88#endif8990/* Double precision floating-point definitions */91#ifndef Dbl_decrement92# define Dbl_decrement(dbl_valuep1,dbl_valuep2) \93if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)--94#endif959697#define update_trap_counts(Fpu_register, aflags, bflags, trap_counts) { \98aflags=(Fpu_register[0])>>27; /* assumes zero fill. 32 bit */ \99Fpu_register[0] |= bflags; \100}101102u_int103decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])104{105unsigned int current_ir, excp;106int target, exception_index = 1;107boolean inexact;108unsigned int aflags;109unsigned int bflags;110unsigned int excptype;111112113/* Keep stats on how many floating point exceptions (based on type)114* that happen. Want to keep this overhead low, but still provide115* some information to the customer. All exits from this routine116* need to restore Fpu_register[0]117*/118119bflags=(Fpu_register[0] & 0xf8000000);120Fpu_register[0] &= 0x07ffffff;121122/* exception_index is used to index the exception register queue. It123* always points at the last register that contains a valid exception. A124* zero value implies no exceptions (also the initialized value). Setting125* the T-bit resets the exception_index to zero.126*/127128/*129* Check for reserved-op exception. A reserved-op exception does not130* set any exception registers nor does it set the T-bit. If the T-bit131* is not set then a reserved-op exception occurred.132*133* At some point, we may want to report reserved op exceptions as134* illegal instructions.135*/136137if (!Is_tbit_set()) {138update_trap_counts(Fpu_register, aflags, bflags, trap_counts);139return SIGNALCODE(SIGILL, ILL_COPROC);140}141142/*143* Is a coprocessor op.144*145* Now we need to determine what type of exception occurred.146*/147for (exception_index=1; exception_index<=MAX_EXCP_REG; exception_index++) {148current_ir = Excp_instr(exception_index);149/*150* On PA89: there are 5 different unimplemented exception151* codes: 0x1, 0x9, 0xb, 0x3, and 0x23. PA-RISC 2.0 adds152* another, 0x2b. Only these have the low order bit set.153*/154excptype = Excp_type(exception_index);155if (excptype & UNIMPLEMENTEDEXCEPTION) {156/*157* Clear T-bit and exception register so that158* we can tell if a trap really occurs while159* emulating the instruction.160*/161Clear_tbit();162Clear_excp_register(exception_index);163/*164* Now emulate this instruction. If a trap occurs,165* fpudispatch will return a non-zero number166*/167excp = fpudispatch(current_ir,excptype,0,Fpu_register);168/* accumulate the status flags, don't lose them as in hpux */169if (excp) {170/*171* We now need to make sure that the T-bit and the172* exception register contain the correct values173* before continuing.174*/175/*176* Set t-bit since it might still be needed for a177* subsequent real trap (I don't understand fully -PB)178*/179Set_tbit();180/* some of the following code uses181* Excp_type(exception_index) so fix that up */182Set_exceptiontype_and_instr_field(excp,current_ir,183Fpu_register[exception_index]);184if (excp == UNIMPLEMENTEDEXCEPTION) {185/*186* it is really unimplemented, so restore the187* TIMEX extended unimplemented exception code188*/189excp = excptype;190update_trap_counts(Fpu_register, aflags, bflags,191trap_counts);192return SIGNALCODE(SIGILL, ILL_COPROC);193}194/* some of the following code uses excptype, so195* fix that up too */196excptype = excp;197}198/* handle exceptions other than the real UNIMPLIMENTED the199* same way as if the hardware had caused them */200if (excp == NOEXCEPTION)201/* For now use 'break', should technically be 'continue' */202break;203}204205/*206* In PA89, the underflow exception has been extended to encode207* additional information. The exception looks like pp01x0,208* where x is 1 if inexact and pp represent the inexact bit (I)209* and the round away bit (RA)210*/211if (excptype & UNDERFLOWEXCEPTION) {212/* check for underflow trap enabled */213if (Is_underflowtrap_enabled()) {214update_trap_counts(Fpu_register, aflags, bflags,215trap_counts);216return SIGNALCODE(SIGFPE, FPE_FLTUND);217} else {218/*219* Isn't a real trap; we need to220* return the default value.221*/222target = current_ir & fivebits;223#ifndef lint224if (Ibit(Fpu_register[exception_index])) inexact = TRUE;225else inexact = FALSE;226#endif227switch (Excp_format()) {228case SGL:229/*230* If ra (round-away) is set, will231* want to undo the rounding done232* by the hardware.233*/234if (Rabit(Fpu_register[exception_index]))235Sgl_decrement(Fpu_sgl(target));236237/* now denormalize */238sgl_denormalize(&Fpu_sgl(target),&inexact,Rounding_mode());239break;240case DBL:241/*242* If ra (round-away) is set, will243* want to undo the rounding done244* by the hardware.245*/246if (Rabit(Fpu_register[exception_index]))247Dbl_decrement(Fpu_dblp1(target),Fpu_dblp2(target));248249/* now denormalize */250dbl_denormalize(&Fpu_dblp1(target),&Fpu_dblp2(target),251&inexact,Rounding_mode());252break;253}254if (inexact) Set_underflowflag();255/*256* Underflow can generate an inexact257* exception. If inexact trap is enabled,258* want to do an inexact trap, otherwise259* set inexact flag.260*/261if (inexact && Is_inexacttrap_enabled()) {262/*263* Set exception field of exception register264* to inexact, parm field to zero.265* Underflow bit should be cleared.266*/267Set_exceptiontype(Fpu_register[exception_index],268INEXACTEXCEPTION);269Set_parmfield(Fpu_register[exception_index],0);270update_trap_counts(Fpu_register, aflags, bflags,271trap_counts);272return SIGNALCODE(SIGFPE, FPE_FLTRES);273}274else {275/*276* Exception register needs to be cleared.277* Inexact flag needs to be set if inexact.278*/279Clear_excp_register(exception_index);280if (inexact) Set_inexactflag();281}282}283continue;284}285switch(Excp_type(exception_index)) {286case OVERFLOWEXCEPTION:287case OVERFLOWEXCEPTION | INEXACTEXCEPTION:288/* check for overflow trap enabled */289update_trap_counts(Fpu_register, aflags, bflags,290trap_counts);291if (Is_overflowtrap_enabled()) {292update_trap_counts(Fpu_register, aflags, bflags,293trap_counts);294return SIGNALCODE(SIGFPE, FPE_FLTOVF);295} else {296/*297* Isn't a real trap; we need to298* return the default value.299*/300target = current_ir & fivebits;301switch (Excp_format()) {302case SGL:303Sgl_setoverflow(Fpu_sgl(target));304break;305case DBL:306Dbl_setoverflow(Fpu_dblp1(target),Fpu_dblp2(target));307break;308}309Set_overflowflag();310/*311* Overflow always generates an inexact312* exception. If inexact trap is enabled,313* want to do an inexact trap, otherwise314* set inexact flag.315*/316if (Is_inexacttrap_enabled()) {317/*318* Set exception field of exception319* register to inexact. Overflow320* bit should be cleared.321*/322Set_exceptiontype(Fpu_register[exception_index],323INEXACTEXCEPTION);324update_trap_counts(Fpu_register, aflags, bflags,325trap_counts);326return SIGNALCODE(SIGFPE, FPE_FLTRES);327}328else {329/*330* Exception register needs to be cleared.331* Inexact flag needs to be set.332*/333Clear_excp_register(exception_index);334Set_inexactflag();335}336}337break;338case INVALIDEXCEPTION:339case OPC_2E_INVALIDEXCEPTION:340update_trap_counts(Fpu_register, aflags, bflags, trap_counts);341return SIGNALCODE(SIGFPE, FPE_FLTINV);342case DIVISIONBYZEROEXCEPTION:343update_trap_counts(Fpu_register, aflags, bflags, trap_counts);344Clear_excp_register(exception_index);345return SIGNALCODE(SIGFPE, FPE_FLTDIV);346case INEXACTEXCEPTION:347update_trap_counts(Fpu_register, aflags, bflags, trap_counts);348return SIGNALCODE(SIGFPE, FPE_FLTRES);349default:350update_trap_counts(Fpu_register, aflags, bflags, trap_counts);351printk("%s(%d) Unknown FPU exception 0x%x\n", __FILE__,352__LINE__, Excp_type(exception_index));353return SIGNALCODE(SIGILL, ILL_COPROC);354case NOEXCEPTION: /* no exception */355/*356* Clear exception register in case357* other fields are non-zero.358*/359Clear_excp_register(exception_index);360break;361}362}363/*364* No real exceptions occurred.365*/366Clear_tbit();367update_trap_counts(Fpu_register, aflags, bflags, trap_counts);368return(NOTRAP);369}370371372