~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/parisc/math-emu/decode_exc.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 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 }
358 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php