1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
5 * Floating-point emulation code
6 * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
12 * @(#) pa/fp/decode_exc.c $ Revision: $
15 * <<please update with a synopsis of the functionality provided by this file>>
17 * External Interfaces:
18 * <<the following list was autogenerated, please review>>
19 * decode_fpu(Fpu_register, trap_counts)
21 * Internal Interfaces:
25 * <<please update with a overview of the operation of this file>>
30 #include <linux/kernel.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> */
40 #undef Fpustatus_register
41 #define Fpustatus_register Fpu_register[0]
43 /* General definitions */
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 fmt 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 */
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 : fmt) & twobits)
62 /* Miscellaneous definitions */
63 #define Fpu_sgl(index) Fpu_register[index*2]
65 #define Fpu_dblp1(index) Fpu_register[index*2]
66 #define Fpu_dblp2(index) Fpu_register[(index*2)+1]
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]
73 /* Single precision floating-point definitions */
75 # define Sgl_decrement(sgl_value) Sall(sgl_value)--
78 /* Double precision floating-point definitions */
80 # define Dbl_decrement(dbl_valuep1,dbl_valuep2) \
81 if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)--
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; \
91 decode_fpu(unsigned int Fpu_register
[], unsigned int trap_counts
[])
93 unsigned int current_ir
, excp
;
94 int target
, exception_index
= 1;
98 unsigned int excptype
;
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]
107 bflags
=(Fpu_register
[0] & 0xf8000000);
108 Fpu_register
[0] &= 0x07ffffff;
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.
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.
121 * At some point, we may want to report reserved op exceptions as
122 * illegal instructions.
125 if (!Is_tbit_set()) {
126 update_trap_counts(Fpu_register
, aflags
, bflags
, trap_counts
);
127 return SIGNALCODE(SIGILL
, ILL_COPROC
);
131 * Is a coprocessor op.
133 * Now we need to determine what type of exception occurred.
135 for (exception_index
=1; exception_index
<=MAX_EXCP_REG
; exception_index
++) {
136 current_ir
= Excp_instr(exception_index
);
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.
142 excptype
= Excp_type(exception_index
);
143 if (excptype
& UNIMPLEMENTEDEXCEPTION
) {
145 * Clear T-bit and exception register so that
146 * we can tell if a trap really occurs while
147 * emulating the instruction.
150 Clear_excp_register(exception_index
);
152 * Now emulate this instruction. If a trap occurs,
153 * fpudispatch will return a non-zero number
155 excp
= fpudispatch(current_ir
,excptype
,0,Fpu_register
);
156 /* accumulate the status flags, don't lose them as in hpux */
159 * We now need to make sure that the T-bit and the
160 * exception register contain the correct values
164 * Set t-bit since it might still be needed for a
165 * subsequent real trap (I don't understand fully -PB)
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
) {
174 * it is really unimplemented, so restore the
175 * TIMEX extended unimplemented exception code
178 update_trap_counts(Fpu_register
, aflags
, bflags
,
180 return SIGNALCODE(SIGILL
, ILL_COPROC
);
182 /* some of the following code uses excptype, so
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' */
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)
199 if (excptype
& UNDERFLOWEXCEPTION
) {
200 /* check for underflow trap enabled */
201 if (Is_underflowtrap_enabled()) {
202 update_trap_counts(Fpu_register
, aflags
, bflags
,
204 return SIGNALCODE(SIGFPE
, FPE_FLTUND
);
207 * Isn't a real trap; we need to
208 * return the default value.
210 target
= current_ir
& fivebits
;
212 if (Ibit(Fpu_register
[exception_index
])) inexact
= TRUE
;
213 else inexact
= FALSE
;
215 switch (Excp_format()) {
218 * If ra (round-away) is set, will
219 * want to undo the rounding done
222 if (Rabit(Fpu_register
[exception_index
]))
223 Sgl_decrement(Fpu_sgl(target
));
225 /* now denormalize */
226 sgl_denormalize(&Fpu_sgl(target
),&inexact
,Rounding_mode());
230 * If ra (round-away) is set, will
231 * want to undo the rounding done
234 if (Rabit(Fpu_register
[exception_index
]))
235 Dbl_decrement(Fpu_dblp1(target
),Fpu_dblp2(target
));
237 /* now denormalize */
238 dbl_denormalize(&Fpu_dblp1(target
),&Fpu_dblp2(target
),
239 &inexact
,Rounding_mode());
242 if (inexact
) Set_underflowflag();
244 * Underflow can generate an inexact
245 * exception. If inexact trap is enabled,
246 * want to do an inexact trap, otherwise
249 if (inexact
&& Is_inexacttrap_enabled()) {
251 * Set exception field of exception register
252 * to inexact, parm field to zero.
253 * Underflow bit should be cleared.
255 Set_exceptiontype(Fpu_register
[exception_index
],
257 Set_parmfield(Fpu_register
[exception_index
],0);
258 update_trap_counts(Fpu_register
, aflags
, bflags
,
260 return SIGNALCODE(SIGFPE
, FPE_FLTRES
);
264 * Exception register needs to be cleared.
265 * Inexact flag needs to be set if inexact.
267 Clear_excp_register(exception_index
);
268 if (inexact
) Set_inexactflag();
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
,
279 if (Is_overflowtrap_enabled()) {
280 update_trap_counts(Fpu_register
, aflags
, bflags
,
282 return SIGNALCODE(SIGFPE
, FPE_FLTOVF
);
285 * Isn't a real trap; we need to
286 * return the default value.
288 target
= current_ir
& fivebits
;
289 switch (Excp_format()) {
291 Sgl_setoverflow(Fpu_sgl(target
));
294 Dbl_setoverflow(Fpu_dblp1(target
),Fpu_dblp2(target
));
299 * Overflow always generates an inexact
300 * exception. If inexact trap is enabled,
301 * want to do an inexact trap, otherwise
304 if (Is_inexacttrap_enabled()) {
306 * Set exception field of exception
307 * register to inexact. Overflow
308 * bit should be cleared.
310 Set_exceptiontype(Fpu_register
[exception_index
],
312 update_trap_counts(Fpu_register
, aflags
, bflags
,
314 return SIGNALCODE(SIGFPE
, FPE_FLTRES
);
318 * Exception register needs to be cleared.
319 * Inexact flag needs to be set.
321 Clear_excp_register(exception_index
);
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
);
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 */
344 * Clear exception register in case
345 * other fields are non-zero.
347 Clear_excp_register(exception_index
);
352 * No real exceptions occurred.
355 update_trap_counts(Fpu_register
, aflags
, bflags
, trap_counts
);