Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
decode_exc.c
Go to the documentation of this file.
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) <[email protected]>
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 
103 u_int
104 decode_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],
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:
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  }
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],
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:
341  update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
342  return SIGNALCODE(SIGFPE, FPE_FLTINV);
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 }