1/* Simulator Floating-point support.
2
3   Copyright 1997, 1998, 2002, 2003, 2007, 2008, 2009, 2010, 2011
4   Free Software Foundation, Inc.
5
6   Contributed by Cygnus Support.
7
8This file is part of GDB, the GNU debugger.
9
10This program is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 3 of the License, or
13(at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
22
23
24
25#ifndef SIM_FPU_H
26#define SIM_FPU_H
27
28
29
30/* The FPU intermediate type - this object, passed by reference,
31   should be treated as opaque.
32
33
34   Pragmatics - pass struct by ref:
35
36   The alternatives for this object/interface that were considered
37   were: a packed 64 bit value; an unpacked structure passed by value;
38   and an unpacked structure passed by reference.
39
40   The packed 64 bit value was rejected because: it limited the
41   precision of intermediate values; reasonable performance would only
42   be achieved when the sim_fpu package was in-lined allowing repeated
43   unpacking operations to be eliminated.
44
45   For unpacked structures (passed by value and reference), the code
46   quality of GCC-2.7 (on x86) for each alternative was compared.
47   Needless to say the results, while better than for a packed 64 bit
48   object, were still poor (GCC had only limited support for the
49   optimization of references to structure members).  Regardless, the
50   struct-by-ref alternative achieved better results when compiled
51   with (better speed) and without (better code density) in-lining.
52   Here's looking forward to an improved GCC optimizer.
53
54
55   Pragmatics - avoid host FP hardware:
56
57   FP operations can be implemented by either: the host's floating
58   point hardware; or by emulating the FP operations using integer
59   only routines.  This is direct tradeoff between speed, portability
60   and correctness.
61
62   The two principal reasons for selecting portability and correctness
63   over speed are:
64
65   1 - Correctness.  The assumption that FP correctness wasn't an
66   issue for code being run on simulators was wrong.  Instead of
67   running FP tolerant (?) code, simulator users instead typically run
68   very aggressive FP code sequences.  The sole purpose of those
69   sequences being to test the target ISA's FP implementation.
70
71   2 - Portability.  The host FP implementation is not predictable.  A
72   simulator modeling aggressive FP code sequences using the hosts FPU
73   relies heavily on the correctness of the hosts FP implementation.
74   It turns out that such trust can be misplaced.  The behavior of
75   host FP implementations when handling edge conditions such as SNaNs
76   and exceptions varied widely.
77
78
79   */
80
81
82typedef enum
83{
84  sim_fpu_class_zero,
85  sim_fpu_class_snan,
86  sim_fpu_class_qnan,
87  sim_fpu_class_number,
88  sim_fpu_class_denorm,
89  sim_fpu_class_infinity,
90} sim_fpu_class;
91
92typedef struct _sim_fpu {
93  sim_fpu_class class;
94  int sign;
95  unsigned64 fraction;
96  int normal_exp;
97} sim_fpu;
98
99
100
101/* Rounding options.
102
103   The value zero (sim_fpu_round_default) for ALU operations indicates
104   that, when possible, rounding should be avoided. */
105
106typedef enum
107{
108  sim_fpu_round_default = 0,
109  sim_fpu_round_near = 1,
110  sim_fpu_round_zero = 2,
111  sim_fpu_round_up = 3,
112  sim_fpu_round_down = 4,
113} sim_fpu_round;
114
115
116/* Options when handling denormalized numbers.  */
117
118typedef enum
119{
120  sim_fpu_denorm_default = 0,
121  sim_fpu_denorm_underflow_inexact = 1,
122  sim_fpu_denorm_zero = 2,
123} sim_fpu_denorm;
124
125
126
127/* Status values returned by FPU operators.
128
129   When checking the result of an FP sequence (ex 32to, add, single,
130   to32) the caller may either: check the return value of each FP
131   operator; or form the union (OR) of the returned values and examine
132   them once at the end.
133
134   FIXME: This facility is still being developed.  The choice of
135   status values returned and their exact meaning may changed in the
136   future.  */
137
138typedef enum
139{
140  sim_fpu_status_invalid_snan = 1,
141  sim_fpu_status_invalid_qnan = 2,
142  sim_fpu_status_invalid_isi = 4, /* (inf - inf) */
143  sim_fpu_status_invalid_idi = 8, /* (inf / inf) */
144  sim_fpu_status_invalid_zdz = 16, /* (0 / 0) */
145  sim_fpu_status_invalid_imz = 32, /* (inf * 0) */
146  sim_fpu_status_invalid_cvi = 64, /* convert to integer */
147  sim_fpu_status_invalid_div0 = 128, /* (X / 0) */
148  sim_fpu_status_invalid_cmp = 256, /* compare */
149  sim_fpu_status_invalid_sqrt = 512,
150  sim_fpu_status_rounded = 1024,
151  sim_fpu_status_inexact = 2048,
152  sim_fpu_status_overflow = 4096,
153  sim_fpu_status_underflow = 8192,
154  sim_fpu_status_denorm = 16384,
155} sim_fpu_status;
156
157
158
159
160/* Directly map between a 32/64 bit register and the sim_fpu internal
161   type.
162
163   When converting from the 32/64 bit packed format to the sim_fpu
164   internal type, the operation is exact.
165
166   When converting from the sim_fpu internal type to 32/64 bit packed
167   format, the operation may result in a loss of precision. The
168   configuration macro WITH_FPU_CONVERSION controls this.  By default,
169   silent round to nearest is performed.  Alternatively, round up,
170   round down and round to zero can be performed.  In a simulator
171   emulating exact FPU behavior, sim_fpu_round_{32,64} should be
172   called before packing the sim_fpu value.  */
173
174INLINE_SIM_FPU (void) sim_fpu_32to (sim_fpu *f, unsigned32 s);
175INLINE_SIM_FPU (void) sim_fpu_232to (sim_fpu *f, unsigned32 h, unsigned32 l);
176INLINE_SIM_FPU (void) sim_fpu_64to (sim_fpu *f, unsigned64 d);
177
178INLINE_SIM_FPU (void) sim_fpu_to32 (unsigned32 *s, const sim_fpu *f);
179INLINE_SIM_FPU (void) sim_fpu_to232 (unsigned32 *h, unsigned32 *l, const sim_fpu *f);
180INLINE_SIM_FPU (void) sim_fpu_to64 (unsigned64 *d, const sim_fpu *f);
181
182
183/* Create a sim_fpu struct using raw information.  (FRACTION & LSMASK
184   (PRECISION-1, 0)) is assumed to contain the fraction part of the
185   floating-point number.  The leading bit LSBIT (PRECISION) is always
186   implied.  The number created can be represented by:
187
188   (SIGN ? "-" : "+") "1." FRACTION{PRECISION-1,0} X 2 ^ NORMAL_EXP>
189
190   You can not specify zero using this function. */
191
192INLINE_SIM_FPU (void) sim_fpu_fractionto (sim_fpu *f, int sign, int normal_exp, unsigned64 fraction, int precision);
193
194/* Reverse operation.  If S is a non-zero number, discards the implied
195   leading one and returns PRECISION fraction bits.  No rounding is
196   performed. */
197INLINE_SIM_FPU (unsigned64) sim_fpu_tofraction (const sim_fpu *s, int precision);
198
199
200
201/* Rounding operators.
202
203   Force an intermediate result to an exact 32/64 bit
204   representation. */
205
206INLINE_SIM_FPU (int) sim_fpu_round_32 (sim_fpu *f,
207				       sim_fpu_round round,
208				       sim_fpu_denorm denorm);
209INLINE_SIM_FPU (int) sim_fpu_round_64 (sim_fpu *f,
210				       sim_fpu_round round,
211				       sim_fpu_denorm denorm);
212
213
214
215/* Arithmetic operators.
216
217   FIXME: In the future, additional arguments ROUNDING and BITSIZE may
218   be added. */
219
220typedef int (sim_fpu_op1) (sim_fpu *f,
221			   const sim_fpu *l);
222typedef int (sim_fpu_op2) (sim_fpu *f,
223			   const sim_fpu *l,
224			   const sim_fpu *r);
225
226INLINE_SIM_FPU (int) sim_fpu_add (sim_fpu *f,
227				  const sim_fpu *l, const sim_fpu *r);
228INLINE_SIM_FPU (int) sim_fpu_sub (sim_fpu *f,
229				  const sim_fpu *l, const sim_fpu *r);
230INLINE_SIM_FPU (int) sim_fpu_mul (sim_fpu *f,
231				  const sim_fpu *l, const sim_fpu *r);
232INLINE_SIM_FPU (int) sim_fpu_div (sim_fpu *f,
233				  const sim_fpu *l, const sim_fpu *r);
234INLINE_SIM_FPU (int) sim_fpu_max (sim_fpu *f,
235				  const sim_fpu *l, const sim_fpu *r);
236INLINE_SIM_FPU (int) sim_fpu_min (sim_fpu *f,
237				  const sim_fpu *l, const sim_fpu *r);
238INLINE_SIM_FPU (int) sim_fpu_neg (sim_fpu *f,
239				  const sim_fpu *a);
240INLINE_SIM_FPU (int) sim_fpu_abs (sim_fpu *f,
241				  const sim_fpu *a);
242INLINE_SIM_FPU (int) sim_fpu_inv (sim_fpu *f,
243				  const sim_fpu *a);
244INLINE_SIM_FPU (int) sim_fpu_sqrt (sim_fpu *f,
245				   const sim_fpu *sqr);
246
247
248
249/* Conversion of integer <-> floating point. */
250
251INLINE_SIM_FPU (int) sim_fpu_i32to (sim_fpu *f, signed32 i,
252				    sim_fpu_round round);
253INLINE_SIM_FPU (int) sim_fpu_u32to (sim_fpu *f, unsigned32 u,
254				    sim_fpu_round round);
255INLINE_SIM_FPU (int) sim_fpu_i64to (sim_fpu *f, signed64 i,
256				    sim_fpu_round round);
257INLINE_SIM_FPU (int) sim_fpu_u64to (sim_fpu *f, unsigned64 u,
258				    sim_fpu_round round);
259#if 0
260INLINE_SIM_FPU (int) sim_fpu_i232to (sim_fpu *f, signed32 h, signed32 l,
261				     sim_fpu_round round);
262#endif
263#if 0
264INLINE_SIM_FPU (int) sim_fpu_u232to (sim_fpu *f, unsigned32 h, unsigned32 l,
265				     sim_fpu_round round);
266#endif
267
268INLINE_SIM_FPU (int) sim_fpu_to32i (signed32 *i, const sim_fpu *f,
269				    sim_fpu_round round);
270INLINE_SIM_FPU (int) sim_fpu_to32u (unsigned32 *u, const sim_fpu *f,
271				    sim_fpu_round round);
272INLINE_SIM_FPU (int) sim_fpu_to64i (signed64 *i, const sim_fpu *f,
273				    sim_fpu_round round);
274INLINE_SIM_FPU (int) sim_fpu_to64u (unsigned64 *u, const sim_fpu *f,
275				    sim_fpu_round round);
276#if 0
277INLINE_SIM_FPU (int) sim_fpu_to232i (signed64 *h, signed64 *l, const sim_fpu *f,
278				     sim_fpu_round round);
279#endif
280#if 0
281INLINE_SIM_FPU (int) sim_fpu_to232u (unsigned64 *h, unsigned64 *l, const sim_fpu *f,
282				     sim_fpu_round round);
283#endif
284
285
286/* Conversion of internal sim_fpu type to host double format.
287
288   For debugging/tracing only.  A SNaN is never returned. */
289
290/* INLINE_SIM_FPU (float) sim_fpu_2f (const sim_fpu *f); */
291INLINE_SIM_FPU (double) sim_fpu_2d (const sim_fpu *d);
292
293/* INLINE_SIM_FPU (void) sim_fpu_f2 (sim_fpu *f, float s); */
294INLINE_SIM_FPU (void) sim_fpu_d2 (sim_fpu *f, double d);
295
296
297
298/* Specific number classes.
299
300   NB: When either, a 32/64 bit floating points is converted to
301   internal format, or an internal format number is rounded to 32/64
302   bit precision, a special marker is retained that indicates that the
303   value was normalized.  For such numbers both is_number and
304   is_denorm return true. */
305
306INLINE_SIM_FPU (int) sim_fpu_is_nan (const sim_fpu *s); /* 1 => SNaN or QNaN */
307INLINE_SIM_FPU (int) sim_fpu_is_snan (const sim_fpu *s); /* 1 => SNaN */
308INLINE_SIM_FPU (int) sim_fpu_is_qnan (const sim_fpu *s); /* 1 => QNaN */
309
310INLINE_SIM_FPU (int) sim_fpu_is_zero (const sim_fpu *s);
311INLINE_SIM_FPU (int) sim_fpu_is_infinity (const sim_fpu *s);
312INLINE_SIM_FPU (int) sim_fpu_is_number (const sim_fpu *s); /* !zero */
313INLINE_SIM_FPU (int) sim_fpu_is_denorm (const sim_fpu *s); /* !zero */
314
315
316
317/* Floating point fields */
318
319INLINE_SIM_FPU (int) sim_fpu_sign (const sim_fpu *s);
320INLINE_SIM_FPU (int) sim_fpu_exp (const sim_fpu *s);
321INLINE_SIM_FPU (unsigned64) sim_fpu_fraction (const sim_fpu *s);
322INLINE_SIM_FPU (unsigned64) sim_fpu_guard (const sim_fpu *s, int is_double);
323
324
325
326/* Specific comparison operators
327
328   For NaNs et al., the comparison operators will set IS to zero and
329   return a nonzero result. */
330
331INLINE_SIM_FPU (int) sim_fpu_lt (int *is, const sim_fpu *l, const sim_fpu *r);
332INLINE_SIM_FPU (int) sim_fpu_le (int *is, const sim_fpu *l, const sim_fpu *r);
333INLINE_SIM_FPU (int) sim_fpu_eq (int *is, const sim_fpu *l, const sim_fpu *r);
334INLINE_SIM_FPU (int) sim_fpu_ne (int *is, const sim_fpu *l, const sim_fpu *r);
335INLINE_SIM_FPU (int) sim_fpu_ge (int *is, const sim_fpu *l, const sim_fpu *r);
336INLINE_SIM_FPU (int) sim_fpu_gt (int *is, const sim_fpu *l, const sim_fpu *r);
337
338INLINE_SIM_FPU (int) sim_fpu_is_lt (const sim_fpu *l, const sim_fpu *r);
339INLINE_SIM_FPU (int) sim_fpu_is_le (const sim_fpu *l, const sim_fpu *r);
340INLINE_SIM_FPU (int) sim_fpu_is_eq (const sim_fpu *l, const sim_fpu *r);
341INLINE_SIM_FPU (int) sim_fpu_is_ne (const sim_fpu *l, const sim_fpu *r);
342INLINE_SIM_FPU (int) sim_fpu_is_ge (const sim_fpu *l, const sim_fpu *r);
343INLINE_SIM_FPU (int) sim_fpu_is_gt (const sim_fpu *l, const sim_fpu *r);
344
345
346
347/* General number class and comparison operators.
348
349   The result of the comparison is indicated by returning one of the
350   values below.  Efficient emulation of a target FP compare
351   instruction can be achieved by redefining the values below to match
352   corresponding target FP status bits.
353
354   For instance.  SIM_FPU_QNAN may be redefined to be the bit
355   `INVALID' while SIM_FPU_NINF might be redefined as the bits
356   `NEGATIVE | INFINITY | VALID'. */
357
358#ifndef SIM_FPU_IS_SNAN
359enum {
360  SIM_FPU_IS_SNAN = 1, /* Noisy not-a-number */
361  SIM_FPU_IS_QNAN = 2, /* Quiet not-a-number */
362  SIM_FPU_IS_NINF = 3, /* -infinity */
363  SIM_FPU_IS_PINF = 4, /* +infinity */
364  SIM_FPU_IS_NNUMBER = 5, /* -number - [ -MAX .. -MIN ] */
365  SIM_FPU_IS_PNUMBER = 6, /* +number - [ +MIN .. +MAX ] */
366  SIM_FPU_IS_NDENORM = 7, /* -denorm - ( MIN .. 0 ) */
367  SIM_FPU_IS_PDENORM = 8, /* +denorm - ( 0 .. MIN ) */
368  SIM_FPU_IS_NZERO = 9, /* -0 */
369  SIM_FPU_IS_PZERO = 10, /* +0 */
370};
371#endif
372
373INLINE_SIM_FPU (int) sim_fpu_is (const sim_fpu *l);
374INLINE_SIM_FPU (int) sim_fpu_cmp (const sim_fpu *l, const sim_fpu *r);
375
376
377
378/* A number of useful constants.  */
379
380extern const sim_fpu sim_fpu_zero;
381extern const sim_fpu sim_fpu_one;
382extern const sim_fpu sim_fpu_two;
383extern const sim_fpu sim_fpu_qnan;
384extern const sim_fpu sim_fpu_max32;
385extern const sim_fpu sim_fpu_max64;
386
387
388/* Select the applicable functions for the fp_word type */
389
390#if WITH_TARGET_FLOATING_POINT_BITSIZE == 32
391#define sim_fpu_tofp sim_fpu_to32
392#define sim_fpu_fpto sim_fpu_32to
393#define sim_fpu_round_fp sim_fpu_round_32
394#define sim_fpu_maxfp sim_fpu_max32
395#endif
396#if WITH_TARGET_FLOATING_POINT_BITSIZE == 64
397#define sim_fpu_tofp sim_fpu_to64
398#define sim_fpu_fpto sim_fpu_64to
399#define sim_fpu_round_fp sim_fpu_round_64
400#define sim_fpu_maxfp sim_fpu_max64
401#endif
402
403
404
405/* For debugging */
406
407typedef void sim_fpu_print_func (void *, const char *, ...);
408
409/* Print a sim_fpu with full precision.  */
410INLINE_SIM_FPU (void) sim_fpu_print_fpu (const sim_fpu *f,
411					 sim_fpu_print_func *print,
412					 void *arg);
413
414/* Print a sim_fpu with `n' trailing digits.  */
415INLINE_SIM_FPU (void) sim_fpu_printn_fpu (const sim_fpu *f,
416					  sim_fpu_print_func *print,
417					  int digits,
418					  void *arg);
419
420INLINE_SIM_FPU (void) sim_fpu_print_status (int status,
421					    sim_fpu_print_func *print,
422					    void *arg);
423
424#if H_REVEALS_MODULE_P (SIM_FPU_INLINE)
425#include "sim-fpu.c"
426#endif
427
428#endif
429