// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Linux/PA-RISC Project (http://www.parisc-linux.org/)3*4* Floating-point emulation code5* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>6*/7/*8* BEGIN_DESC9*10* File:11* @(#) pa/fp/decode_exc.c $ Revision: $12*13* Purpose:14* <<please update with a synopsis of the functionality provided by this file>>15*16* External Interfaces:17* <<the following list was autogenerated, please review>>18* decode_fpu(Fpu_register, trap_counts)19*20* Internal Interfaces:21* <<please update>>22*23* Theory:24* <<please update with a overview of the operation of this file>>25*26* END_DESC27*/2829#include <linux/kernel.h>30#include "float.h"31#include "sgl_float.h"32#include "dbl_float.h"33#include "cnv_float.h"34/* #include "types.h" */35#include <asm/signal.h>36#include <asm/siginfo.h>37/* #include <machine/sys/mdep_private.h> */3839#undef Fpustatus_register40#define Fpustatus_register Fpu_register[0]4142/* General definitions */43#define DOESTRAP 144#define NOTRAP 045#define SIGNALCODE(signal, code) ((signal) << 24 | (code))46#define copropbit 1<<31-2 /* bit position 2 */47#define opclass 9 /* bits 21 & 22 */48#define fmtbits 11 /* bits 19 & 20 */49#define df 13 /* bits 17 & 18 */50#define twobits 3 /* mask low-order 2 bits */51#define fivebits 31 /* mask low-order 5 bits */52#define MAX_EXCP_REG 7 /* number of excpeption registers to check */5354/* Exception register definitions */55#define Excp_type(index) Exceptiontype(Fpu_register[index])56#define Excp_instr(index) Instructionfield(Fpu_register[index])57#define Clear_excp_register(index) Allexception(Fpu_register[index]) = 058#define Excp_format() \59(current_ir >> ((current_ir>>opclass & twobits) == 1 ? df : fmtbits) & twobits)6061/* Miscellaneous definitions */62#define Fpu_sgl(index) Fpu_register[index*2]6364#define Fpu_dblp1(index) Fpu_register[index*2]65#define Fpu_dblp2(index) Fpu_register[(index*2)+1]6667#define Fpu_quadp1(index) Fpu_register[index*2]68#define Fpu_quadp2(index) Fpu_register[(index*2)+1]69#define Fpu_quadp3(index) Fpu_register[(index*2)+2]70#define Fpu_quadp4(index) Fpu_register[(index*2)+3]7172/* Single precision floating-point definitions */73#ifndef Sgl_decrement74# define Sgl_decrement(sgl_value) Sall(sgl_value)--75#endif7677/* Double precision floating-point definitions */78#ifndef Dbl_decrement79# define Dbl_decrement(dbl_valuep1,dbl_valuep2) \80if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)--81#endif828384#define update_trap_counts(Fpu_register, aflags, bflags, trap_counts) { \85aflags=(Fpu_register[0])>>27; /* assumes zero fill. 32 bit */ \86Fpu_register[0] |= bflags; \87}8889u_int90decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])91{92unsigned int current_ir, excp;93int target, exception_index = 1;94boolean inexact;95unsigned int aflags;96unsigned int bflags;97unsigned int excptype;9899100/* Keep stats on how many floating point exceptions (based on type)101* that happen. Want to keep this overhead low, but still provide102* some information to the customer. All exits from this routine103* need to restore Fpu_register[0]104*/105106bflags=(Fpu_register[0] & 0xf8000000);107Fpu_register[0] &= 0x07ffffff;108109/* exception_index is used to index the exception register queue. It110* always points at the last register that contains a valid exception. A111* zero value implies no exceptions (also the initialized value). Setting112* the T-bit resets the exception_index to zero.113*/114115/*116* Check for reserved-op exception. A reserved-op exception does not117* set any exception registers nor does it set the T-bit. If the T-bit118* is not set then a reserved-op exception occurred.119*120* At some point, we may want to report reserved op exceptions as121* illegal instructions.122*/123124if (!Is_tbit_set()) {125update_trap_counts(Fpu_register, aflags, bflags, trap_counts);126return SIGNALCODE(SIGILL, ILL_COPROC);127}128129/*130* Is a coprocessor op.131*132* Now we need to determine what type of exception occurred.133*/134for (exception_index=1; exception_index<=MAX_EXCP_REG; exception_index++) {135current_ir = Excp_instr(exception_index);136/*137* On PA89: there are 5 different unimplemented exception138* codes: 0x1, 0x9, 0xb, 0x3, and 0x23. PA-RISC 2.0 adds139* another, 0x2b. Only these have the low order bit set.140*/141excptype = Excp_type(exception_index);142if (excptype & UNIMPLEMENTEDEXCEPTION) {143/*144* Clear T-bit and exception register so that145* we can tell if a trap really occurs while146* emulating the instruction.147*/148Clear_tbit();149Clear_excp_register(exception_index);150/*151* Now emulate this instruction. If a trap occurs,152* fpudispatch will return a non-zero number153*/154excp = fpudispatch(current_ir,excptype,0,Fpu_register);155/* accumulate the status flags, don't lose them as in hpux */156if (excp) {157/*158* We now need to make sure that the T-bit and the159* exception register contain the correct values160* before continuing.161*/162/*163* Set t-bit since it might still be needed for a164* subsequent real trap (I don't understand fully -PB)165*/166Set_tbit();167/* some of the following code uses168* Excp_type(exception_index) so fix that up */169Set_exceptiontype_and_instr_field(excp,current_ir,170Fpu_register[exception_index]);171if (excp == UNIMPLEMENTEDEXCEPTION) {172/*173* it is really unimplemented, so restore the174* TIMEX extended unimplemented exception code175*/176excp = excptype;177update_trap_counts(Fpu_register, aflags, bflags,178trap_counts);179return SIGNALCODE(SIGILL, ILL_COPROC);180}181/* some of the following code uses excptype, so182* fix that up too */183excptype = excp;184}185/* handle exceptions other than the real UNIMPLIMENTED the186* same way as if the hardware had caused them */187if (excp == NOEXCEPTION)188/* For now use 'break', should technically be 'continue' */189break;190}191192/*193* In PA89, the underflow exception has been extended to encode194* additional information. The exception looks like pp01x0,195* where x is 1 if inexact and pp represent the inexact bit (I)196* and the round away bit (RA)197*/198if (excptype & UNDERFLOWEXCEPTION) {199/* check for underflow trap enabled */200if (Is_underflowtrap_enabled()) {201update_trap_counts(Fpu_register, aflags, bflags,202trap_counts);203return SIGNALCODE(SIGFPE, FPE_FLTUND);204} else {205/*206* Isn't a real trap; we need to207* return the default value.208*/209target = current_ir & fivebits;210#ifndef lint211if (Ibit(Fpu_register[exception_index])) inexact = TRUE;212else inexact = FALSE;213#endif214switch (Excp_format()) {215case SGL:216/*217* If ra (round-away) is set, will218* want to undo the rounding done219* by the hardware.220*/221if (Rabit(Fpu_register[exception_index]))222Sgl_decrement(Fpu_sgl(target));223224/* now denormalize */225sgl_denormalize(&Fpu_sgl(target),&inexact,Rounding_mode());226break;227case DBL:228/*229* If ra (round-away) is set, will230* want to undo the rounding done231* by the hardware.232*/233if (Rabit(Fpu_register[exception_index]))234Dbl_decrement(Fpu_dblp1(target),Fpu_dblp2(target));235236/* now denormalize */237dbl_denormalize(&Fpu_dblp1(target),&Fpu_dblp2(target),238&inexact,Rounding_mode());239break;240}241if (inexact) Set_underflowflag();242/*243* Underflow can generate an inexact244* exception. If inexact trap is enabled,245* want to do an inexact trap, otherwise246* set inexact flag.247*/248if (inexact && Is_inexacttrap_enabled()) {249/*250* Set exception field of exception register251* to inexact, parm field to zero.252* Underflow bit should be cleared.253*/254Set_exceptiontype(Fpu_register[exception_index],255INEXACTEXCEPTION);256Set_parmfield(Fpu_register[exception_index],0);257update_trap_counts(Fpu_register, aflags, bflags,258trap_counts);259return SIGNALCODE(SIGFPE, FPE_FLTRES);260}261else {262/*263* Exception register needs to be cleared.264* Inexact flag needs to be set if inexact.265*/266Clear_excp_register(exception_index);267if (inexact) Set_inexactflag();268}269}270continue;271}272switch(Excp_type(exception_index)) {273case OVERFLOWEXCEPTION:274case OVERFLOWEXCEPTION | INEXACTEXCEPTION:275/* check for overflow trap enabled */276update_trap_counts(Fpu_register, aflags, bflags,277trap_counts);278if (Is_overflowtrap_enabled()) {279update_trap_counts(Fpu_register, aflags, bflags,280trap_counts);281return SIGNALCODE(SIGFPE, FPE_FLTOVF);282} else {283/*284* Isn't a real trap; we need to285* return the default value.286*/287target = current_ir & fivebits;288switch (Excp_format()) {289case SGL:290Sgl_setoverflow(Fpu_sgl(target));291break;292case DBL:293Dbl_setoverflow(Fpu_dblp1(target),Fpu_dblp2(target));294break;295}296Set_overflowflag();297/*298* Overflow always generates an inexact299* exception. If inexact trap is enabled,300* want to do an inexact trap, otherwise301* set inexact flag.302*/303if (Is_inexacttrap_enabled()) {304/*305* Set exception field of exception306* register to inexact. Overflow307* bit should be cleared.308*/309Set_exceptiontype(Fpu_register[exception_index],310INEXACTEXCEPTION);311update_trap_counts(Fpu_register, aflags, bflags,312trap_counts);313return SIGNALCODE(SIGFPE, FPE_FLTRES);314}315else {316/*317* Exception register needs to be cleared.318* Inexact flag needs to be set.319*/320Clear_excp_register(exception_index);321Set_inexactflag();322}323}324break;325case INVALIDEXCEPTION:326case OPC_2E_INVALIDEXCEPTION:327update_trap_counts(Fpu_register, aflags, bflags, trap_counts);328return SIGNALCODE(SIGFPE, FPE_FLTINV);329case DIVISIONBYZEROEXCEPTION:330update_trap_counts(Fpu_register, aflags, bflags, trap_counts);331Clear_excp_register(exception_index);332return SIGNALCODE(SIGFPE, FPE_FLTDIV);333case INEXACTEXCEPTION:334update_trap_counts(Fpu_register, aflags, bflags, trap_counts);335return SIGNALCODE(SIGFPE, FPE_FLTRES);336default:337update_trap_counts(Fpu_register, aflags, bflags, trap_counts);338printk("%s(%d) Unknown FPU exception 0x%x\n", __FILE__,339__LINE__, Excp_type(exception_index));340return SIGNALCODE(SIGILL, ILL_COPROC);341case NOEXCEPTION: /* no exception */342/*343* Clear exception register in case344* other fields are non-zero.345*/346Clear_excp_register(exception_index);347break;348}349}350/*351* No real exceptions occurred.352*/353Clear_tbit();354update_trap_counts(Fpu_register, aflags, bflags, trap_counts);355return(NOTRAP);356}357358359