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