1-- --------------------------------------------------------------------
2-- "float_pkg" package contains functions for floating point math.
3-- Please see the documentation for the floating point package.
4-- This package should be compiled into "ieee_proposed" and used as follows:
5-- use ieee.std_logic_1164.all;
6-- use ieee.numeric_std.all;
7-- use ieee_proposed.fixed_float_types.all;
8-- use ieee_proposed.fixed_pkg.all;
9-- use ieee_proposed.float_pkg.all;
10--
11--  This verison is designed to work with the VHDL-93 compilers.  Please
12--  note the "%%%" comments.  These are where we diverge from the
13--  VHDL-200X LRM.
14--
15-- --------------------------------------------------------------------
16-- Version    : $Revision: 1.1 $
17-- Date       : $Date: 2012/03/09 20:36:50 $
18-- --------------------------------------------------------------------
19
20use STD.TEXTIO.all;
21library IEEE;
22use IEEE.STD_LOGIC_1164.all;
23use IEEE.NUMERIC_STD.all;
24use work.fixed_float_types.all;
25use work.fixed_pkg.all;
26--use ieee.fixed_pkg.all;
27
28package float_pkg is
29-- generic (
30  -- Defaults for sizing routines, when you do a "to_float" this will be
31  -- the default size.  Example float32 would be 8 and 23 (8 downto -23)
32  constant float_exponent_width : NATURAL    := 8;
33  constant float_fraction_width : NATURAL    := 23;
34  -- Rounding algorithm, "round_nearest" is default, other valid values
35  -- are "round_zero" (truncation), "round_inf" (round up), and
36  -- "round_neginf" (round down)
37  constant float_round_style    : round_type := round_nearest;
38  -- Denormal numbers (very small numbers near zero) true or false
39  constant float_denormalize    : BOOLEAN    := true;
40  -- Turns on NAN processing (invalid numbers and overflow) true of false
41  constant float_check_error    : BOOLEAN    := true;
42  -- Guard bits are added to the bottom of every operation for rounding.
43  -- any natural number (including 0) are valid.
44  constant float_guard_bits     : NATURAL    := 3;
45  -- If TRUE, then turn off warnings on "X" propagation
46  constant no_warning : BOOLEAN := (false
47                                                 );
48
49  -- Author David Bishop (dbishop@vhdl.org)
50
51  -- Note that the size of the vector is not defined here, but in
52  -- the package which calls this one.
53  type UNRESOLVED_float is array (INTEGER range <>) of STD_ULOGIC;  -- main type
54  subtype U_float is UNRESOLVED_float;
55
56  subtype float is UNRESOLVED_float;
57  -----------------------------------------------------------------------------
58  -- Use the float type to define your own floating point numbers.
59  -- There must be a negative index or the packages will error out.
60  -- Minimum supported is "subtype float7 is float (3 downto -3);"
61  -- "subtype float16 is float (6 downto -9);" is probably the smallest
62  -- practical one to use.
63  -----------------------------------------------------------------------------
64
65  -- IEEE 754 single precision
66  subtype UNRESOLVED_float32 is UNRESOLVED_float (8 downto -23);
67  alias U_float32 is UNRESOLVED_float32;
68  subtype float32 is float (8 downto -23);
69  -----------------------------------------------------------------------------
70  -- IEEE-754 single precision floating point.  This is a "float"
71  -- in C, and a FLOAT in Fortran.  The exponent is 8 bits wide, and
72  -- the fraction is 23 bits wide.  This format can hold roughly 7 decimal
73  -- digits.  Infinity is 2**127 = 1.7E38 in this number system.
74  -- The bit representation is as follows:
75  -- 1 09876543 21098765432109876543210
76  -- 8 76543210 12345678901234567890123
77  -- 0 00000000 00000000000000000000000
78  -- 8 7      0 -1                  -23
79  -- +/-   exp.  fraction
80  -----------------------------------------------------------------------------
81
82  -- IEEE 754 double precision
83  subtype UNRESOLVED_float64 is UNRESOLVED_float (11 downto -52);
84  alias U_float64 is UNRESOLVED_float64;
85  subtype float64 is float (11 downto -52);
86  -----------------------------------------------------------------------------
87  -- IEEE-754 double precision floating point.  This is a "double float"
88  -- in C, and a FLOAT*8 in Fortran.  The exponent is 11 bits wide, and
89  -- the fraction is 52 bits wide.  This format can hold roughly 15 decimal
90  -- digits.  Infinity is 2**2047 in this number system.
91  -- The bit representation is as follows:
92  --  3 21098765432 1098765432109876543210987654321098765432109876543210
93  --  1 09876543210 1234567890123456789012345678901234567890123456789012
94  --  S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
95  -- 11 10        0 -1                                               -52
96  -- +/-  exponent    fraction
97  -----------------------------------------------------------------------------
98
99  -- IEEE 854 & C extended precision
100  subtype UNRESOLVED_float128 is UNRESOLVED_float (15 downto -112);
101  alias U_float128 is UNRESOLVED_float128;
102  subtype float128 is float (15 downto -112);
103  -----------------------------------------------------------------------------
104  -- The 128 bit floating point number is "long double" in C (on
105  -- some systems this is a 70 bit floating point number) and FLOAT*32
106  -- in Fortran.  The exponent is 15 bits wide and the fraction is 112
107  -- bits wide. This number can handle approximately 33 decimal digits.
108  -- Infinity is 2**32,767 in this number system.
109  -----------------------------------------------------------------------------
110
111  -- purpose: Checks for a valid floating point number
112  type valid_fpstate is (nan,           -- Signaling NaN (C FP_NAN)
113                         quiet_nan,     -- Quiet NaN (C FP_NAN)
114                         neg_inf,       -- Negative infinity (C FP_INFINITE)
115                         neg_normal,    -- negative normalized nonzero
116                         neg_denormal,  -- negative denormalized (FP_SUBNORMAL)
117                         neg_zero,      -- -0 (C FP_ZERO)
118                         pos_zero,      -- +0 (C FP_ZERO)
119                         pos_denormal,  -- Positive denormalized (FP_SUBNORMAL)
120                         pos_normal,    -- positive normalized nonzero
121                         pos_inf,       -- positive infinity
122                         isx);          -- at least one input is unknown
123
124  -- This deferred constant will tell you if the package body is synthesizable
125  -- or implemented as real numbers.
126  constant fphdlsynth_or_real : BOOLEAN;  -- deferred constant
127
128  -- Returns the class which X falls into
129  function Classfp (
130    x           : UNRESOLVED_float;              -- floating point input
131    check_error : BOOLEAN := float_check_error)  -- check for errors
132    return valid_fpstate;
133
134  -- Arithmetic functions, these operators do not require parameters.
135  function "abs" (arg : UNRESOLVED_float) return UNRESOLVED_float;
136  function "-" (arg   : UNRESOLVED_float) return UNRESOLVED_float;
137
138  -- These allows the base math functions to use the default values
139  -- of their parameters.  Thus they do full IEEE floating point.
140
141  function "+" (l, r   : UNRESOLVED_float) return UNRESOLVED_float;
142  function "-" (l, r   : UNRESOLVED_float) return UNRESOLVED_float;
143  function "*" (l, r   : UNRESOLVED_float) return UNRESOLVED_float;
144  function "/" (l, r   : UNRESOLVED_float) return UNRESOLVED_float;
145  function "rem" (l, r : UNRESOLVED_float) return UNRESOLVED_float;
146  function "mod" (l, r : UNRESOLVED_float) return UNRESOLVED_float;
147
148  -- Basic parameter list
149  -- round_style - Selects the rounding algorithm to use
150  -- guard - extra bits added to the end if the operation to add precision
151  -- check_error - When "false" turns off NAN and overflow checks
152  -- denormalize - When "false" turns off denormal number processing
153
154  function add (
155    l, r                 : UNRESOLVED_float;  -- floating point input
156    constant round_style : round_type := float_round_style;  -- rounding option
157    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
158    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
159    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
160    return UNRESOLVED_float;
161
162  function subtract (
163    l, r                 : UNRESOLVED_float;  -- floating point input
164    constant round_style : round_type := float_round_style;  -- rounding option
165    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
166    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
167    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
168    return UNRESOLVED_float;
169
170  function multiply (
171    l, r                 : UNRESOLVED_float;  -- floating point input
172    constant round_style : round_type := float_round_style;  -- rounding option
173    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
174    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
175    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
176    return UNRESOLVED_float;
177
178  function divide (
179    l, r                 : UNRESOLVED_float;  -- floating point input
180    constant round_style : round_type := float_round_style;  -- rounding option
181    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
182    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
183    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
184    return UNRESOLVED_float;
185
186  function remainder (
187    l, r                 : UNRESOLVED_float;  -- floating point input
188    constant round_style : round_type := float_round_style;  -- rounding option
189    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
190    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
191    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
192    return UNRESOLVED_float;
193
194  function modulo (
195    l, r                 : UNRESOLVED_float;  -- floating point input
196    constant round_style : round_type := float_round_style;  -- rounding option
197    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
198    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
199    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
200    return UNRESOLVED_float;
201
202  -- reciprocal
203  function reciprocal (
204    arg                  : UNRESOLVED_float;  -- floating point input
205    constant round_style : round_type := float_round_style;  -- rounding option
206    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
207    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
208    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
209    return UNRESOLVED_float;
210
211  function dividebyp2 (
212    l, r                 : UNRESOLVED_float;  -- floating point input
213    constant round_style : round_type := float_round_style;  -- rounding option
214    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
215    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
216    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
217    return UNRESOLVED_float;
218
219  -- Multiply accumulate  result = l*r + c
220  function mac (
221    l, r, c              : UNRESOLVED_float;  -- floating point input
222    constant round_style : round_type := float_round_style;  -- rounding option
223    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
224    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
225    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
226    return UNRESOLVED_float;
227
228  -- Square root (all 754 based implementations need this)
229  function sqrt (
230    arg                  : UNRESOLVED_float;  -- floating point input
231    constant round_style : round_type := float_round_style;
232    constant guard       : NATURAL    := float_guard_bits;
233    constant check_error : BOOLEAN    := float_check_error;
234    constant denormalize : BOOLEAN    := float_denormalize)
235    return UNRESOLVED_float;
236
237  function Is_Negative (arg : UNRESOLVED_float) return BOOLEAN;
238
239  -----------------------------------------------------------------------------
240  -- compare functions
241  -- =, /=, >=, <=, <, >, maximum, minimum
242
243  function eq (                               -- equal =
244    l, r                 : UNRESOLVED_float;  -- floating point input
245    constant check_error : BOOLEAN := float_check_error;
246    constant denormalize : BOOLEAN := float_denormalize)
247    return BOOLEAN;
248
249  function ne (                               -- not equal /=
250    l, r                 : UNRESOLVED_float;  -- floating point input
251    constant check_error : BOOLEAN := float_check_error;
252    constant denormalize : BOOLEAN := float_denormalize)
253    return BOOLEAN;
254
255  function lt (                               -- less than <
256    l, r                 : UNRESOLVED_float;  -- floating point input
257    constant check_error : BOOLEAN := float_check_error;
258    constant denormalize : BOOLEAN := float_denormalize)
259    return BOOLEAN;
260
261  function gt (                               -- greater than >
262    l, r                 : UNRESOLVED_float;  -- floating point input
263    constant check_error : BOOLEAN := float_check_error;
264    constant denormalize : BOOLEAN := float_denormalize)
265    return BOOLEAN;
266
267  function le (                               -- less than or equal to <=
268    l, r                 : UNRESOLVED_float;  -- floating point input
269    constant check_error : BOOLEAN := float_check_error;
270    constant denormalize : BOOLEAN := float_denormalize)
271    return BOOLEAN;
272
273  function ge (                               -- greater than or equal to >=
274    l, r                 : UNRESOLVED_float;  -- floating point input
275    constant check_error : BOOLEAN := float_check_error;
276    constant denormalize : BOOLEAN := float_denormalize)
277    return BOOLEAN;
278
279  -- Need to overload the default versions of these
280  function "="  (l, r : UNRESOLVED_float) return BOOLEAN;
281  function "/=" (l, r : UNRESOLVED_float) return BOOLEAN;
282  function ">=" (l, r : UNRESOLVED_float) return BOOLEAN;
283  function "<=" (l, r : UNRESOLVED_float) return BOOLEAN;
284  function ">"  (l, r : UNRESOLVED_float) return BOOLEAN;
285  function "<"  (l, r : UNRESOLVED_float) return BOOLEAN;
286
287  function \?=\  (l, r : UNRESOLVED_float) return STD_ULOGIC;
288  function \?/=\ (l, r : UNRESOLVED_float) return STD_ULOGIC;
289  function \?>\  (l, r : UNRESOLVED_float) return STD_ULOGIC;
290  function \?>=\ (l, r : UNRESOLVED_float) return STD_ULOGIC;
291  function \?<\  (l, r : UNRESOLVED_float) return STD_ULOGIC;
292  function \?<=\ (l, r : UNRESOLVED_float) return STD_ULOGIC;
293
294  function std_match (l, r     : UNRESOLVED_float) return BOOLEAN;
295  function find_rightmost (arg : UNRESOLVED_float; y : STD_ULOGIC)
296    return INTEGER;
297  function find_leftmost (arg : UNRESOLVED_float; y : STD_ULOGIC)
298    return INTEGER;
299  function maximum (l, r : UNRESOLVED_float) return UNRESOLVED_float;
300  function minimum (l, r : UNRESOLVED_float) return UNRESOLVED_float;
301
302  -- conversion functions
303  -- Converts one floating point number into another.
304
305  function resize (
306    arg                     : UNRESOLVED_float;  -- Floating point input
307    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
308    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
309    constant round_style    : round_type := float_round_style;  -- rounding option
310    constant check_error    : BOOLEAN    := float_check_error;
311    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
312    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
313    return UNRESOLVED_float;
314
315  function resize (
316    arg                     : UNRESOLVED_float;  -- Floating point input
317    size_res                : UNRESOLVED_float;
318    constant round_style    : round_type := float_round_style;  -- rounding option
319    constant check_error    : BOOLEAN    := float_check_error;
320    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
321    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
322    return UNRESOLVED_float;
323
324  function to_float32 (
325    arg                     : UNRESOLVED_float;
326    constant round_style    : round_type := float_round_style;  -- rounding option
327    constant check_error    : BOOLEAN    := float_check_error;
328    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
329    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
330    return UNRESOLVED_float32;
331
332  function to_float64 (
333    arg                     : UNRESOLVED_float;
334    constant round_style    : round_type := float_round_style;  -- rounding option
335    constant check_error    : BOOLEAN    := float_check_error;
336    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
337    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
338    return UNRESOLVED_float64;
339
340  function to_float128 (
341    arg                     : UNRESOLVED_float;
342    constant round_style    : round_type := float_round_style;  -- rounding option
343    constant check_error    : BOOLEAN    := float_check_error;
344    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
345    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
346    return UNRESOLVED_float128;
347
348  -- Converts an fp into an SLV (needed for synthesis)
349  function to_slv (arg : UNRESOLVED_float) return STD_LOGIC_VECTOR;
350  alias to_StdLogicVector is to_slv [UNRESOLVED_float return STD_LOGIC_VECTOR];
351  alias to_Std_Logic_Vector is to_slv [UNRESOLVED_float return STD_LOGIC_VECTOR];
352
353  -- Converts an fp into an std_ulogic_vector (sulv)
354  function to_sulv (arg : UNRESOLVED_float) return STD_ULOGIC_VECTOR;
355  alias to_StdULogicVector is to_sulv [UNRESOLVED_float return STD_ULOGIC_VECTOR];
356  alias to_Std_ULogic_Vector is to_sulv [UNRESOLVED_float return STD_ULOGIC_VECTOR];
357
358  -- std_ulogic_vector to float
359  function to_float (
360    arg                     : STD_ULOGIC_VECTOR;
361    constant exponent_width : NATURAL := float_exponent_width;  -- length of FP output exponent
362    constant fraction_width : NATURAL := float_fraction_width)  -- length of FP output fraction
363    return UNRESOLVED_float;
364
365  -- Integer to float
366  function to_float (
367    arg                     : INTEGER;
368    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
369    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
370    constant round_style    : round_type := float_round_style)  -- rounding option
371    return UNRESOLVED_float;
372
373  -- real to float
374  function to_float (
375    arg                     : REAL;
376    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
377    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
378    constant round_style    : round_type := float_round_style;  -- rounding option
379    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
380    return UNRESOLVED_float;
381
382  -- unsigned to float
383  function to_float (
384    arg                     : UNSIGNED;
385    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
386    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
387    constant round_style    : round_type := float_round_style)  -- rounding option
388    return UNRESOLVED_float;
389
390  -- signed to float
391  function to_float (
392    arg                     : SIGNED;
393    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
394    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
395    constant round_style    : round_type := float_round_style)  -- rounding option
396    return UNRESOLVED_float;
397
398  -- unsigned fixed point to float
399  function to_float (
400    arg                     : UNRESOLVED_ufixed;  -- unsigned fixed point input
401    constant exponent_width : NATURAL    := float_exponent_width;  -- width of exponent
402    constant fraction_width : NATURAL    := float_fraction_width;  -- width of fraction
403    constant round_style    : round_type := float_round_style;  -- rounding
404    constant denormalize    : BOOLEAN    := float_denormalize)  -- use ieee extensions
405    return UNRESOLVED_float;
406
407  -- signed fixed point to float
408  function to_float (
409    arg                     : UNRESOLVED_sfixed;
410    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
411    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
412    constant round_style    : round_type := float_round_style;  -- rounding
413    constant denormalize    : BOOLEAN    := float_denormalize)  -- rounding option
414    return UNRESOLVED_float;
415
416  -- size_res functions
417  -- Integer to float
418  function to_float (
419    arg                  : INTEGER;
420    size_res             : UNRESOLVED_float;
421    constant round_style : round_type := float_round_style)  -- rounding option
422    return UNRESOLVED_float;
423
424  -- real to float
425  function to_float (
426    arg                  : REAL;
427    size_res             : UNRESOLVED_float;
428    constant round_style : round_type := float_round_style;  -- rounding option
429    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
430    return UNRESOLVED_float;
431
432  -- unsigned to float
433  function to_float (
434    arg                  : UNSIGNED;
435    size_res             : UNRESOLVED_float;
436    constant round_style : round_type := float_round_style)  -- rounding option
437    return UNRESOLVED_float;
438
439  -- signed to float
440  function to_float (
441    arg                  : SIGNED;
442    size_res             : UNRESOLVED_float;
443    constant round_style : round_type := float_round_style)  -- rounding option
444    return UNRESOLVED_float;
445
446  -- sulv to float
447  function to_float (
448    arg      : STD_ULOGIC_VECTOR;
449    size_res : UNRESOLVED_float)
450    return UNRESOLVED_float;
451
452  -- unsigned fixed point to float
453  function to_float (
454    arg                  : UNRESOLVED_ufixed;  -- unsigned fixed point input
455    size_res             : UNRESOLVED_float;
456    constant round_style : round_type := float_round_style;  -- rounding
457    constant denormalize : BOOLEAN    := float_denormalize)  -- use ieee extensions
458    return UNRESOLVED_float;
459
460  -- signed fixed point to float
461  function to_float (
462    arg                  : UNRESOLVED_sfixed;
463    size_res             : UNRESOLVED_float;
464    constant round_style : round_type := float_round_style;  -- rounding
465    constant denormalize : BOOLEAN    := float_denormalize)  -- rounding option
466    return UNRESOLVED_float;
467
468  -- float to unsigned
469  function to_unsigned (
470    arg                  : UNRESOLVED_float;  -- floating point input
471    constant size        : NATURAL;     -- length of output
472    constant round_style : round_type := float_round_style;  -- rounding option
473    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
474    return UNSIGNED;
475
476  -- float to signed
477  function to_signed (
478    arg                  : UNRESOLVED_float;  -- floating point input
479    constant size        : NATURAL;     -- length of output
480    constant round_style : round_type := float_round_style;  -- rounding option
481    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
482    return SIGNED;
483
484  -- purpose: Converts a float to unsigned fixed point
485  function to_ufixed (
486    arg                     : UNRESOLVED_float;  -- fp input
487    constant left_index     : INTEGER;  -- integer part
488    constant right_index    : INTEGER;  -- fraction part
489    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;  -- saturate
490    constant round_style    : fixed_round_style_type    := fixed_round_style;  -- rounding
491    constant check_error    : BOOLEAN                   := float_check_error;  -- check for errors
492    constant denormalize    : BOOLEAN                   := float_denormalize)
493    return UNRESOLVED_ufixed;
494
495  -- float to signed fixed point
496  function to_sfixed (
497    arg                     : UNRESOLVED_float;  -- fp input
498    constant left_index     : INTEGER;  -- integer part
499    constant right_index    : INTEGER;  -- fraction part
500    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;  -- saturate
501    constant round_style    : fixed_round_style_type    := fixed_round_style;  -- rounding
502    constant check_error    : BOOLEAN                   := float_check_error;  -- check for errors
503    constant denormalize    : BOOLEAN                   := float_denormalize)
504    return UNRESOLVED_sfixed;
505
506  -- size_res versions
507  -- float to unsigned
508  function to_unsigned (
509    arg                  : UNRESOLVED_float;  -- floating point input
510    size_res             : UNSIGNED;
511    constant round_style : round_type := float_round_style;  -- rounding option
512    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
513    return UNSIGNED;
514
515  -- float to signed
516  function to_signed (
517    arg                  : UNRESOLVED_float;  -- floating point input
518    size_res             : SIGNED;
519    constant round_style : round_type := float_round_style;  -- rounding option
520    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
521    return SIGNED;
522
523  -- purpose: Converts a float to unsigned fixed point
524  function to_ufixed (
525    arg                     : UNRESOLVED_float;  -- fp input
526    size_res                : UNRESOLVED_ufixed;
527    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;  -- saturate
528    constant round_style    : fixed_round_style_type    := fixed_round_style;  -- rounding
529    constant check_error    : BOOLEAN                   := float_check_error;  -- check for errors
530    constant denormalize    : BOOLEAN                   := float_denormalize)
531    return UNRESOLVED_ufixed;
532
533  -- float to signed fixed point
534  function to_sfixed (
535    arg                     : UNRESOLVED_float;  -- fp input
536    size_res                : UNRESOLVED_sfixed;
537    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;  -- saturate
538    constant round_style    : fixed_round_style_type    := fixed_round_style;  -- rounding
539    constant check_error    : BOOLEAN                   := float_check_error;  -- check for errors
540    constant denormalize    : BOOLEAN                   := float_denormalize)
541    return UNRESOLVED_sfixed;
542
543  -- float to real
544  function to_real (
545    arg                  : UNRESOLVED_float;  -- floating point input
546    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
547    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
548    return REAL;
549
550  -- float to integer
551  function to_integer (
552    arg                  : UNRESOLVED_float;  -- floating point input
553    constant round_style : round_type := float_round_style;  -- rounding option
554    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
555    return INTEGER;
556
557  -- For Verilog compatability
558  function realtobits (arg : REAL) return STD_ULOGIC_VECTOR;
559  function bitstoreal (arg : STD_ULOGIC_VECTOR) return REAL;
560
561  -- Maps metalogical values
562  function to_01 (
563    arg  : UNRESOLVED_float;            -- floating point input
564    XMAP : STD_LOGIC := '0')
565    return UNRESOLVED_float;
566
567  function Is_X (arg    : UNRESOLVED_float) return BOOLEAN;
568  function to_X01 (arg  : UNRESOLVED_float) return UNRESOLVED_float;
569  function to_X01Z (arg : UNRESOLVED_float) return UNRESOLVED_float;
570  function to_UX01 (arg : UNRESOLVED_float) return UNRESOLVED_float;
571
572  -- These two procedures were copied out of the body because they proved
573  -- very useful for vendor specific algorithm development
574  -- Break_number converts a floating point number into it's parts
575  -- Exponent is biased by -1
576
577  procedure break_number (
578    arg         : in  UNRESOLVED_float;
579    denormalize : in  BOOLEAN := float_denormalize;
580    check_error : in  BOOLEAN := float_check_error;
581    fract       : out UNSIGNED;
582    expon       : out SIGNED;  -- NOTE:  Add 1 to get the real exponent!
583    sign        : out STD_ULOGIC);
584
585  procedure break_number (
586    arg         : in  UNRESOLVED_float;
587    denormalize : in  BOOLEAN := float_denormalize;
588    check_error : in  BOOLEAN := float_check_error;
589    fract       : out ufixed;           -- a number between 1.0 and 2.0
590    expon       : out SIGNED;  -- NOTE:  Add 1 to get the real exponent!
591    sign        : out STD_ULOGIC);
592
593  -- Normalize takes a fraction and and exponent and converts them into
594  -- a floating point number.  Does the shifting and the rounding.
595  -- Exponent is assumed to be biased by -1
596
597  function normalize (
598    fract                   : UNSIGNED;           -- fraction, unnormalized
599    expon                   : SIGNED;   -- exponent - 1, normalized
600    sign                    : STD_ULOGIC;         -- sign bit
601    sticky                  : STD_ULOGIC := '0';  -- Sticky bit (rounding)
602    constant exponent_width : NATURAL    := float_exponent_width;  -- size of output exponent
603    constant fraction_width : NATURAL    := float_fraction_width;  -- size of output fraction
604    constant round_style    : round_type := float_round_style;  -- rounding option
605    constant denormalize    : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
606    constant nguard         : NATURAL    := float_guard_bits)   -- guard bits
607    return UNRESOLVED_float;
608
609  -- Exponent is assumed to be biased by -1
610  function normalize (
611    fract                   : ufixed;   -- unsigned fixed point
612    expon                   : SIGNED;   -- exponent - 1, normalized
613    sign                    : STD_ULOGIC;         -- sign bit
614    sticky                  : STD_ULOGIC := '0';  -- Sticky bit (rounding)
615    constant exponent_width : NATURAL    := float_exponent_width;  -- size of output exponent
616    constant fraction_width : NATURAL    := float_fraction_width;  -- size of output fraction
617    constant round_style    : round_type := float_round_style;  -- rounding option
618    constant denormalize    : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
619    constant nguard         : NATURAL    := float_guard_bits)   -- guard bits
620    return UNRESOLVED_float;
621
622  function normalize (
623    fract                : UNSIGNED;    -- unsigned
624    expon                : SIGNED;      -- exponent - 1, normalized
625    sign                 : STD_ULOGIC;  -- sign bit
626    sticky               : STD_ULOGIC := '0';  -- Sticky bit (rounding)
627    size_res             : UNRESOLVED_float;   -- used for sizing only
628    constant round_style : round_type := float_round_style;  -- rounding option
629    constant denormalize : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
630    constant nguard      : NATURAL    := float_guard_bits)   -- guard bits
631    return UNRESOLVED_float;
632
633  -- Exponent is assumed to be biased by -1
634  function normalize (
635    fract                : ufixed;      -- unsigned fixed point
636    expon                : SIGNED;      -- exponent - 1, normalized
637    sign                 : STD_ULOGIC;  -- sign bit
638    sticky               : STD_ULOGIC := '0';  -- Sticky bit (rounding)
639    size_res             : UNRESOLVED_float;   -- used for sizing only
640    constant round_style : round_type := float_round_style;  -- rounding option
641    constant denormalize : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
642    constant nguard      : NATURAL    := float_guard_bits)   -- guard bits
643    return UNRESOLVED_float;
644
645  -- overloaded versions
646  function "+"   (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float;
647  function "+"   (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float;
648  function "+"   (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float;
649  function "+"   (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float;
650  function "-"   (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float;
651  function "-"   (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float;
652  function "-"   (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float;
653  function "-"   (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float;
654  function "*"   (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float;
655  function "*"   (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float;
656  function "*"   (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float;
657  function "*"   (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float;
658  function "/"   (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float;
659  function "/"   (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float;
660  function "/"   (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float;
661  function "/"   (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float;
662  function "rem" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float;
663  function "rem" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float;
664  function "rem" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float;
665  function "rem" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float;
666  function "mod" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float;
667  function "mod" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float;
668  function "mod" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float;
669  function "mod" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float;
670
671  -- overloaded compare functions
672  function "="   (l : UNRESOLVED_float; r : REAL) return BOOLEAN;
673  function "/="  (l : UNRESOLVED_float; r : REAL) return BOOLEAN;
674  function ">="  (l : UNRESOLVED_float; r : REAL) return BOOLEAN;
675  function "<="  (l : UNRESOLVED_float; r : REAL) return BOOLEAN;
676  function ">"   (l : UNRESOLVED_float; r : REAL) return BOOLEAN;
677  function "<"   (l : UNRESOLVED_float; r : REAL) return BOOLEAN;
678  function "="   (l : REAL; r : UNRESOLVED_float) return BOOLEAN;
679  function "/="  (l : REAL; r : UNRESOLVED_float) return BOOLEAN;
680  function ">="  (l : REAL; r : UNRESOLVED_float) return BOOLEAN;
681  function "<="  (l : REAL; r : UNRESOLVED_float) return BOOLEAN;
682  function ">"   (l : REAL; r : UNRESOLVED_float) return BOOLEAN;
683  function "<"   (l : REAL; r : UNRESOLVED_float) return BOOLEAN;
684  function "="   (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN;
685  function "/="  (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN;
686  function ">="  (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN;
687  function "<="  (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN;
688  function ">"   (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN;
689  function "<"   (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN;
690  function "="   (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN;
691  function "/="  (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN;
692  function ">="  (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN;
693  function "<="  (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN;
694  function ">"   (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN;
695  function "<"   (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN;
696  function \?=\  (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC;
697  function \?/=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC;
698  function \?>\  (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC;
699  function \?>=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC;
700  function \?<\  (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC;
701  function \?<=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC;
702  function \?=\  (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC;
703  function \?/=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC;
704  function \?>\  (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC;
705  function \?>=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC;
706  function \?<\  (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC;
707  function \?<=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC;
708  function \?=\  (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC;
709  function \?/=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC;
710  function \?>\  (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC;
711  function \?>=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC;
712  function \?<\  (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC;
713  function \?<=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC;
714  function \?=\  (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC;
715  function \?/=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC;
716  function \?>\  (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC;
717  function \?>=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC;
718  function \?<\  (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC;
719  function \?<=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC;
720  -- minimum and maximum overloads
721  function maximum (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float;
722  function minimum (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float;
723  function maximum (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float;
724  function minimum (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float;
725  function maximum (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float;
726  function minimum (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float;
727  function maximum (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float;
728  function minimum (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float;
729----------------------------------------------------------------------------
730  -- logical functions
731  ----------------------------------------------------------------------------
732
733  function "not"  (l    : UNRESOLVED_float) return UNRESOLVED_float;
734  function "and"  (l, r : UNRESOLVED_float) return UNRESOLVED_float;
735  function "or"   (l, r : UNRESOLVED_float) return UNRESOLVED_float;
736  function "nand" (l, r : UNRESOLVED_float) return UNRESOLVED_float;
737  function "nor"  (l, r : UNRESOLVED_float) return UNRESOLVED_float;
738  function "xor"  (l, r : UNRESOLVED_float) return UNRESOLVED_float;
739  function "xnor" (l, r : UNRESOLVED_float) return UNRESOLVED_float;
740  -- Vector and std_ulogic functions, same as functions in numeric_std
741  function "and" (l : STD_ULOGIC; r : UNRESOLVED_float)
742    return UNRESOLVED_float;
743  function "and" (l : UNRESOLVED_float; r : STD_ULOGIC)
744    return UNRESOLVED_float;
745  function "or" (l : STD_ULOGIC; r : UNRESOLVED_float)
746    return UNRESOLVED_float;
747  function "or" (l : UNRESOLVED_float; r : STD_ULOGIC)
748    return UNRESOLVED_float;
749  function "nand" (l : STD_ULOGIC; r : UNRESOLVED_float)
750    return UNRESOLVED_float;
751  function "nand" (l : UNRESOLVED_float; r : STD_ULOGIC)
752    return UNRESOLVED_float;
753  function "nor" (l : STD_ULOGIC; r : UNRESOLVED_float)
754    return UNRESOLVED_float;
755  function "nor" (l : UNRESOLVED_float; r : STD_ULOGIC)
756    return UNRESOLVED_float;
757  function "xor" (l : STD_ULOGIC; r : UNRESOLVED_float)
758    return UNRESOLVED_float;
759  function "xor" (l : UNRESOLVED_float; r : STD_ULOGIC)
760    return UNRESOLVED_float;
761  function "xnor" (l : STD_ULOGIC; r : UNRESOLVED_float)
762    return UNRESOLVED_float;
763  function "xnor" (l : UNRESOLVED_float; r : STD_ULOGIC)
764    return UNRESOLVED_float;
765  -- Reduction operators, same as numeric_std functions
766  function and_reduce  (l : UNRESOLVED_float) return STD_ULOGIC;
767  function nand_reduce (l : UNRESOLVED_float) return STD_ULOGIC;
768  function or_reduce   (l : UNRESOLVED_float) return STD_ULOGIC;
769  function nor_reduce  (l : UNRESOLVED_float) return STD_ULOGIC;
770  function xor_reduce  (l : UNRESOLVED_float) return STD_ULOGIC;
771  function xnor_reduce (l : UNRESOLVED_float) return STD_ULOGIC;
772
773  -- Note: "sla", "sra", "sll", "slr", "rol" and "ror" not implemented.
774
775  -----------------------------------------------------------------------------
776  -- Recommended Functions from the IEEE 754 Appendix
777  -----------------------------------------------------------------------------
778
779  -- returns x with the sign of y.
780  function Copysign (x, y : UNRESOLVED_float) return UNRESOLVED_float;
781
782  -- Returns y * 2**n for integral values of N without computing 2**n
783  function Scalb (
784    y                    : UNRESOLVED_float;  -- floating point input
785    N                    : INTEGER;     -- exponent to add
786    constant round_style : round_type := float_round_style;  -- rounding option
787    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
788    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
789    return UNRESOLVED_float;
790
791  -- Returns y * 2**n for integral values of N without computing 2**n
792  function Scalb (
793    y                    : UNRESOLVED_float;  -- floating point input
794    N                    : SIGNED;      -- exponent to add
795    constant round_style : round_type := float_round_style;  -- rounding option
796    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
797    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
798    return UNRESOLVED_float;
799
800  -- returns the unbiased exponent of x
801  function Logb (x : UNRESOLVED_float) return INTEGER;
802  function Logb (x : UNRESOLVED_float) return SIGNED;
803
804  -- returns the next representable neighbor of x in the direction toward y
805  function Nextafter (
806    x, y                 : UNRESOLVED_float;  -- floating point input
807    constant check_error : BOOLEAN := float_check_error;  -- check for errors
808    constant denormalize : BOOLEAN := float_denormalize)
809    return UNRESOLVED_float;
810
811  -- Returns TRUE if X is unordered with Y.
812  function Unordered (x, y : UNRESOLVED_float) return BOOLEAN;
813  function Finite (x       : UNRESOLVED_float) return BOOLEAN;
814  function Isnan (x        : UNRESOLVED_float) return BOOLEAN;
815
816  -- Function to return constants.
817  function zerofp (
818    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
819    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
820    return UNRESOLVED_float;
821  function nanfp (
822    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
823    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
824    return UNRESOLVED_float;
825  function qnanfp (
826    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
827    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
828    return UNRESOLVED_float;
829  function pos_inffp (
830    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
831    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
832    return UNRESOLVED_float;
833  function neg_inffp (
834    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
835    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
836    return UNRESOLVED_float;
837  function neg_zerofp (
838    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
839    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
840    return UNRESOLVED_float;
841  -- size_res versions
842  function zerofp (
843    size_res : UNRESOLVED_float)        -- variable is only use for sizing
844    return UNRESOLVED_float;
845  function nanfp (
846    size_res : UNRESOLVED_float)        -- variable is only use for sizing
847    return UNRESOLVED_float;
848  function qnanfp (
849    size_res : UNRESOLVED_float)        -- variable is only use for sizing
850    return UNRESOLVED_float;
851  function pos_inffp (
852    size_res : UNRESOLVED_float)        -- variable is only use for sizing
853    return UNRESOLVED_float;
854  function neg_inffp (
855    size_res : UNRESOLVED_float)        -- variable is only use for sizing
856    return UNRESOLVED_float;
857  function neg_zerofp (
858    size_res : UNRESOLVED_float)        -- variable is only use for sizing
859    return UNRESOLVED_float;
860
861  -- ===========================================================================
862  -- string and textio Functions
863  -- ===========================================================================
864-- rtl_synthesis off
865-- pragma synthesis_off
866  -- writes S:EEEE:FFFFFFFF
867  procedure WRITE (
868    L         : inout LINE;              -- access type (pointer)
869    VALUE     : in    UNRESOLVED_float;  -- value to write
870    JUSTIFIED : in    SIDE  := right;    -- which side to justify text
871    FIELD     : in    WIDTH := 0);       -- width of field
872
873  -- Reads SEEEEFFFFFFFF, "." and ":" are ignored
874  procedure READ (L : inout LINE; VALUE : out UNRESOLVED_float);
875  procedure READ (L    : inout LINE; VALUE : out UNRESOLVED_float;
876                  GOOD : out   BOOLEAN);
877
878  alias BREAD is READ [LINE, UNRESOLVED_float, BOOLEAN];
879  alias BREAD is READ [LINE, UNRESOLVED_float];
880  alias BWRITE is WRITE [LINE, UNRESOLVED_float, SIDE, WIDTH];
881  alias BINARY_READ is READ [LINE, UNRESOLVED_FLOAT, BOOLEAN];
882  alias BINARY_READ is READ [LINE, UNRESOLVED_FLOAT];
883  alias BINARY_WRITE is WRITE [LINE, UNRESOLVED_float, SIDE, WIDTH];
884
885  procedure OWRITE (
886    L         : inout LINE;              -- access type (pointer)
887    VALUE     : in    UNRESOLVED_float;  -- value to write
888    JUSTIFIED : in    SIDE  := right;    -- which side to justify text
889    FIELD     : in    WIDTH := 0);       -- width of field
890
891  -- Octal read with padding, no separators used
892  procedure OREAD (L : inout LINE; VALUE : out UNRESOLVED_float);
893  procedure OREAD (L    : inout LINE; VALUE : out UNRESOLVED_float;
894                   GOOD : out   BOOLEAN);
895  alias OCTAL_READ is OREAD [LINE, UNRESOLVED_FLOAT, BOOLEAN];
896  alias OCTAL_READ is OREAD [LINE, UNRESOLVED_FLOAT];
897  alias OCTAL_WRITE is OWRITE [LINE, UNRESOLVED_FLOAT, SIDE, WIDTH];
898
899  -- Hex write with padding, no separators
900  procedure HWRITE (
901    L         : inout LINE;              -- access type (pointer)
902    VALUE     : in    UNRESOLVED_float;  -- value to write
903    JUSTIFIED : in    SIDE  := right;    -- which side to justify text
904    FIELD     : in    WIDTH := 0);       -- width of field
905
906  -- Hex read with padding, no separators used
907  procedure HREAD (L : inout LINE; VALUE : out UNRESOLVED_float);
908  procedure HREAD (L    : inout LINE; VALUE : out UNRESOLVED_float;
909                   GOOD : out   BOOLEAN);
910  alias HEX_READ is HREAD [LINE, UNRESOLVED_FLOAT, BOOLEAN];
911  alias HEX_READ is HREAD [LINE, UNRESOLVED_FLOAT];
912  alias HEX_WRITE is HWRITE [LINE, UNRESOLVED_FLOAT, SIDE, WIDTH];
913
914  -- returns "S:EEEE:FFFFFFFF"
915  function to_string (value : UNRESOLVED_float) return STRING;
916  alias TO_BSTRING is TO_STRING [UNRESOLVED_FLOAT return STRING];
917  alias TO_BINARY_STRING is TO_STRING [UNRESOLVED_FLOAT return STRING];
918
919  -- Returns a HEX string, with padding
920  function to_hstring (value : UNRESOLVED_float) return STRING;
921  alias TO_HEX_STRING is TO_HSTRING [UNRESOLVED_FLOAT return STRING];
922
923  -- Returns and octal string, with padding
924  function to_ostring (value : UNRESOLVED_float) return STRING;
925  alias TO_OCTAL_STRING is TO_OSTRING [UNRESOLVED_FLOAT return STRING];
926
927  function from_string (
928    bstring                 : STRING;   -- binary string
929    constant exponent_width : NATURAL := float_exponent_width;
930    constant fraction_width : NATURAL := float_fraction_width)
931    return UNRESOLVED_float;
932  alias from_bstring is from_string [STRING, NATURAL, NATURAL
933                                     return UNRESOLVED_float];
934  alias from_binary_string is from_string [STRING, NATURAL, NATURAL
935                                           return UNRESOLVED_float];
936  function from_ostring (
937    ostring                 : STRING;   -- Octal string
938    constant exponent_width : NATURAL := float_exponent_width;
939    constant fraction_width : NATURAL := float_fraction_width)
940    return UNRESOLVED_float;
941  alias from_octal_string is from_ostring [STRING, NATURAL, NATURAL
942                                           return UNRESOLVED_float];
943
944  function from_hstring (
945    hstring                 : STRING;   -- hex string
946    constant exponent_width : NATURAL := float_exponent_width;
947    constant fraction_width : NATURAL := float_fraction_width)
948    return UNRESOLVED_float;
949  alias from_hex_string is from_hstring [STRING, NATURAL, NATURAL
950                                         return UNRESOLVED_float];
951
952  function from_string (
953    bstring  : STRING;                  -- binary string
954    size_res : UNRESOLVED_float)        -- used for sizing only
955    return UNRESOLVED_float;
956  alias from_bstring is from_string [STRING, UNRESOLVED_float
957                                     return UNRESOLVED_float];
958  alias from_binary_string is from_string [STRING, UNRESOLVED_float
959                                           return UNRESOLVED_float];
960
961  function from_ostring (
962    ostring  : STRING;                  -- Octal string
963    size_res : UNRESOLVED_float)        -- used for sizing only
964    return UNRESOLVED_float;
965  alias from_octal_string is from_ostring [STRING, UNRESOLVED_float
966                                           return UNRESOLVED_float];
967
968  function from_hstring (
969    hstring  : STRING;                  -- hex string
970    size_res : UNRESOLVED_float)        -- used for sizing only
971    return UNRESOLVED_float;
972  alias from_hex_string is from_hstring [STRING, UNRESOLVED_float
973                                         return UNRESOLVED_float];
974-- rtl_synthesis on
975-- pragma synthesis_on
976  -- IN VHDL-2006 std_logic_vector is a subtype of std_ulogic_vector, so these
977  -- extra functions are needed for compatability.
978  function to_float (
979    arg                     : STD_LOGIC_VECTOR;
980    constant exponent_width : NATURAL := float_exponent_width;  -- length of FP output exponent
981    constant fraction_width : NATURAL := float_fraction_width)  -- length of FP output fraction
982    return UNRESOLVED_float;
983
984  function to_float (
985    arg      : STD_LOGIC_VECTOR;
986    size_res : UNRESOLVED_float)
987    return UNRESOLVED_float;
988
989  -- For Verilog compatability
990  function realtobits (arg : REAL) return STD_LOGIC_VECTOR;
991  function bitstoreal (arg : STD_LOGIC_VECTOR) return REAL;
992
993end package float_pkg;
994-------------------------------------------------------------------------------
995-- Proposed package body for the VHDL-200x-FT float_pkg package
996-- This version is optimized for Synthesis, and not for simulation.
997-- Note that there are functional differences between the synthesis and
998-- simulation packages bodies.  The Synthesis version is preferred.
999-- This package body supplies a recommended implementation of these functions
1000-- Version    : $Revision: 1.1 $
1001-- Date       : $Date: 2012/03/09 20:36:50 $
1002--
1003--  Created for VHDL-200X par, David Bishop (dbishop@vhdl.org)
1004-------------------------------------------------------------------------------
1005
1006package body float_pkg is
1007
1008  -- Author David Bishop (dbishop@vhdl.org)
1009  -----------------------------------------------------------------------------
1010  -- type declarations
1011  -----------------------------------------------------------------------------
1012
1013  -- This deferred constant will tell you if the package body is synthesizable
1014  -- or implemented as real numbers, set to "true" if synthesizable.
1015  constant fphdlsynth_or_real : BOOLEAN := true;  -- deferred constant
1016
1017  -- types of boundary conditions
1018  type boundary_type is (normal, infinity, zero, denormal);
1019
1020  -- null range array constant
1021  constant NAFP : UNRESOLVED_float (0 downto 1)  := (others => '0');
1022  constant NSLV : STD_ULOGIC_VECTOR (0 downto 1) := (others => '0');
1023
1024  -- %%% Replicated functions
1025  -- These functions are replicated so that we don't need to reference the new
1026  -- 2006 package std.standard, std_logic_1164 and numeric_std.
1027  function maximum (
1028    l, r : INTEGER)                     -- inputs
1029    return INTEGER is
1030  begin  -- function max
1031    if l > r then return l;
1032    else return r;
1033    end if;
1034  end function maximum;
1035
1036  function minimum (
1037    l, r : INTEGER)                     -- inputs
1038    return INTEGER is
1039  begin  -- function min
1040    if l > r then return r;
1041    else return l;
1042    end if;
1043  end function minimum;
1044
1045  function or_reduce (arg : STD_ULOGIC_VECTOR)
1046    return STD_LOGIC is
1047    variable Upper, Lower : STD_ULOGIC;
1048    variable Half         : INTEGER;
1049    variable BUS_int      : STD_ULOGIC_VECTOR (arg'length - 1 downto 0);
1050    variable Result       : STD_ULOGIC;
1051  begin
1052    if (arg'length < 1) then            -- In the case of a NULL range
1053      Result := '0';
1054    else
1055      BUS_int := to_ux01 (arg);
1056      if (BUS_int'length = 1) then
1057        Result := BUS_int (BUS_int'left);
1058      elsif (BUS_int'length = 2) then
1059        Result := BUS_int (BUS_int'right) or BUS_int (BUS_int'left);
1060      else
1061        Half   := (BUS_int'length + 1) / 2 + BUS_int'right;
1062        Upper  := or_reduce (BUS_int (BUS_int'left downto Half));
1063        Lower  := or_reduce (BUS_int (Half - 1 downto BUS_int'right));
1064        Result := Upper or Lower;
1065      end if;
1066    end if;
1067    return Result;
1068  end function or_reduce;
1069
1070  function or_reduce (arg : UNSIGNED)
1071    return STD_ULOGIC is
1072  begin
1073    return or_reduce (STD_ULOGIC_VECTOR (arg));
1074  end function or_reduce;
1075
1076  function or_reduce (arg : SIGNED)
1077    return STD_ULOGIC is
1078  begin
1079    return or_reduce (STD_ULOGIC_VECTOR (arg));
1080  end function or_reduce;
1081
1082  function or_reduce (arg : STD_LOGIC_VECTOR)
1083    return STD_ULOGIC is
1084  begin
1085    return or_reduce (STD_ULOGIC_VECTOR (arg));
1086  end function or_reduce;
1087
1088  -- purpose: AND all of the bits in a vector together
1089  -- This is a copy of the proposed "and_reduce" from 1076.3
1090  function and_reduce (arg : STD_ULOGIC_VECTOR)
1091    return STD_LOGIC is
1092    variable Upper, Lower : STD_ULOGIC;
1093    variable Half         : INTEGER;
1094    variable BUS_int      : STD_ULOGIC_VECTOR (arg'length - 1 downto 0);
1095    variable Result       : STD_ULOGIC;
1096  begin
1097    if (arg'length < 1) then            -- In the case of a NULL range
1098      Result := '1';
1099    else
1100      BUS_int := to_ux01 (arg);
1101      if (BUS_int'length = 1) then
1102        Result := BUS_int (BUS_int'left);
1103      elsif (BUS_int'length = 2) then
1104        Result := BUS_int (BUS_int'right) and BUS_int (BUS_int'left);
1105      else
1106        Half   := (BUS_int'length + 1) / 2 + BUS_int'right;
1107        Upper  := and_reduce (BUS_int (BUS_int'left downto Half));
1108        Lower  := and_reduce (BUS_int (Half - 1 downto BUS_int'right));
1109        Result := Upper and Lower;
1110      end if;
1111    end if;
1112    return Result;
1113  end function and_reduce;
1114
1115  function and_reduce (arg : UNSIGNED)
1116    return STD_ULOGIC is
1117  begin
1118    return and_reduce (STD_ULOGIC_VECTOR (arg));
1119  end function and_reduce;
1120
1121  function and_reduce (arg : SIGNED)
1122    return STD_ULOGIC is
1123  begin
1124    return and_reduce (STD_ULOGIC_VECTOR (arg));
1125  end function and_reduce;
1126
1127  function xor_reduce (arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is
1128    variable Upper, Lower : STD_ULOGIC;
1129    variable Half         : INTEGER;
1130    variable BUS_int      : STD_ULOGIC_VECTOR (arg'length - 1 downto 0);
1131    variable Result       : STD_ULOGIC := '0';  -- In the case of a NULL range
1132  begin
1133    if (arg'length >= 1) then
1134      BUS_int := to_ux01 (arg);
1135      if (BUS_int'length = 1) then
1136        Result := BUS_int (BUS_int'left);
1137      elsif (BUS_int'length = 2) then
1138        Result := BUS_int(BUS_int'right) xor BUS_int(BUS_int'left);
1139      else
1140        Half   := (BUS_int'length + 1) / 2 + BUS_int'right;
1141        Upper  := xor_reduce (BUS_int (BUS_int'left downto Half));
1142        Lower  := xor_reduce (BUS_int (Half - 1 downto BUS_int'right));
1143        Result := Upper xor Lower;
1144      end if;
1145    end if;
1146    return Result;
1147  end function xor_reduce;
1148
1149  function nand_reduce(arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is
1150  begin
1151    return not and_reduce (arg);
1152  end function nand_reduce;
1153
1154  function nor_reduce(arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is
1155  begin
1156    return not or_reduce (arg);
1157  end function nor_reduce;
1158
1159  function xnor_reduce(arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is
1160  begin
1161    return not xor_reduce (arg);
1162  end function xnor_reduce;
1163
1164  function find_leftmost (ARG : UNSIGNED; Y : STD_ULOGIC)
1165    return INTEGER is
1166  begin
1167    for INDEX in ARG'range loop
1168      if ARG(INDEX) = Y then
1169        return INDEX;
1170      end if;
1171    end loop;
1172    return -1;
1173  end function find_leftmost;
1174
1175  -- Match table, copied form new std_logic_1164
1176  type stdlogic_table is array(STD_ULOGIC, STD_ULOGIC) of STD_ULOGIC;
1177  constant match_logic_table : stdlogic_table := (
1178    -----------------------------------------------------
1179    -- U    X    0    1    Z    W    L    H    -         |   |
1180    -----------------------------------------------------
1181    ('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', '1'),  -- | U |
1182    ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'),  -- | X |
1183    ('U', 'X', '1', '0', 'X', 'X', '1', '0', '1'),  -- | 0 |
1184    ('U', 'X', '0', '1', 'X', 'X', '0', '1', '1'),  -- | 1 |
1185    ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'),  -- | Z |
1186    ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'),  -- | W |
1187    ('U', 'X', '1', '0', 'X', 'X', '1', '0', '1'),  -- | L |
1188    ('U', 'X', '0', '1', 'X', 'X', '0', '1', '1'),  -- | H |
1189    ('1', '1', '1', '1', '1', '1', '1', '1', '1')   -- | - |
1190    );
1191
1192
1193  -------------------------------------------------------------------
1194  -- ?= functions, Similar to "std_match", but returns "std_ulogic".
1195  -------------------------------------------------------------------
1196  -- %%% FUNCTION "?=" ( l, r : std_ulogic ) RETURN std_ulogic IS
1197  function \?=\ (l, r : STD_ULOGIC) return STD_ULOGIC is
1198  begin
1199    return match_logic_table (l, r);
1200  end function \?=\;
1201  -- %%% END FUNCTION "?=";
1202
1203  -- %%% FUNCTION "?/=" ( l, r : std_ulogic ) RETURN std_ulogic is
1204  function \?/=\ (l, r : STD_ULOGIC) return STD_ULOGIC is
1205  begin
1206    return not match_logic_table (l, r);
1207  end function \?/=\;
1208  -- %%% END FUNCTION "?/=";
1209
1210  function \?=\ (l, r : STD_ULOGIC_VECTOR) return STD_ULOGIC is
1211    alias lv        : STD_ULOGIC_VECTOR(1 to l'length) is l;
1212    alias rv        : STD_ULOGIC_VECTOR(1 to r'length) is r;
1213    variable result, result1 : STD_ULOGIC;
1214  begin
1215    -- Logically identical to an "=" operator.
1216    if ((l'length < 1) and (r'length < 1)) then
1217      -- VHDL-2008 LRM 9.2.3 Two NULL arrays of the same type are equal
1218      return '1';
1219    elsif lv'length /= rv'length then
1220      -- Two arrays of different lengths are false
1221      return '0';
1222    else
1223      result := '1';
1224      for i in lv'low to lv'high loop
1225        result1 := match_logic_table(lv(i), rv(i));
1226        result := result and result1;
1227      end loop;
1228      return result;
1229    end if;
1230  end function \?=\;
1231
1232  function Is_X (s : UNSIGNED) return BOOLEAN is
1233  begin
1234    return Is_X (STD_LOGIC_VECTOR (s));
1235  end function Is_X;
1236
1237  function Is_X (s : SIGNED) return BOOLEAN is
1238  begin
1239    return Is_X (STD_LOGIC_VECTOR (s));
1240  end function Is_X;
1241-- %%% END replicated functions
1242
1243  -- Special version of "minimum" to do some boundary checking
1244  function mine (L, R : INTEGER)
1245    return INTEGER is
1246  begin  -- function minimum
1247    if (L = INTEGER'low or R = INTEGER'low) then
1248      report float_pkg'instance_name
1249        & " Unbounded number passed, was a literal used?"
1250        severity error;
1251      return 0;
1252    end if;
1253    return minimum (L, R);
1254  end function mine;
1255
1256  -- Generates the base number for the exponent normalization offset.
1257  function gen_expon_base (
1258    constant exponent_width : NATURAL)
1259    return SIGNED is
1260    variable result : SIGNED (exponent_width-1 downto 0);
1261  begin
1262    result                    := (others => '1');
1263    result (exponent_width-1) := '0';
1264    return result;
1265  end function gen_expon_base;
1266
1267  -- Integer version of the "log2" command (contributed by Peter Ashenden)
1268  function log2 (A : NATURAL) return NATURAL is
1269    variable quotient : NATURAL;
1270    variable result   : NATURAL := 0;
1271  begin
1272    quotient := A / 2;
1273    while quotient > 0 loop
1274      quotient := quotient / 2;
1275      result   := result + 1;
1276    end loop;
1277    return result;
1278  end function log2;
1279
1280  -- Function similar to the ILOGB function in MATH_REAL
1281  function log2 (A : REAL) return INTEGER is
1282    variable Y : REAL;
1283    variable N : INTEGER := 0;
1284  begin
1285    if (A = 1.0 or A = 0.0) then
1286      return 0;
1287    end if;
1288    Y := A;
1289    if(A > 1.0) then
1290      while Y >= 2.0 loop
1291        Y := Y / 2.0;
1292        N := N + 1;
1293      end loop;
1294      return N;
1295    end if;
1296    -- O < Y < 1
1297    while Y < 1.0 loop
1298      Y := Y * 2.0;
1299      N := N - 1;
1300    end loop;
1301    return N;
1302  end function log2;
1303
1304  -- purpose: Test the boundary conditions of a Real number
1305  procedure test_boundary (
1306    arg                     : in  REAL;     -- Input, converted to real
1307    constant fraction_width : in  NATURAL;  -- length of FP output fraction
1308    constant exponent_width : in  NATURAL;  -- length of FP exponent
1309    constant denormalize    : in  BOOLEAN := true;  -- Use IEEE extended FP
1310    variable btype          : out boundary_type;
1311    variable log2i          : out INTEGER
1312    ) is
1313    constant expon_base : SIGNED (exponent_width-1 downto 0) :=
1314      gen_expon_base(exponent_width);   -- exponent offset
1315    constant exp_min : SIGNED (12 downto 0) :=
1316      -(resize(expon_base, 13)) + 1;    -- Minimum normal exponent
1317    constant exp_ext_min : SIGNED (12 downto 0) :=
1318      exp_min - fraction_width;         -- Minimum for denormal exponent
1319    variable log2arg : INTEGER;         -- log2 of argument
1320  begin  -- function test_boundary
1321    -- Check to see if the exponent is big enough
1322    -- Note that the argument is always an absolute value at this point.
1323    log2arg := log2(arg);
1324    if arg = 0.0 then
1325      btype := zero;
1326    elsif exponent_width > 11 then      -- Exponent for Real is 11 (64 bit)
1327      btype := normal;
1328    else
1329      if log2arg < to_integer(exp_min) then
1330        if denormalize then
1331          if log2arg < to_integer(exp_ext_min) then
1332            btype := zero;
1333          else
1334            btype := denormal;
1335          end if;
1336        else
1337          if log2arg < to_integer(exp_min)-1 then
1338            btype := zero;
1339          else
1340            btype := normal;            -- Can still represent this number
1341          end if;
1342        end if;
1343      elsif exponent_width < 11 then
1344        if log2arg > to_integer(expon_base)+1 then
1345          btype := infinity;
1346        else
1347          btype := normal;
1348        end if;
1349      else
1350        btype := normal;
1351      end if;
1352    end if;
1353    log2i := log2arg;
1354  end procedure test_boundary;
1355
1356  -- purpose: Rounds depending on the state of the "round_style"
1357  -- Logic taken from
1358  -- "What Every Computer Scientist Should Know About Floating Point Arithmetic"
1359  -- by David Goldberg (1991)
1360  function check_round (
1361    fract_in             : STD_ULOGIC;  -- input fraction
1362    sign                 : STD_ULOGIC;  -- sign bit
1363    remainder            : UNSIGNED;    -- remainder to round from
1364    sticky               : STD_ULOGIC := '0';      -- Sticky bit
1365    constant round_style : round_type)  -- rounding type
1366    return BOOLEAN is
1367    variable result     : BOOLEAN;
1368    variable or_reduced : STD_ULOGIC;
1369  begin  -- function check_round
1370    result := false;
1371    if (remainder'length > 0) then      -- if remainder in a null array
1372      or_reduced := or_reduce (remainder & sticky);
1373      rounding_case : case round_style is
1374        when round_nearest =>           -- Round Nearest, default mode
1375          if remainder(remainder'high) = '1' then  -- round
1376            if (remainder'length > 1) then
1377              if ((or_reduce (remainder(remainder'high-1
1378                                        downto remainder'low)) = '1'
1379                   or sticky = '1')
1380                  or fract_in = '1') then
1381                -- Make the bottom bit zero if possible if we are at 1/2
1382                result := true;
1383              end if;
1384            else
1385              result := (fract_in = '1' or sticky = '1');
1386            end if;
1387          end if;
1388        when round_inf =>               -- round up if positive, else truncate.
1389          if or_reduced = '1' and sign = '0' then
1390            result := true;
1391          end if;
1392        when round_neginf =>        -- round down if negative, else truncate.
1393          if or_reduced = '1' and sign = '1' then
1394            result := true;
1395          end if;
1396        when round_zero =>              -- round toward 0   Truncate
1397          null;
1398      end case rounding_case;
1399    end if;
1400    return result;
1401  end function check_round;
1402
1403  -- purpose: Rounds depending on the state of the "round_style"
1404  -- unsigned version
1405  procedure fp_round (
1406    fract_in  : in  UNSIGNED;            -- input fraction
1407    expon_in  : in  SIGNED;              -- input exponent
1408    fract_out : out UNSIGNED;            -- output fraction
1409    expon_out : out SIGNED) is           -- output exponent
1410  begin  -- procedure fp_round
1411    if and_reduce (fract_in) = '1' then  -- Fraction is all "1"
1412      expon_out := expon_in + 1;
1413      fract_out := to_unsigned(0, fract_out'high+1);
1414    else
1415      expon_out := expon_in;
1416      fract_out := fract_in + 1;
1417    end if;
1418  end procedure fp_round;
1419
1420  -- This version of break_number doesn't call "classfp"
1421  procedure break_number (              -- internal version
1422    arg         : in  UNRESOLVED_float;
1423    fptyp       : in  valid_fpstate;
1424    denormalize : in  BOOLEAN := true;
1425    fract       : out UNSIGNED;
1426    expon       : out SIGNED) is
1427    constant fraction_width : NATURAL := -arg'low;  -- length of FP output fraction
1428    constant exponent_width : NATURAL := arg'high;  -- length of FP output exponent
1429    constant expon_base     : SIGNED (exponent_width-1 downto 0) :=
1430      gen_expon_base(exponent_width);   -- exponent offset
1431    variable exp : SIGNED (expon'range);
1432  begin
1433    fract (fraction_width-1 downto 0) :=
1434      UNSIGNED (to_slv(arg(-1 downto -fraction_width)));
1435    breakcase : case fptyp is
1436      when pos_zero | neg_zero =>
1437        fract (fraction_width) := '0';
1438        exp                    := -expon_base;
1439      when pos_denormal | neg_denormal =>
1440        if denormalize then
1441          exp                    := -expon_base;
1442          fract (fraction_width) := '0';
1443        else
1444          exp                    := -expon_base - 1;
1445          fract (fraction_width) := '1';
1446        end if;
1447      when pos_normal | neg_normal | pos_inf | neg_inf =>
1448        fract (fraction_width) := '1';
1449        exp                    := SIGNED(arg(exponent_width-1 downto 0));
1450        exp (exponent_width-1) := not exp(exponent_width-1);
1451      when others =>
1452        assert NO_WARNING
1453          report float_pkg'instance_name
1454          & "BREAK_NUMBER: " &
1455          "Meta state detected in fp_break_number process"
1456          severity warning;
1457        -- complete the case, if a NAN goes in, a NAN comes out.
1458        exp                    := (others => '1');
1459        fract (fraction_width) := '1';
1460    end case breakcase;
1461    expon := exp;
1462  end procedure break_number;
1463
1464  -- purpose: floating point to UNSIGNED
1465  -- Used by to_integer, to_unsigned, and to_signed functions
1466  procedure float_to_unsigned (
1467    arg                  : in  UNRESOLVED_float;    -- floating point input
1468    variable sign        : out STD_ULOGIC;          -- sign of output
1469    variable frac        : out UNSIGNED;            -- unsigned biased output
1470    constant denormalize : in  BOOLEAN;             -- turn on denormalization
1471    constant bias        : in  NATURAL;             -- bias for fixed point
1472    constant round_style : in  round_type) is       -- rounding method
1473    constant fraction_width : INTEGER := -mine(arg'low, arg'low);  -- length of FP output fraction
1474    constant exponent_width : INTEGER := arg'high;  -- length of FP output exponent
1475    variable fract          : UNSIGNED (frac'range);  -- internal version of frac
1476    variable isign          : STD_ULOGIC;           -- internal version of sign
1477    variable exp            : INTEGER;  -- Exponent
1478    variable expon          : SIGNED (exponent_width-1 downto 0);  -- Vectorized exp
1479    -- Base to divide fraction by
1480    variable frac_shift     : UNSIGNED (frac'high+3 downto 0);  -- Fraction shifted
1481    variable shift          : INTEGER;
1482    variable remainder      : UNSIGNED (2 downto 0);
1483    variable round          : STD_ULOGIC;           -- round BIT
1484  begin
1485    isign                   := to_x01(arg(arg'high));
1486    -- exponent /= '0', normal floating point
1487    expon                   := to_01(SIGNED(arg (exponent_width-1 downto 0)), 'X');
1488    expon(exponent_width-1) := not expon(exponent_width-1);
1489    exp                     := to_integer (expon);
1490    -- Figure out the fraction
1491    fract                   := (others => '0');     -- fill with zero
1492    fract (fract'high)      := '1';     -- Add the "1.0".
1493    shift                   := (fract'high-1) - exp;
1494    if fraction_width > fract'high then             -- Can only use size-2 bits
1495      fract (fract'high-1 downto 0) := UNSIGNED (to_slv (arg(-1 downto
1496                                                             -fract'high)));
1497    else                                -- can use all bits
1498      fract (fract'high-1 downto fract'high-fraction_width) :=
1499        UNSIGNED (to_slv (arg(-1 downto -fraction_width)));
1500    end if;
1501    frac_shift := fract & "000";
1502    if shift < 0 then                   -- Overflow
1503      fract := (others => '1');
1504    else
1505      frac_shift := shift_right (frac_shift, shift);
1506      fract      := frac_shift (frac_shift'high downto 3);
1507      remainder  := frac_shift (2 downto 0);
1508      -- round (round_zero will bypass this and truncate)
1509      case round_style is
1510        when round_nearest =>
1511          round := remainder(2) and
1512                   (fract (0) or (or_reduce (remainder (1 downto 0))));
1513        when round_inf =>
1514          round := remainder(2) and not isign;
1515        when round_neginf =>
1516          round := remainder(2) and isign;
1517        when others =>
1518          round := '0';
1519      end case;
1520      if round = '1' then
1521        fract := fract + 1;
1522      end if;
1523    end if;
1524    frac := fract;
1525    sign := isign;
1526  end procedure float_to_unsigned;
1527
1528  -- purpose: returns a part of a vector, this function is here because
1529  -- or (fractr (to_integer(shiftx) downto 0));
1530  -- can't be synthesized in some synthesis tools.
1531  function smallfract (
1532    arg   : UNSIGNED;
1533    shift : NATURAL)
1534    return STD_ULOGIC is
1535    variable orx : STD_ULOGIC;
1536  begin
1537    orx := arg(shift);
1538    for i in arg'range loop
1539      if i < shift then
1540        orx := arg(i) or orx;
1541      end if;
1542    end loop;
1543    return orx;
1544  end function smallfract;
1545  ---------------------------------------------------------------------------
1546  -- Visible functions
1547  ---------------------------------------------------------------------------
1548
1549  -- purpose: converts the negative index to a positive one
1550  -- negative indices are illegal in 1164 and 1076.3
1551  function to_sulv (
1552    arg : UNRESOLVED_float)             -- fp vector
1553    return STD_ULOGIC_VECTOR is
1554    variable result : STD_ULOGIC_VECTOR (arg'length-1 downto 0);
1555  begin  -- function to_std_ulogic_vector
1556    if arg'length < 1 then
1557      return NSLV;
1558    end if;
1559    result := STD_ULOGIC_VECTOR (arg);
1560    return result;
1561  end function to_sulv;
1562
1563  -- Converts an fp into an SLV
1564  function to_slv (arg : UNRESOLVED_float) return STD_LOGIC_VECTOR is
1565  begin
1566    return to_stdlogicvector (to_sulv (arg));
1567  end function to_slv;
1568
1569  -- purpose: normalizes a floating point number
1570  -- This version assumes an "unsigned" input with
1571  function normalize (
1572    fract                   : UNSIGNED;   -- fraction, unnormalized
1573    expon                   : SIGNED;   -- exponent, normalized by -1
1574    sign                    : STD_ULOGIC;         -- sign BIT
1575    sticky                  : STD_ULOGIC := '0';  -- Sticky bit (rounding)
1576    constant exponent_width : NATURAL    := float_exponent_width;  -- size of output exponent
1577    constant fraction_width : NATURAL    := float_fraction_width;  -- size of output fraction
1578    constant round_style    : round_type := float_round_style;  -- rounding option
1579    constant denormalize    : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
1580    constant nguard         : NATURAL    := float_guard_bits)  -- guard bits
1581    return UNRESOLVED_float is
1582    variable sfract     : UNSIGNED (fract'high downto 0);  -- shifted fraction
1583    variable rfract     : UNSIGNED (fraction_width-1 downto 0);   -- fraction
1584    variable exp        : SIGNED (exponent_width+1 downto 0);  -- exponent
1585    variable rexp       : SIGNED (exponent_width+1 downto 0);  -- result exponent
1586    variable rexpon     : UNSIGNED (exponent_width-1 downto 0);   -- exponent
1587    variable result     : UNRESOLVED_float (exponent_width downto -fraction_width);  -- result
1588    variable shiftr     : INTEGER;      -- shift amount
1589    variable stickyx    : STD_ULOGIC;   -- version of sticky
1590    constant expon_base : SIGNED (exponent_width-1 downto 0) :=
1591      gen_expon_base(exponent_width);   -- exponent offset
1592    variable round, zerores, infres : BOOLEAN;
1593  begin  -- function normalize
1594    zerores := false;
1595    infres  := false;
1596    round   := false;
1597    shiftr  := find_leftmost (to_01(fract), '1')     -- Find the first "1"
1598               - fraction_width - nguard;  -- subtract the length we want
1599    exp := resize (expon, exp'length) + shiftr;
1600    if (or_reduce (fract) = '0') then   -- Zero
1601      zerores := true;
1602    elsif ((exp <= -resize(expon_base, exp'length)-1) and denormalize)
1603      or ((exp < -resize(expon_base, exp'length)-1) and not denormalize) then
1604      if (exp >= -resize(expon_base, exp'length)-fraction_width-1)
1605        and denormalize then
1606        exp    := -resize(expon_base, exp'length)-1;
1607        shiftr := -to_integer (expon + expon_base);  -- new shift
1608      else                              -- return zero
1609        zerores := true;
1610      end if;
1611    elsif (exp > expon_base-1) then     -- infinity
1612      infres := true;
1613    end if;
1614    if zerores then
1615      result := zerofp (fraction_width => fraction_width,
1616                        exponent_width => exponent_width);
1617    elsif infres then
1618      result := pos_inffp (fraction_width => fraction_width,
1619                           exponent_width => exponent_width);
1620    else
1621      sfract := fract srl shiftr;       -- shift
1622      if shiftr > 0 then
1623--        stickyx := sticky or (or_reduce(fract (shiftr-1 downto 0)));
1624        stickyx := sticky or smallfract (fract, shiftr-1);
1625      else
1626        stickyx := sticky;
1627      end if;
1628      if nguard > 0 then
1629        round := check_round (
1630          fract_in    => sfract (nguard),
1631          sign        => sign,
1632          remainder   => sfract(nguard-1 downto 0),
1633          sticky      => stickyx,
1634          round_style => round_style);
1635      end if;
1636      if round then
1637        fp_round(fract_in  => sfract (fraction_width-1+nguard downto nguard),
1638                 expon_in  => exp(rexp'range),
1639                 fract_out => rfract,
1640                 expon_out => rexp);
1641      else
1642        rfract := sfract (fraction_width-1+nguard downto nguard);
1643        rexp   := exp(rexp'range);
1644      end if;
1645      -- result
1646      rexpon := UNSIGNED (rexp(exponent_width-1 downto 0));
1647      rexpon (exponent_width-1)          := not rexpon(exponent_width-1);
1648      result (rexpon'range)              := UNRESOLVED_float(rexpon);
1649      result (-1 downto -fraction_width) := UNRESOLVED_float(rfract);
1650    end if;
1651    result (exponent_width) := sign;    -- sign BIT
1652    return result;
1653  end function normalize;
1654
1655  -- purpose: normalizes a floating point number
1656  -- This version assumes a "ufixed" input
1657  function normalize (
1658    fract                   : ufixed;   -- unsigned fixed point
1659    expon                   : SIGNED;   -- exponent, normalized by -1
1660    sign                    : STD_ULOGIC;         -- sign bit
1661    sticky                  : STD_ULOGIC := '0';  -- Sticky bit (rounding)
1662    constant exponent_width : NATURAL    := float_exponent_width;  -- size of output exponent
1663    constant fraction_width : NATURAL    := float_fraction_width;  -- size of output fraction
1664    constant round_style    : round_type := float_round_style;  -- rounding option
1665    constant denormalize    : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
1666    constant nguard         : NATURAL    := float_guard_bits)   -- guard bits
1667    return UNRESOLVED_float is
1668    variable result : UNRESOLVED_float (exponent_width downto -fraction_width);
1669    variable arguns : UNSIGNED (fract'high + fraction_width + nguard
1670                                downto 0) := (others => '0');
1671  begin  -- function normalize
1672    arguns (arguns'high downto maximum (arguns'high-fract'length+1, 0)) :=
1673      UNSIGNED (to_slv (fract));
1674    result := normalize (fract          => arguns,
1675                         expon          => expon,
1676                         sign           => sign,
1677                         sticky         => sticky,
1678                         fraction_width => fraction_width,
1679                         exponent_width => exponent_width,
1680                         round_style    => round_style,
1681                         denormalize    => denormalize,
1682                         nguard         => nguard);
1683    return result;
1684  end function normalize;
1685
1686  -- purpose: normalizes a floating point number
1687  -- This version assumes a "ufixed" input with a "size_res" input
1688  function normalize (
1689    fract                : ufixed;      -- unsigned fixed point
1690    expon                : SIGNED;      -- exponent, normalized by -1
1691    sign                 : STD_ULOGIC;  -- sign bit
1692    sticky               : STD_ULOGIC := '0';  -- Sticky bit (rounding)
1693    size_res             : UNRESOLVED_float;   -- used for sizing only
1694    constant round_style : round_type := float_round_style;  -- rounding option
1695    constant denormalize : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
1696    constant nguard      : NATURAL    := float_guard_bits)   -- guard bits
1697    return UNRESOLVED_float is
1698    constant fraction_width : NATURAL := -size_res'low;
1699    constant exponent_width : NATURAL := size_res'high;
1700    variable result         : UNRESOLVED_float (exponent_width downto -fraction_width);
1701    variable arguns : UNSIGNED (fract'high + fraction_width + nguard
1702                                downto 0) := (others => '0');
1703  begin  -- function normalize
1704    arguns (arguns'high downto maximum (arguns'high-fract'length+1, 0)) :=
1705      UNSIGNED (to_slv (fract));
1706    result := normalize (fract          => arguns,
1707                         expon          => expon,
1708                         sign           => sign,
1709                         sticky         => sticky,
1710                         fraction_width => fraction_width,
1711                         exponent_width => exponent_width,
1712                         round_style    => round_style,
1713                         denormalize    => denormalize,
1714                         nguard         => nguard);
1715    return result;
1716  end function normalize;
1717
1718  -- Regular "normalize" function with a "size_res" input.
1719  function normalize (
1720    fract                : UNSIGNED;    -- unsigned
1721    expon                : SIGNED;      -- exponent - 1, normalized
1722    sign                 : STD_ULOGIC;  -- sign bit
1723    sticky               : STD_ULOGIC := '0';  -- Sticky bit (rounding)
1724    size_res             : UNRESOLVED_float;   -- used for sizing only
1725    constant round_style : round_type := float_round_style;  -- rounding option
1726    constant denormalize : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
1727    constant nguard      : NATURAL    := float_guard_bits)   -- guard bits
1728    return UNRESOLVED_float is
1729  begin
1730    return normalize (fract          => fract,
1731                      expon          => expon,
1732                      sign           => sign,
1733                      sticky         => sticky,
1734                      fraction_width => -size_res'low,
1735                      exponent_width => size_res'high,
1736                      round_style    => round_style,
1737                      denormalize    => denormalize,
1738                      nguard         => nguard);
1739  end function normalize;
1740
1741  -- Returns the class which X falls into
1742  function Classfp (
1743    x           : UNRESOLVED_float;     -- floating point input
1744    check_error : BOOLEAN := float_check_error)   -- check for errors
1745    return valid_fpstate is
1746    constant fraction_width : INTEGER := -mine(x'low, x'low);  -- length of FP output fraction
1747    constant exponent_width : INTEGER := x'high;  -- length of FP output exponent
1748    variable arg            : UNRESOLVED_float (exponent_width downto -fraction_width);
1749  begin  -- classfp
1750    if (arg'length < 1 or fraction_width < 3 or exponent_width < 3
1751        or x'left < x'right) then
1752      report float_pkg'instance_name
1753        & "CLASSFP: " &
1754        "Floating point number detected with a bad range"
1755        severity error;
1756      return isx;
1757    end if;
1758    -- Check for "X".
1759    arg := to_01 (x, 'X');
1760    if (arg(0) = 'X') then
1761      return isx;                       -- If there is an X in the number
1762      -- Special cases, check for illegal number
1763    elsif check_error and
1764      (and_reduce (STD_ULOGIC_VECTOR (arg (exponent_width-1 downto 0)))
1765       = '1') then                      -- Exponent is all "1".
1766      if or_reduce (to_slv (arg (-1 downto -fraction_width)))
1767        /= '0' then  -- Fraction must be all "0" or this is not a number.
1768        if (arg(-1) = '1') then         -- From "W. Khan - IEEE standard
1769          return nan;            -- 754 binary FP Signaling nan (Not a number)
1770        else
1771          return quiet_nan;
1772        end if;
1773        -- Check for infinity
1774      elsif arg(exponent_width) = '0' then
1775        return pos_inf;                 -- Positive infinity
1776      else
1777        return neg_inf;                 -- Negative infinity
1778      end if;
1779      -- check for "0"
1780    elsif or_reduce (STD_LOGIC_VECTOR (arg (exponent_width-1 downto 0)))
1781      = '0' then                        -- Exponent is all "0"
1782      if or_reduce (to_slv (arg (-1 downto -fraction_width)))
1783        = '0' then                      -- Fraction is all "0"
1784        if arg(exponent_width) = '0' then
1785          return pos_zero;              -- Zero
1786        else
1787          return neg_zero;
1788        end if;
1789      else
1790        if arg(exponent_width) = '0' then
1791          return pos_denormal;          -- Denormal number (ieee extended fp)
1792        else
1793          return neg_denormal;
1794        end if;
1795      end if;
1796    else
1797      if arg(exponent_width) = '0' then
1798        return pos_normal;              -- Normal FP number
1799      else
1800        return neg_normal;
1801      end if;
1802    end if;
1803  end function Classfp;
1804
1805  procedure break_number (
1806    arg         : in  UNRESOLVED_float;
1807    denormalize : in  BOOLEAN := float_denormalize;
1808    check_error : in  BOOLEAN := float_check_error;
1809    fract       : out UNSIGNED;
1810    expon       : out SIGNED;
1811    sign        : out STD_ULOGIC) is
1812    constant fraction_width : NATURAL := -mine(arg'low, arg'low);  -- length of FP output fraction
1813    variable fptyp          : valid_fpstate;
1814  begin
1815    fptyp := Classfp (arg, check_error);
1816    sign  := to_x01(arg(arg'high));
1817    break_number (
1818      arg         => arg,
1819      fptyp       => fptyp,
1820      denormalize => denormalize,
1821      fract       => fract,
1822      expon       => expon);
1823  end procedure break_number;
1824
1825  procedure break_number (
1826    arg         : in  UNRESOLVED_float;
1827    denormalize : in  BOOLEAN := float_denormalize;
1828    check_error : in  BOOLEAN := float_check_error;
1829    fract       : out ufixed;           -- 1 downto -fraction_width
1830    expon       : out SIGNED;           -- exponent_width-1 downto 0
1831    sign        : out STD_ULOGIC) is
1832    constant fraction_width : NATURAL := -mine(arg'low, arg'low);  -- length of FP output fraction
1833    variable fptyp          : valid_fpstate;
1834    variable ufract         : UNSIGNED (fraction_width downto 0);  -- unsigned fraction
1835  begin
1836    fptyp := Classfp (arg, check_error);
1837    sign  := to_x01(arg(arg'high));
1838    break_number (
1839      arg         => arg,
1840      fptyp       => fptyp,
1841      denormalize => denormalize,
1842      fract       => ufract,
1843      expon       => expon);
1844    fract (0 downto -fraction_width) := ufixed (ufract);
1845  end procedure break_number;
1846
1847  -- Arithmetic functions
1848  function "abs" (
1849    arg : UNRESOLVED_float)             -- floating point input
1850    return UNRESOLVED_float is
1851    variable result : UNRESOLVED_float (arg'range);  -- result
1852  begin
1853    if (arg'length > 0) then
1854      result            := to_01 (arg, 'X');
1855      result (arg'high) := '0';         -- set the sign bit to positive
1856      return result;
1857    else
1858      return NAFP;
1859    end if;
1860  end function "abs";
1861
1862  -- IEEE 754 "negative" function
1863  function "-" (
1864    arg : UNRESOLVED_float)                          -- floating point input
1865    return UNRESOLVED_float is
1866    variable result : UNRESOLVED_float (arg'range);  -- result
1867  begin
1868    if (arg'length > 0) then
1869      result            := to_01 (arg, 'X');
1870      result (arg'high) := not result (arg'high);    -- invert sign bit
1871      return result;
1872    else
1873      return NAFP;
1874    end if;
1875  end function "-";
1876
1877  -- Addition, adds two floating point numbers
1878  function add (
1879    l, r                 : UNRESOLVED_float;  -- floating point input
1880    constant round_style : round_type := float_round_style;  -- rounding option
1881    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
1882    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
1883    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
1884    return UNRESOLVED_float is
1885    constant fraction_width   : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
1886    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
1887    constant addguard         : NATURAL := guard;         -- add one guard bit
1888    variable lfptype, rfptype : valid_fpstate;
1889    variable fpresult         : UNRESOLVED_float (exponent_width downto -fraction_width);
1890    variable fractl, fractr   : UNSIGNED (fraction_width+1+addguard downto 0);  -- fractions
1891    variable fractc, fracts   : UNSIGNED (fractl'range);  -- constant and shifted variables
1892    variable urfract, ulfract : UNSIGNED (fraction_width downto 0);
1893    variable ufract           : UNSIGNED (fraction_width+1+addguard downto 0);
1894    variable exponl, exponr   : SIGNED (exponent_width-1 downto 0);  -- exponents
1895    variable rexpon           : SIGNED (exponent_width downto 0);  -- result exponent
1896    variable shiftx           : SIGNED (exponent_width downto 0);  -- shift fractions
1897    variable sign             : STD_ULOGIC;   -- sign of the output
1898    variable leftright        : BOOLEAN;      -- left or right used
1899    variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width);
1900    variable sticky           : STD_ULOGIC;   -- Holds precision for rounding
1901  begin  -- addition
1902    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
1903      lfptype := isx;
1904    else
1905      lfptype := classfp (l, check_error);
1906      rfptype := classfp (r, check_error);
1907    end if;
1908    if (lfptype = isx or rfptype = isx) then
1909      fpresult := (others => 'X');
1910    elsif (lfptype = nan or lfptype = quiet_nan or
1911           rfptype = nan or rfptype = quiet_nan)
1912      -- Return quiet NAN, IEEE754-1985-7.1,1
1913      or (lfptype = pos_inf and rfptype = neg_inf)
1914      or (lfptype = neg_inf and rfptype = pos_inf) then
1915      -- Return quiet NAN, IEEE754-1985-7.1,2
1916      fpresult := qnanfp (fraction_width => fraction_width,
1917                          exponent_width => exponent_width);
1918    elsif (lfptype = pos_inf or rfptype = pos_inf) then   -- x + inf = inf
1919      fpresult := pos_inffp (fraction_width => fraction_width,
1920                             exponent_width => exponent_width);
1921    elsif (lfptype = neg_inf or rfptype = neg_inf) then   -- x - inf = -inf
1922      fpresult := neg_inffp (fraction_width => fraction_width,
1923                             exponent_width => exponent_width);
1924    elsif (lfptype = neg_zero and rfptype = neg_zero) then   -- -0 + -0 = -0
1925      fpresult := neg_zerofp (fraction_width => fraction_width,
1926                             exponent_width => exponent_width);
1927    else
1928      lresize := resize (arg            => to_x01(l),
1929                         exponent_width => exponent_width,
1930                         fraction_width => fraction_width,
1931                         denormalize_in => denormalize,
1932                         denormalize    => denormalize);
1933      lfptype := classfp (lresize, false);    -- errors already checked
1934      rresize := resize (arg            => to_x01(r),
1935                         exponent_width => exponent_width,
1936                         fraction_width => fraction_width,
1937                         denormalize_in => denormalize,
1938                         denormalize    => denormalize);
1939      rfptype := classfp (rresize, false);    -- errors already checked
1940      break_number (
1941        arg         => lresize,
1942        fptyp       => lfptype,
1943        denormalize => denormalize,
1944        fract       => ulfract,
1945        expon       => exponl);
1946      fractl := (others => '0');
1947      fractl (fraction_width+addguard downto addguard) := ulfract;
1948      break_number (
1949        arg         => rresize,
1950        fptyp       => rfptype,
1951        denormalize => denormalize,
1952        fract       => urfract,
1953        expon       => exponr);
1954      fractr := (others => '0');
1955      fractr (fraction_width+addguard downto addguard) := urfract;
1956      shiftx := (exponl(exponent_width-1) & exponl) - exponr;
1957      if shiftx < -fractl'high then
1958        rexpon    := exponr(exponent_width-1) & exponr;
1959        fractc    := fractr;
1960        fracts    := (others => '0');   -- add zero
1961        leftright := false;
1962        sticky    := or_reduce (fractl);
1963      elsif shiftx < 0 then
1964        shiftx    := - shiftx;
1965        fracts    := shift_right (fractl, to_integer(shiftx));
1966        fractc    := fractr;
1967        rexpon    := exponr(exponent_width-1) & exponr;
1968        leftright := false;
1969--        sticky    := or_reduce (fractl (to_integer(shiftx) downto 0));
1970        sticky    := smallfract (fractl, to_integer(shiftx));
1971      elsif shiftx = 0 then
1972        rexpon := exponl(exponent_width-1) & exponl;
1973        sticky := '0';
1974        if fractr > fractl then
1975          fractc    := fractr;
1976          fracts    := fractl;
1977          leftright := false;
1978        else
1979          fractc    := fractl;
1980          fracts    := fractr;
1981          leftright := true;
1982        end if;
1983      elsif shiftx > fractr'high then
1984        rexpon    := exponl(exponent_width-1) & exponl;
1985        fracts    := (others => '0');   -- add zero
1986        fractc    := fractl;
1987        leftright := true;
1988        sticky    := or_reduce (fractr);
1989      elsif shiftx > 0 then
1990        fracts    := shift_right (fractr, to_integer(shiftx));
1991        fractc    := fractl;
1992        rexpon    := exponl(exponent_width-1) & exponl;
1993        leftright := true;
1994--        sticky    := or_reduce (fractr (to_integer(shiftx) downto 0));
1995        sticky    := smallfract (fractr, to_integer(shiftx));
1996      end if;
1997      -- add
1998      fracts (0) := fracts (0) or sticky;     -- Or the sticky bit into the LSB
1999      if l(l'high) = r(r'high) then
2000        ufract := fractc + fracts;
2001        sign   := l(l'high);
2002      else                              -- signs are different
2003        ufract := fractc - fracts;      -- always positive result
2004        if leftright then               -- Figure out which sign to use
2005          sign := l(l'high);
2006        else
2007          sign := r(r'high);
2008        end if;
2009      end if;
2010      if or_reduce (ufract) = '0' then
2011        sign := '0';                    -- IEEE 854, 6.3, paragraph 2.
2012      end if;
2013        -- normalize
2014      fpresult := normalize (fract          => ufract,
2015                             expon          => rexpon,
2016                             sign           => sign,
2017                             sticky         => sticky,
2018                             fraction_width => fraction_width,
2019                             exponent_width => exponent_width,
2020                             round_style    => round_style,
2021                             denormalize    => denormalize,
2022                             nguard         => addguard);
2023    end if;
2024    return fpresult;
2025  end function add;
2026
2027  -- Subtraction, Calls "add".
2028  function subtract (
2029    l, r                 : UNRESOLVED_float;     -- floating point input
2030    constant round_style : round_type := float_round_style;  -- rounding option
2031    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
2032    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
2033    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
2034    return UNRESOLVED_float is
2035    variable negr : UNRESOLVED_float (r'range);  -- negative version of r
2036  begin
2037    negr := -r;
2038    return add (l           => l,
2039                r           => negr,
2040                round_style => round_style,
2041                guard       => guard,
2042                check_error => check_error,
2043                denormalize => denormalize);
2044  end function subtract;
2045
2046  -- Floating point multiply
2047  function multiply (
2048    l, r                 : UNRESOLVED_float;  -- floating point input
2049    constant round_style : round_type := float_round_style;  -- rounding option
2050    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
2051    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
2052    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
2053    return UNRESOLVED_float is
2054    constant fraction_width   : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
2055    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
2056    constant multguard        : NATURAL := guard;           -- guard bits
2057    variable lfptype, rfptype : valid_fpstate;
2058    variable fpresult         : UNRESOLVED_float (exponent_width downto -fraction_width);
2059    variable fractl, fractr   : UNSIGNED (fraction_width downto 0);  -- fractions
2060    variable rfract           : UNSIGNED ((2*(fraction_width))+1 downto 0);  -- result fraction
2061    variable sfract           : UNSIGNED (fraction_width+1+multguard downto 0);  -- result fraction
2062    variable shifty           : INTEGER;      -- denormal shift
2063    variable exponl, exponr   : SIGNED (exponent_width-1 downto 0);  -- exponents
2064    variable rexpon           : SIGNED (exponent_width+1 downto 0);  -- result exponent
2065    variable fp_sign          : STD_ULOGIC;   -- sign of result
2066    variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width);
2067    variable sticky           : STD_ULOGIC;   -- Holds precision for rounding
2068  begin  -- multiply
2069    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
2070      lfptype := isx;
2071    else
2072      lfptype := classfp (l, check_error);
2073      rfptype := classfp (r, check_error);
2074    end if;
2075    if (lfptype = isx or rfptype = isx) then
2076      fpresult := (others => 'X');
2077    elsif ((lfptype = nan or lfptype = quiet_nan or
2078            rfptype = nan or rfptype = quiet_nan)) then
2079      -- Return quiet NAN, IEEE754-1985-7.1,1
2080      fpresult := qnanfp (fraction_width => fraction_width,
2081                          exponent_width => exponent_width);
2082    elsif (((lfptype = pos_inf or lfptype = neg_inf) and
2083            (rfptype = pos_zero or rfptype = neg_zero)) or
2084           ((rfptype = pos_inf or rfptype = neg_inf) and
2085            (lfptype = pos_zero or lfptype = neg_zero))) then    -- 0 * inf
2086      -- Return quiet NAN, IEEE754-1985-7.1,3
2087      fpresult := qnanfp (fraction_width => fraction_width,
2088                          exponent_width => exponent_width);
2089    elsif (lfptype = pos_inf or rfptype = pos_inf
2090           or lfptype = neg_inf or rfptype = neg_inf) then  -- x * inf = inf
2091      fpresult := pos_inffp (fraction_width => fraction_width,
2092                             exponent_width => exponent_width);
2093      -- figure out the sign
2094      fp_sign := l(l'high) xor r(r'high);     -- figure out the sign
2095      fpresult (exponent_width) := fp_sign;
2096    else
2097      fp_sign := l(l'high) xor r(r'high);     -- figure out the sign
2098      lresize := resize (arg            => to_x01(l),
2099                         exponent_width => exponent_width,
2100                         fraction_width => fraction_width,
2101                         denormalize_in => denormalize,
2102                         denormalize    => denormalize);
2103      lfptype := classfp (lresize, false);    -- errors already checked
2104      rresize := resize (arg            => to_x01(r),
2105                         exponent_width => exponent_width,
2106                         fraction_width => fraction_width,
2107                         denormalize_in => denormalize,
2108                         denormalize    => denormalize);
2109      rfptype := classfp (rresize, false);    -- errors already checked
2110      break_number (
2111        arg         => lresize,
2112        fptyp       => lfptype,
2113        denormalize => denormalize,
2114        fract       => fractl,
2115        expon       => exponl);
2116      break_number (
2117        arg         => rresize,
2118        fptyp       => rfptype,
2119        denormalize => denormalize,
2120        fract       => fractr,
2121        expon       => exponr);
2122      if (rfptype = pos_denormal or rfptype = neg_denormal) then
2123        shifty := fraction_width - find_leftmost(fractr, '1');
2124        fractr := shift_left (fractr, shifty);
2125      elsif (lfptype = pos_denormal or lfptype = neg_denormal) then
2126        shifty := fraction_width - find_leftmost(fractl, '1');
2127        fractl := shift_left (fractl, shifty);
2128      else
2129        shifty := 0;
2130        -- Note that a denormal number * a denormal number is always zero.
2131      end if;
2132      -- multiply
2133      -- add the exponents
2134      rexpon := resize (exponl, rexpon'length) + exponr - shifty + 1;
2135      rfract := fractl * fractr;        -- Multiply the fraction
2136      sfract := rfract (rfract'high downto
2137                        rfract'high - (fraction_width+1+multguard));
2138      sticky := or_reduce (rfract (rfract'high-(fraction_width+1+multguard)
2139                                   downto 0));
2140      -- normalize
2141      fpresult := normalize (fract          => sfract,
2142                             expon          => rexpon,
2143                             sign           => fp_sign,
2144                             sticky         => sticky,
2145                             fraction_width => fraction_width,
2146                             exponent_width => exponent_width,
2147                             round_style    => round_style,
2148                             denormalize    => denormalize,
2149                             nguard         => multguard);
2150    end if;
2151    return fpresult;
2152  end function multiply;
2153
2154  function short_divide (
2155    lx, rx : UNSIGNED)
2156    return UNSIGNED is
2157    -- This is a special divider for the floating point routines.
2158    -- For a true unsigned divider, "stages" needs to = lx'high
2159    constant stages       : INTEGER := lx'high - rx'high;  -- number of stages
2160    variable partial      : UNSIGNED (lx'range);
2161    variable q            : UNSIGNED (stages downto 0);
2162    variable partial_argl : SIGNED (rx'high + 2 downto 0);
2163    variable partial_arg  : SIGNED (rx'high + 2 downto 0);
2164  begin
2165    partial := lx;
2166    for i in stages downto 0 loop
2167      partial_argl := resize ("0" & SIGNED (partial(lx'high downto i)),
2168                              partial_argl'length);
2169      partial_arg := partial_argl - SIGNED ("0" & rx);
2170      if (partial_arg (partial_arg'high) = '1') then       -- negative
2171        q(i) := '0';
2172      else
2173        q(i) := '1';
2174        partial (lx'high+i-stages downto lx'high+i-stages-rx'high) :=
2175          UNSIGNED (partial_arg(rx'range));
2176      end if;
2177    end loop;
2178    -- to make the output look like that of the unsigned IEEE divide.
2179    return resize (q, lx'length);
2180  end function short_divide;
2181
2182  -- 1/X function.  Needed for algorithm development.
2183  function reciprocal (
2184    arg                  : UNRESOLVED_float;
2185    constant round_style : round_type := float_round_style;  -- rounding option
2186    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
2187    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
2188    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
2189    return UNRESOLVED_float is
2190    constant fraction_width : NATURAL := -mine(arg'low, arg'low);  -- length of FP output fraction
2191    constant exponent_width : NATURAL := arg'high;  -- length of FP output exponent
2192    constant divguard       : NATURAL := guard;     -- guard bits
2193    function onedivy (
2194      arg : UNSIGNED)
2195      return UNSIGNED is
2196      variable q   : UNSIGNED((2*arg'high)+1 downto 0);
2197      variable one : UNSIGNED (q'range);
2198    begin
2199      one           := (others => '0');
2200      one(one'high) := '1';
2201      q := short_divide (one, arg);     -- Unsigned divide
2202      return resize (q, arg'length+1);
2203    end function onedivy;
2204    variable fptype        : valid_fpstate;
2205    variable expon         : SIGNED (exponent_width-1 downto 0);   -- exponents
2206    variable denorm_offset : NATURAL range 0 to 2;
2207    variable fract         : UNSIGNED (fraction_width downto 0);
2208    variable fractg        : UNSIGNED (fraction_width+divguard downto 0);
2209    variable sfract        : UNSIGNED (fraction_width+1+divguard downto 0);  -- result fraction
2210    variable fpresult      : UNRESOLVED_float (exponent_width downto -fraction_width);
2211  begin  -- reciprocal
2212    fptype := classfp(arg, check_error);
2213    classcase : case fptype is
2214      when isx =>
2215        fpresult := (others => 'X');
2216      when nan | quiet_nan =>
2217        -- Return quiet NAN, IEEE754-1985-7.1,1
2218        fpresult := qnanfp (fraction_width => fraction_width,
2219                            exponent_width => exponent_width);
2220      when pos_inf | neg_inf =>         -- 1/inf, return 0
2221        fpresult := zerofp (fraction_width => fraction_width,
2222                            exponent_width => exponent_width);
2223      when neg_zero | pos_zero =>       -- 1/0
2224        report float_pkg'instance_name
2225          & "RECIPROCAL: Floating Point divide by zero"
2226          severity error;
2227        fpresult := pos_inffp (fraction_width => fraction_width,
2228                               exponent_width => exponent_width);
2229      when others =>
2230        if (fptype = pos_denormal or fptype = neg_denormal)
2231          and ((arg (-1) or arg(-2)) /= '1') then
2232          -- 1/denormal = infinity, with the exception of 2**-expon_base
2233          fpresult := pos_inffp (fraction_width => fraction_width,
2234                                 exponent_width => exponent_width);
2235          fpresult (exponent_width) := to_x01 (arg (exponent_width));
2236        else
2237          break_number (
2238            arg         => arg,
2239            fptyp       => fptype,
2240            denormalize => denormalize,
2241            fract       => fract,
2242            expon       => expon);
2243          fractg := (others => '0');
2244          if (fptype = pos_denormal or fptype = neg_denormal) then
2245            -- The reciprocal of a denormal number is typically zero,
2246            -- except for two special cases which are trapped here.
2247            if (to_x01(arg (-1)) = '1') then
2248              fractg (fractg'high downto divguard+1) :=
2249                fract (fract'high-1 downto 0);      -- Shift to not denormal
2250              denorm_offset := 1;       -- add 1 to exponent compensate
2251            else                        -- arg(-2) = '1'
2252              fractg (fractg'high downto divguard+2) :=
2253                fract (fract'high-2 downto 0);      -- Shift to not denormal
2254              denorm_offset := 2;       -- add 2 to exponent compensate
2255            end if;
2256          else
2257            fractg (fractg'high downto divguard) := fract;
2258            denorm_offset := 0;
2259          end if;
2260          expon  := - expon - 3 + denorm_offset;
2261          sfract := onedivy (fractg);
2262          -- normalize
2263          fpresult := normalize (fract          => sfract,
2264                                 expon          => expon,
2265                                 sign           => arg(exponent_width),
2266                                 sticky         => '1',
2267                                 fraction_width => fraction_width,
2268                                 exponent_width => exponent_width,
2269                                 round_style    => round_style,
2270                                 denormalize    => denormalize,
2271                                 nguard         => divguard);
2272        end if;
2273    end case classcase;
2274    return fpresult;
2275  end function reciprocal;
2276
2277  -- floating point division
2278  function divide (
2279    l, r                 : UNRESOLVED_float;       -- floating point input
2280    constant round_style : round_type := float_round_style;  -- rounding option
2281    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
2282    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
2283    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
2284    return UNRESOLVED_float is
2285    constant fraction_width   : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
2286    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
2287    constant divguard         : NATURAL := guard;  -- division guard bits
2288    variable lfptype, rfptype : valid_fpstate;
2289    variable fpresult         : UNRESOLVED_float (exponent_width downto -fraction_width);
2290    variable ulfract, urfract : UNSIGNED (fraction_width downto 0);
2291    variable fractl           : UNSIGNED ((2*(fraction_width+divguard)+1) downto 0);  -- left
2292    variable fractr           : UNSIGNED (fraction_width+divguard downto 0);  -- right
2293    variable rfract           : UNSIGNED (fractl'range);    -- result fraction
2294    variable sfract           : UNSIGNED (fraction_width+1+divguard downto 0);  -- result fraction
2295    variable exponl, exponr   : SIGNED (exponent_width-1 downto 0);  -- exponents
2296    variable rexpon           : SIGNED (exponent_width+1 downto 0);  -- result exponent
2297    variable fp_sign, sticky  : STD_ULOGIC;        -- sign of result
2298    variable shifty, shiftx   : INTEGER;           -- denormal number shift
2299    variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width);
2300  begin  -- divide
2301    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
2302      lfptype := isx;
2303    else
2304      lfptype := classfp (l, check_error);
2305      rfptype := classfp (r, check_error);
2306    end if;
2307    classcase : case rfptype is
2308      when isx =>
2309        fpresult := (others => 'X');
2310      when nan | quiet_nan =>
2311        -- Return quiet NAN, IEEE754-1985-7.1,1
2312        fpresult := qnanfp (fraction_width => fraction_width,
2313                            exponent_width => exponent_width);
2314      when pos_inf | neg_inf =>
2315        if lfptype = pos_inf or lfptype = neg_inf  -- inf / inf
2316          or lfptype = quiet_nan or lfptype = nan then
2317          -- Return quiet NAN, IEEE754-1985-7.1,4
2318          fpresult := qnanfp (fraction_width => fraction_width,
2319                              exponent_width => exponent_width);
2320        else                            -- x / inf = 0
2321          fpresult := zerofp (fraction_width => fraction_width,
2322                              exponent_width => exponent_width);
2323          fp_sign := l(l'high) xor r(r'high);        -- sign
2324          fpresult (fpresult'high) := fp_sign;  -- sign
2325        end if;
2326      when pos_zero | neg_zero =>
2327        if lfptype = pos_zero or lfptype = neg_zero         -- 0 / 0
2328          or lfptype = quiet_nan or lfptype = nan then
2329          -- Return quiet NAN, IEEE754-1985-7.1,4
2330          fpresult := qnanfp (fraction_width => fraction_width,
2331                              exponent_width => exponent_width);
2332        else
2333          report float_pkg'instance_name
2334            & "DIVIDE: Floating Point divide by zero"
2335            severity error;
2336          -- Infinity, define in 754-1985-7.2
2337          fpresult := pos_inffp (fraction_width => fraction_width,
2338                                 exponent_width => exponent_width);
2339          fp_sign := l(l'high) xor r(r'high);        -- sign
2340          fpresult (fpresult'high) := fp_sign;  -- sign
2341        end if;
2342      when others =>
2343        classcase2 : case lfptype is
2344          when isx =>
2345            fpresult := (others => 'X');
2346          when nan | quiet_nan =>
2347            -- Return quiet NAN, IEEE754-1985-7.1,1
2348            fpresult := qnanfp (fraction_width => fraction_width,
2349                                exponent_width => exponent_width);
2350          when pos_inf | neg_inf =>     -- inf / x = inf
2351            fpresult := pos_inffp (fraction_width => fraction_width,
2352                                   exponent_width => exponent_width);
2353            fp_sign := l(l'high) xor r(r'high);        -- sign
2354            fpresult(exponent_width) := fp_sign;
2355          when pos_zero | neg_zero =>   -- 0 / X = 0
2356            fpresult := zerofp (fraction_width => fraction_width,
2357                                exponent_width => exponent_width);
2358            fp_sign := l(l'high) xor r(r'high);        -- sign
2359            fpresult(exponent_width) := fp_sign;
2360          when others =>
2361            fp_sign := l(l'high) xor r(r'high);        -- sign
2362            lresize := resize (arg            => to_x01(l),
2363                               exponent_width => exponent_width,
2364                               fraction_width => fraction_width,
2365                               denormalize_in => denormalize,
2366                               denormalize    => denormalize);
2367            lfptype := classfp (lresize, false);   -- errors already checked
2368            rresize := resize (arg            => to_x01(r),
2369                               exponent_width => exponent_width,
2370                               fraction_width => fraction_width,
2371                               denormalize_in => denormalize,
2372                               denormalize    => denormalize);
2373            rfptype := classfp (rresize, false);   -- errors already checked
2374            break_number (
2375              arg         => lresize,
2376              fptyp       => lfptype,
2377              denormalize => denormalize,
2378              fract       => ulfract,
2379              expon       => exponl);
2380            -- right side
2381            break_number (
2382              arg         => rresize,
2383              fptyp       => rfptype,
2384              denormalize => denormalize,
2385              fract       => urfract,
2386              expon       => exponr);
2387            -- Compute the exponent
2388            rexpon := resize (exponl, rexpon'length) - exponr - 2;
2389            if (rfptype = pos_denormal or rfptype = neg_denormal) then
2390              -- Do the shifting here not after.  That way we have a smaller
2391              -- shifter, and need a smaller divider, because the top
2392              -- bit in the divisor will always be a "1".
2393              shifty := fraction_width - find_leftmost(urfract, '1');
2394              urfract := shift_left (urfract, shifty);
2395              rexpon := rexpon + shifty;
2396            end if;
2397            fractr := (others => '0');
2398            fractr (fraction_width+divguard downto divguard) := urfract;
2399            if (lfptype = pos_denormal or lfptype = neg_denormal) then
2400              shiftx := fraction_width - find_leftmost(ulfract, '1');
2401              ulfract := shift_left (ulfract, shiftx);
2402              rexpon := rexpon - shiftx;
2403            end if;
2404            fractl  := (others => '0');
2405            fractl (fractl'high downto fractl'high-fraction_width) := ulfract;
2406            -- divide
2407            rfract := short_divide (fractl, fractr);        -- unsigned divide
2408            sfract := rfract (sfract'range);       -- lower bits
2409            sticky := '1';
2410            -- normalize
2411            fpresult := normalize (fract          => sfract,
2412                                   expon          => rexpon,
2413                                   sign           => fp_sign,
2414                                   sticky         => sticky,
2415                                   fraction_width => fraction_width,
2416                                   exponent_width => exponent_width,
2417                                   round_style    => round_style,
2418                                   denormalize    => denormalize,
2419                                   nguard         => divguard);
2420        end case classcase2;
2421    end case classcase;
2422    return fpresult;
2423  end function divide;
2424
2425  -- division by a power of 2
2426  function dividebyp2 (
2427    l, r                 : UNRESOLVED_float;      -- floating point input
2428    constant round_style : round_type := float_round_style;  -- rounding option
2429    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
2430    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
2431    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
2432    return UNRESOLVED_float is
2433    constant fraction_width   : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
2434    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
2435    variable lfptype, rfptype : valid_fpstate;
2436    variable fpresult         : UNRESOLVED_float (exponent_width downto -fraction_width);
2437    variable ulfract, urfract : UNSIGNED (fraction_width downto 0);
2438    variable exponl, exponr   : SIGNED(exponent_width-1 downto 0);  -- exponents
2439    variable rexpon           : SIGNED(exponent_width downto 0);  -- result exponent
2440    variable fp_sign          : STD_ULOGIC;       -- sign of result
2441    variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width);
2442  begin  -- divisionbyp2
2443    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
2444      lfptype := isx;
2445    else
2446      lfptype := classfp (l, check_error);
2447      rfptype := classfp (r, check_error);
2448    end if;
2449    classcase : case rfptype is
2450      when isx =>
2451        fpresult := (others => 'X');
2452      when nan | quiet_nan =>
2453        -- Return quiet NAN, IEEE754-1985-7.1,1
2454        fpresult := qnanfp (fraction_width => fraction_width,
2455                            exponent_width => exponent_width);
2456      when pos_inf | neg_inf =>
2457        if lfptype = pos_inf or lfptype = neg_inf then      -- inf / inf
2458          -- Return quiet NAN, IEEE754-1985-7.1,4
2459          fpresult := qnanfp (fraction_width => fraction_width,
2460                              exponent_width => exponent_width);
2461        else                            -- x / inf = 0
2462          fpresult := zerofp (fraction_width => fraction_width,
2463                              exponent_width => exponent_width);
2464          fp_sign := l(l'high) xor r(r'high);        -- sign
2465          fpresult (fpresult'high) := fp_sign;  -- sign
2466        end if;
2467      when pos_zero | neg_zero =>
2468        if lfptype = pos_zero or lfptype = neg_zero then    -- 0 / 0
2469          -- Return quiet NAN, IEEE754-1985-7.1,4
2470          fpresult := qnanfp (fraction_width => fraction_width,
2471                              exponent_width => exponent_width);
2472        else
2473          report float_pkg'instance_name
2474            & "DIVIDEBYP2: Floating Point divide by zero"
2475            severity error;
2476          -- Infinity, define in 754-1985-7.2
2477          fpresult := pos_inffp (fraction_width => fraction_width,
2478                                 exponent_width => exponent_width);
2479          fp_sign := l(l'high) xor r(r'high);        -- sign
2480          fpresult (fpresult'high) := fp_sign;  -- sign
2481        end if;
2482      when others =>
2483        classcase2 : case lfptype is
2484          when isx =>
2485            fpresult := (others => 'X');
2486          when nan | quiet_nan =>
2487            -- Return quiet NAN, IEEE754-1985-7.1,1
2488            fpresult := qnanfp (fraction_width => fraction_width,
2489                                exponent_width => exponent_width);
2490          when pos_inf | neg_inf =>     -- inf / x = inf
2491            fpresult := pos_inffp (fraction_width => fraction_width,
2492                                   exponent_width => exponent_width);
2493            fp_sign := l(l'high) xor r(r'high);        -- sign
2494            fpresult (exponent_width) := fp_sign;  -- sign
2495          when pos_zero | neg_zero =>   -- 0 / X = 0
2496            fpresult := zerofp (fraction_width => fraction_width,
2497                                exponent_width => exponent_width);
2498            fp_sign := l(l'high) xor r(r'high);        -- sign
2499            fpresult (exponent_width) := fp_sign;  -- sign
2500          when others =>
2501            fp_sign := l(l'high) xor r(r'high);        -- sign
2502            lresize := resize (arg            => to_x01(l),
2503                               exponent_width => exponent_width,
2504                               fraction_width => fraction_width,
2505                               denormalize_in => denormalize,
2506                               denormalize    => denormalize);
2507            lfptype := classfp (lresize, false);  -- errors already checked
2508            rresize := resize (arg            => to_x01(r),
2509                               exponent_width => exponent_width,
2510                               fraction_width => fraction_width,
2511                               denormalize_in => denormalize,
2512                               denormalize    => denormalize);
2513            rfptype := classfp (rresize, false);  -- errors already checked
2514            break_number (
2515              arg         => lresize,
2516              fptyp       => lfptype,
2517              denormalize => denormalize,
2518              fract       => ulfract,
2519              expon       => exponl);
2520            -- right side
2521            break_number (
2522              arg         => rresize,
2523              fptyp       => rfptype,
2524              denormalize => denormalize,
2525              fract       => urfract,
2526              expon       => exponr);
2527            assert (or_reduce (urfract (fraction_width-1 downto 0)) = '0')
2528              report float_pkg'instance_name
2529              & "DIVIDEBYP2: "
2530              & "Dividebyp2 called with a non power of two divisor"
2531              severity error;
2532            rexpon := (exponl(exponl'high)&exponl)
2533                      - (exponr(exponr'high)&exponr) - 1;
2534            -- normalize
2535            fpresult := normalize (fract          => ulfract,
2536                                   expon          => rexpon,
2537                                   sign           => fp_sign,
2538                                   sticky         => '1',
2539                                   fraction_width => fraction_width,
2540                                   exponent_width => exponent_width,
2541                                   round_style    => round_style,
2542                                   denormalize    => denormalize,
2543                                   nguard         => 0);
2544        end case classcase2;
2545    end case classcase;
2546    return fpresult;
2547  end function dividebyp2;
2548
2549  -- Multiply accumulate  result = l*r + c
2550  function mac (
2551    l, r, c              : UNRESOLVED_float;      -- floating point input
2552    constant round_style : round_type := float_round_style;  -- rounding option
2553    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
2554    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
2555    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
2556    return UNRESOLVED_float is
2557    constant fraction_width : NATURAL :=
2558      -mine (mine(l'low, r'low), c'low);   -- length of FP output fraction
2559    constant exponent_width : NATURAL :=
2560      maximum (maximum(l'high, r'high), c'high);  -- length of FP output exponent
2561    variable lfptype, rfptype, cfptype : valid_fpstate;
2562    variable fpresult                  : UNRESOLVED_float (exponent_width downto -fraction_width);
2563    variable fractl, fractr            : UNSIGNED (fraction_width downto 0);  -- fractions
2564    variable fractx                    : UNSIGNED (fraction_width+guard downto 0);
2565    variable fractc, fracts            : UNSIGNED (fraction_width+1+guard downto 0);
2566    variable rfract                    : UNSIGNED ((2*(fraction_width))+1 downto 0);  -- result fraction
2567    variable sfract, ufract            : UNSIGNED (fraction_width+1+guard downto 0);  -- result fraction
2568    variable exponl, exponr, exponc    : SIGNED (exponent_width-1 downto 0);  -- exponents
2569    variable rexpon, rexpon2           : SIGNED (exponent_width+1 downto 0);  -- result exponent
2570    variable shifty                    : INTEGER;      -- denormal shift
2571    variable shiftx                    : SIGNED (rexpon'range);  -- shift fractions
2572    variable fp_sign                   : STD_ULOGIC;  -- sign of result
2573    variable lresize, rresize          : UNRESOLVED_float (exponent_width downto -fraction_width);
2574    variable cresize                   : UNRESOLVED_float (exponent_width downto -fraction_width - guard);
2575    variable leftright                 : BOOLEAN;     -- left or right used
2576    variable sticky                    : STD_ULOGIC;  -- Holds precision for rounding
2577  begin  -- multiply
2578    if (fraction_width = 0 or l'length < 7 or r'length < 7 or c'length < 7) then
2579      lfptype := isx;
2580    else
2581      lfptype := classfp (l, check_error);
2582      rfptype := classfp (r, check_error);
2583      cfptype := classfp (c, check_error);
2584    end if;
2585    if (lfptype = isx or rfptype = isx or cfptype = isx) then
2586      fpresult := (others => 'X');
2587    elsif (lfptype = nan or lfptype = quiet_nan or
2588           rfptype = nan or rfptype = quiet_nan or
2589           cfptype = nan or cfptype = quiet_nan) then
2590      -- Return quiet NAN, IEEE754-1985-7.1,1
2591      fpresult := qnanfp (fraction_width => fraction_width,
2592                          exponent_width => exponent_width);
2593    elsif (((lfptype = pos_inf or lfptype = neg_inf) and
2594            (rfptype = pos_zero or rfptype = neg_zero)) or
2595           ((rfptype = pos_inf or rfptype = neg_inf) and
2596            (lfptype = pos_zero or lfptype = neg_zero))) then  -- 0 * inf
2597      -- Return quiet NAN, IEEE754-1985-7.1,3
2598      fpresult := qnanfp (fraction_width => fraction_width,
2599                          exponent_width => exponent_width);
2600    elsif (lfptype = pos_inf or rfptype = pos_inf
2601           or lfptype = neg_inf or rfptype = neg_inf  -- x * inf = inf
2602           or cfptype = neg_inf or cfptype = pos_inf) then  -- x + inf = inf
2603      fpresult := pos_inffp (fraction_width => fraction_width,
2604                             exponent_width => exponent_width);
2605      -- figure out the sign
2606      fpresult (exponent_width) := l(l'high) xor r(r'high);
2607    else
2608      fp_sign := l(l'high) xor r(r'high);  -- figure out the sign
2609      lresize := resize (arg            => to_x01(l),
2610                         exponent_width => exponent_width,
2611                         fraction_width => fraction_width,
2612                         denormalize_in => denormalize,
2613                         denormalize    => denormalize);
2614      lfptype := classfp (lresize, false);        -- errors already checked
2615      rresize := resize (arg            => to_x01(r),
2616                         exponent_width => exponent_width,
2617                         fraction_width => fraction_width,
2618                         denormalize_in => denormalize,
2619                         denormalize    => denormalize);
2620      rfptype := classfp (rresize, false);        -- errors already checked
2621      cresize := resize (arg            => to_x01(c),
2622                         exponent_width => exponent_width,
2623                         fraction_width => -cresize'low,
2624                         denormalize_in => denormalize,
2625                         denormalize    => denormalize);
2626      cfptype := classfp (cresize, false);        -- errors already checked
2627      break_number (
2628        arg         => lresize,
2629        fptyp       => lfptype,
2630        denormalize => denormalize,
2631        fract       => fractl,
2632        expon       => exponl);
2633      break_number (
2634        arg         => rresize,
2635        fptyp       => rfptype,
2636        denormalize => denormalize,
2637        fract       => fractr,
2638        expon       => exponr);
2639      break_number (
2640        arg         => cresize,
2641        fptyp       => cfptype,
2642        denormalize => denormalize,
2643        fract       => fractx,
2644        expon       => exponc);
2645      if (rfptype = pos_denormal or rfptype = neg_denormal) then
2646        shifty := fraction_width - find_leftmost(fractr, '1');
2647        fractr := shift_left (fractr, shifty);
2648      elsif (lfptype = pos_denormal or lfptype = neg_denormal) then
2649        shifty := fraction_width - find_leftmost(fractl, '1');
2650        fractl := shift_left (fractl, shifty);
2651      else
2652        shifty := 0;
2653        -- Note that a denormal number * a denormal number is always zero.
2654      end if;
2655      -- multiply
2656      rfract := fractl * fractr;        -- Multiply the fraction
2657      -- add the exponents
2658      rexpon := resize (exponl, rexpon'length) + exponr - shifty + 1;
2659      shiftx := rexpon - exponc;
2660      if shiftx < -fractl'high then
2661        rexpon2 := resize (exponc, rexpon2'length);
2662        fractc  := "0" & fractx;
2663        fracts  := (others => '0');
2664        sticky  := or_reduce (rfract);
2665      elsif shiftx < 0 then
2666        shiftx := - shiftx;
2667        fracts := shift_right (rfract (rfract'high downto rfract'high
2668                                       - fracts'length+1),
2669                               to_integer(shiftx));
2670        fractc    := "0" & fractx;
2671        rexpon2   := resize (exponc, rexpon2'length);
2672        leftright := false;
2673        sticky := or_reduce (rfract (to_integer(shiftx)+rfract'high
2674                                     - fracts'length downto 0));
2675      elsif shiftx = 0 then
2676        rexpon2 := resize (exponc, rexpon2'length);
2677        sticky  := or_reduce (rfract (rfract'high - fractc'length downto 0));
2678        if rfract (rfract'high downto rfract'high - fractc'length+1) > fractx
2679        then
2680          fractc := "0" & fractx;
2681          fracts := rfract (rfract'high downto rfract'high
2682                            - fracts'length+1);
2683          leftright := false;
2684        else
2685          fractc := rfract (rfract'high downto rfract'high
2686                            - fractc'length+1);
2687          fracts    := "0" & fractx;
2688          leftright := true;
2689        end if;
2690      elsif shiftx > fractx'high then
2691        rexpon2   := rexpon;
2692        fracts    := (others => '0');
2693        fractc    := rfract (rfract'high downto rfract'high - fractc'length+1);
2694        leftright := true;
2695        sticky := or_reduce (fractx & rfract (rfract'high - fractc'length
2696                                              downto 0));
2697      else                              -- fractx'high > shiftx > 0
2698        rexpon2   := rexpon;
2699        fracts    := "0" & shift_right (fractx, to_integer (shiftx));
2700        fractc    := rfract (rfract'high downto rfract'high - fractc'length+1);
2701        leftright := true;
2702        sticky := or_reduce (fractx (to_integer (shiftx) downto 0)
2703                             & rfract (rfract'high - fractc'length downto 0));
2704      end if;
2705      fracts (0) := fracts (0) or sticky;  -- Or the sticky bit into the LSB
2706      if fp_sign = to_X01(c(c'high)) then
2707        ufract  := fractc + fracts;
2708        fp_sign := fp_sign;
2709      else                              -- signs are different
2710        ufract := fractc - fracts;      -- always positive result
2711        if leftright then               -- Figure out which sign to use
2712          fp_sign := fp_sign;
2713        else
2714          fp_sign := c(c'high);
2715        end if;
2716      end if;
2717      -- normalize
2718      fpresult := normalize (fract          => ufract,
2719                             expon          => rexpon2,
2720                             sign           => fp_sign,
2721                             sticky         => sticky,
2722                             fraction_width => fraction_width,
2723                             exponent_width => exponent_width,
2724                             round_style    => round_style,
2725                             denormalize    => denormalize,
2726                             nguard         => guard);
2727    end if;
2728    return fpresult;
2729  end function mac;
2730
2731  -- "rem" function
2732  function remainder (
2733    l, r                 : UNRESOLVED_float;       -- floating point input
2734    constant round_style : round_type := float_round_style;  -- rounding option
2735    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
2736    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
2737    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
2738    return UNRESOLVED_float is
2739    constant fraction_width   : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
2740    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
2741    constant divguard         : NATURAL := guard;  -- division guard bits
2742    variable lfptype, rfptype : valid_fpstate;
2743    variable fpresult         : UNRESOLVED_float (exponent_width downto -fraction_width);
2744    variable ulfract, urfract : UNSIGNED (fraction_width downto 0);
2745    variable fractr, fractl   : UNSIGNED (fraction_width+divguard downto 0);  -- right
2746    variable rfract           : UNSIGNED (fractr'range);    -- result fraction
2747    variable sfract           : UNSIGNED (fraction_width+divguard downto 0);  -- result fraction
2748    variable exponl, exponr   : SIGNED (exponent_width-1 downto 0);  -- exponents
2749    variable rexpon           : SIGNED (exponent_width downto 0);  -- result exponent
2750    variable fp_sign          : STD_ULOGIC;        -- sign of result
2751    variable shifty           : INTEGER;           -- denormal number shift
2752    variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width);
2753  begin  -- remainder
2754    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
2755      lfptype := isx;
2756    else
2757      lfptype := classfp (l, check_error);
2758      rfptype := classfp (r, check_error);
2759    end if;
2760    if (lfptype = isx or rfptype = isx) then
2761      fpresult := (others => 'X');
2762    elsif (lfptype = nan or lfptype = quiet_nan)
2763      or (rfptype = nan or rfptype = quiet_nan)
2764      -- Return quiet NAN, IEEE754-1985-7.1,1
2765      or (lfptype = pos_inf or lfptype = neg_inf)  -- inf rem x
2766      -- Return quiet NAN, IEEE754-1985-7.1,5
2767      or (rfptype = pos_zero or rfptype = neg_zero) then    -- x rem 0
2768      -- Return quiet NAN, IEEE754-1985-7.1,5
2769      fpresult := qnanfp (fraction_width => fraction_width,
2770                          exponent_width => exponent_width);
2771    elsif (rfptype = pos_inf or rfptype = neg_inf) then     -- x rem inf = 0
2772      fpresult := zerofp (fraction_width => fraction_width,
2773                          exponent_width => exponent_width);
2774    elsif (abs(l) < abs(r)) then
2775      fpresult := l;
2776    else
2777      fp_sign := to_X01(l(l'high));     -- sign
2778      lresize := resize (arg            => to_x01(l),
2779                         exponent_width => exponent_width,
2780                         fraction_width => fraction_width,
2781                         denormalize_in => denormalize,
2782                         denormalize    => denormalize);
2783      lfptype := classfp (lresize, false);         -- errors already checked
2784      rresize := resize (arg            => to_x01(r),
2785                         exponent_width => exponent_width,
2786                         fraction_width => fraction_width,
2787                         denormalize_in => denormalize,
2788                         denormalize    => denormalize);
2789      rfptype := classfp (rresize, false);         -- errors already checked
2790      fractl  := (others => '0');
2791      break_number (
2792        arg         => lresize,
2793        fptyp       => lfptype,
2794        denormalize => denormalize,
2795        fract       => ulfract,
2796        expon       => exponl);
2797      fractl (fraction_width+divguard downto divguard) := ulfract;
2798      -- right side
2799      fractr := (others => '0');
2800      break_number (
2801        arg         => rresize,
2802        fptyp       => rfptype,
2803        denormalize => denormalize,
2804        fract       => urfract,
2805        expon       => exponr);
2806      fractr (fraction_width+divguard downto divguard) := urfract;
2807      rexpon := (exponr(exponr'high)&exponr);
2808      shifty := to_integer(exponl - rexpon);
2809      if (shifty > 0) then
2810        fractr := shift_right (fractr, shifty);
2811        rexpon := rexpon + shifty;
2812      end if;
2813      if (fractr /= 0) then
2814        -- rem
2815        rfract := fractl rem fractr;    -- unsigned rem
2816        sfract := rfract (sfract'range);           -- lower bits
2817        -- normalize
2818        fpresult := normalize (fract          => sfract,
2819                               expon          => rexpon,
2820                               sign           => fp_sign,
2821                               fraction_width => fraction_width,
2822                               exponent_width => exponent_width,
2823                               round_style    => round_style,
2824                               denormalize    => denormalize,
2825                               nguard         => divguard);
2826      else
2827        -- If we shift "fractr" so far that it becomes zero, return zero.
2828        fpresult := zerofp (fraction_width => fraction_width,
2829                            exponent_width => exponent_width);
2830      end if;
2831    end if;
2832    return fpresult;
2833  end function remainder;
2834
2835  -- "mod" function
2836  function modulo (
2837    l, r                 : UNRESOLVED_float;  -- floating point input
2838    constant round_style : round_type := float_round_style;  -- rounding option
2839    constant guard       : NATURAL    := float_guard_bits;  -- number of guard bits
2840    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
2841    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
2842    return UNRESOLVED_float is
2843    constant fraction_width   : NATURAL := - mine(l'low, r'low);  -- length of FP output fraction
2844    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
2845    variable lfptype, rfptype : valid_fpstate;
2846    variable fpresult         : UNRESOLVED_float (exponent_width downto -fraction_width);
2847    variable remres           : UNRESOLVED_float (exponent_width downto -fraction_width);
2848  begin  -- remainder
2849    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
2850      lfptype := isx;
2851    else
2852      lfptype := classfp (l, check_error);
2853      rfptype := classfp (r, check_error);
2854    end if;
2855    if (lfptype = isx or rfptype = isx) then
2856      fpresult := (others => 'X');
2857    elsif (lfptype = nan or lfptype = quiet_nan)
2858      or (rfptype = nan or rfptype = quiet_nan)
2859      -- Return quiet NAN, IEEE754-1985-7.1,1
2860      or (lfptype = pos_inf or lfptype = neg_inf)           -- inf rem x
2861      -- Return quiet NAN, IEEE754-1985-7.1,5
2862      or (rfptype = pos_zero or rfptype = neg_zero) then    -- x rem 0
2863      -- Return quiet NAN, IEEE754-1985-7.1,5
2864      fpresult := qnanfp (fraction_width => fraction_width,
2865                          exponent_width => exponent_width);
2866    elsif (rfptype = pos_inf or rfptype = neg_inf) then     -- x rem inf = 0
2867      fpresult := zerofp (fraction_width => fraction_width,
2868                          exponent_width => exponent_width);
2869    else
2870      remres := remainder (l           => abs(l),
2871                           r           => abs(r),
2872                           round_style => round_style,
2873                           guard       => guard,
2874                           check_error => false,
2875                           denormalize => denormalize);
2876      -- MOD is the same as REM, but you do something different with
2877      -- negative values
2878      if (is_negative (l)) then
2879        remres := - remres;
2880      end if;
2881      if (is_negative (l) = is_negative (r) or remres = 0) then
2882        fpresult := remres;
2883      else
2884        fpresult := add (l           => remres,
2885                         r           => r,
2886                         round_style => round_style,
2887                         guard       => guard,
2888                         check_error => false,
2889                         denormalize => denormalize);
2890      end if;
2891    end if;
2892    return fpresult;
2893  end function modulo;
2894
2895  -- Square root of a floating point number.  Done using Newton's Iteration.
2896  function sqrt (
2897    arg                  : UNRESOLVED_float;        -- floating point input
2898    constant round_style : round_type := float_round_style;
2899    constant guard       : NATURAL    := float_guard_bits;
2900    constant check_error : BOOLEAN    := float_check_error;
2901    constant denormalize : BOOLEAN    := float_denormalize)
2902    return UNRESOLVED_float is
2903    constant fraction_width : NATURAL := guard-arg'low;  -- length of FP output fraction
2904    constant exponent_width : NATURAL := arg'high;  -- length of FP output exponent
2905    variable sign           : STD_ULOGIC;
2906    variable fpresult       : float (arg'range);
2907    variable fptype         : valid_fpstate;
2908    variable iexpon         : SIGNED(exponent_width-1 downto 0);  -- exponents
2909    variable expon          : SIGNED(exponent_width downto 0);    -- exponents
2910    variable ufact          : ufixed (0 downto arg'low);
2911    variable fact           : ufixed (2 downto -fraction_width);  -- fraction
2912    variable resb           : ufixed (fact'high+1 downto fact'low);
2913  begin  -- square root
2914    fptype := Classfp (arg, check_error);
2915    classcase : case fptype is
2916      when isx =>
2917        fpresult := (others => 'X');
2918      when nan | quiet_nan |
2919        -- Return quiet NAN, IEEE754-1985-7.1,1
2920        neg_normal | neg_denormal | neg_inf =>      -- sqrt (neg)
2921        -- Return quiet NAN, IEEE754-1985-7.1.6
2922        fpresult := qnanfp (fraction_width => fraction_width-guard,
2923                            exponent_width => exponent_width);
2924      when pos_inf =>                   -- Sqrt (inf), return infinity
2925        fpresult := pos_inffp (fraction_width => fraction_width-guard,
2926                               exponent_width => exponent_width);
2927      when pos_zero =>                  -- return 0
2928        fpresult := zerofp (fraction_width => fraction_width-guard,
2929                            exponent_width => exponent_width);
2930      when neg_zero =>                  -- IEEE754-1985-6.3 return -0
2931        fpresult := neg_zerofp (fraction_width => fraction_width-guard,
2932                                exponent_width => exponent_width);
2933      when others =>
2934        break_number (arg         => arg,
2935                      denormalize => denormalize,
2936                      check_error => false,
2937                      fract       => ufact,
2938                      expon       => iexpon,
2939                      sign        => sign);
2940        expon := resize (iexpon+1, expon'length);   -- get exponent
2941        fact  := resize (ufact, fact'high, fact'low);
2942        if (expon(0) = '1') then
2943          fact := fact sla 1;           -- * 2.0
2944        end if;
2945        expon := shift_right (expon, 1);            -- exponent/2
2946        -- Newton's iteration - root := (1 + arg) / 2
2947        resb  := (fact + 1) sra 1;
2948        for j in 0 to fraction_width/4 loop
2949          --   root := (root + (arg/root))/2
2950          resb := resize (arg            => (resb + (fact/resb)) sra 1,
2951                          left_index     => resb'high,
2952                          right_index    => resb'low,
2953                          round_style    => fixed_truncate,
2954                          overflow_style => fixed_wrap);
2955        end loop;
2956        fpresult := normalize (fract          => resb,
2957                               expon          => expon-1,
2958                               sign           => '0',
2959                               exponent_width => arg'high,
2960                               fraction_width => -arg'low,
2961                               round_style    => round_style,
2962                               denormalize    => denormalize,
2963                               nguard         => guard);
2964    end case classcase;
2965    return fpresult;
2966  end function sqrt;
2967
2968  function Is_Negative (arg : UNRESOLVED_float) return BOOLEAN is
2969    -- Technically -0 should return "false", but I'm leaving that case out.
2970  begin
2971    return (to_x01(arg(arg'high)) = '1');
2972  end function Is_Negative;
2973
2974  -- compare functions
2975  -- =, /=, >=, <=, <, >
2976
2977  function eq (                         -- equal =
2978    l, r                 : UNRESOLVED_float;  -- floating point input
2979    constant check_error : BOOLEAN := float_check_error;
2980    constant denormalize : BOOLEAN := float_denormalize)
2981    return BOOLEAN is
2982    variable lfptype, rfptype       : valid_fpstate;
2983    variable is_equal, is_unordered : BOOLEAN;
2984    constant fraction_width         : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
2985    constant exponent_width         : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
2986    variable lresize, rresize       : UNRESOLVED_float (exponent_width downto -fraction_width);
2987  begin  -- equal
2988    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
2989      return false;
2990    else
2991      lfptype := classfp (l, check_error);
2992      rfptype := classfp (r, check_error);
2993    end if;
2994    if (lfptype = neg_zero or lfptype = pos_zero) and
2995      (rfptype = neg_zero or rfptype = pos_zero) then
2996      is_equal := true;
2997    else
2998      lresize := resize (arg            => to_x01(l),
2999                         exponent_width => exponent_width,
3000                         fraction_width => fraction_width,
3001                         denormalize_in => denormalize,
3002                         denormalize    => denormalize);
3003      rresize := resize (arg            => to_x01(r),
3004                         exponent_width => exponent_width,
3005                         fraction_width => fraction_width,
3006                         denormalize_in => denormalize,
3007                         denormalize    => denormalize);
3008      is_equal := (to_slv(lresize) = to_slv(rresize));
3009    end if;
3010    if (check_error) then
3011      is_unordered := Unordered (x => l,
3012                                 y => r);
3013    else
3014      is_unordered := false;
3015    end if;
3016    return is_equal and not is_unordered;
3017  end function eq;
3018
3019  function lt (                         -- less than <
3020    l, r                 : UNRESOLVED_float;         -- floating point input
3021    constant check_error : BOOLEAN := float_check_error;
3022    constant denormalize : BOOLEAN := float_denormalize)
3023    return BOOLEAN is
3024    constant fraction_width             : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
3025    constant exponent_width             : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
3026    variable lfptype, rfptype           : valid_fpstate;
3027    variable expl, expr                 : UNSIGNED (exponent_width-1 downto 0);
3028    variable fractl, fractr             : UNSIGNED (fraction_width-1 downto 0);
3029    variable is_less_than, is_unordered : BOOLEAN;
3030    variable lresize, rresize           : UNRESOLVED_float (exponent_width downto -fraction_width);
3031  begin
3032    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
3033      is_less_than := false;
3034    else
3035      lresize := resize (arg            => to_x01(l),
3036                         exponent_width => exponent_width,
3037                         fraction_width => fraction_width,
3038                         denormalize_in => denormalize,
3039                         denormalize    => denormalize);
3040      rresize := resize (arg            => to_x01(r),
3041                         exponent_width => exponent_width,
3042                         fraction_width => fraction_width,
3043                         denormalize_in => denormalize,
3044                         denormalize    => denormalize);
3045      if to_x01(l(l'high)) = to_x01(r(r'high)) then  -- sign bits
3046        expl := UNSIGNED(lresize(exponent_width-1 downto 0));
3047        expr := UNSIGNED(rresize(exponent_width-1 downto 0));
3048        if expl = expr then
3049          fractl := UNSIGNED (to_slv(lresize(-1 downto -fraction_width)));
3050          fractr := UNSIGNED (to_slv(rresize(-1 downto -fraction_width)));
3051          if to_x01(l(l'high)) = '0' then            -- positive number
3052            is_less_than := (fractl < fractr);
3053          else
3054            is_less_than := (fractl > fractr);       -- negative
3055          end if;
3056        else
3057          if to_x01(l(l'high)) = '0' then            -- positive number
3058            is_less_than := (expl < expr);
3059          else
3060            is_less_than := (expl > expr);           -- negative
3061          end if;
3062        end if;
3063      else
3064        lfptype := classfp (l, check_error);
3065        rfptype := classfp (r, check_error);
3066        if (lfptype = neg_zero and rfptype = pos_zero) then
3067          is_less_than := false;        -- -0 < 0 returns false.
3068        else
3069          is_less_than := (to_x01(l(l'high)) > to_x01(r(r'high)));
3070        end if;
3071      end if;
3072    end if;
3073    if check_error then
3074      is_unordered := Unordered (x => l,
3075                                 y => r);
3076    else
3077      is_unordered := false;
3078    end if;
3079    return is_less_than and not is_unordered;
3080  end function lt;
3081
3082  function gt (                         -- greater than >
3083    l, r                 : UNRESOLVED_float;  -- floating point input
3084    constant check_error : BOOLEAN := float_check_error;
3085    constant denormalize : BOOLEAN := float_denormalize)
3086    return BOOLEAN is
3087    constant fraction_width   : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
3088    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
3089    variable lfptype, rfptype : valid_fpstate;
3090    variable expl, expr       : UNSIGNED (exponent_width-1 downto 0);
3091    variable fractl, fractr   : UNSIGNED (fraction_width-1 downto 0);
3092    variable is_greater_than  : BOOLEAN;
3093    variable is_unordered     : BOOLEAN;
3094    variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width);
3095  begin  -- greater_than
3096    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
3097      is_greater_than := false;
3098    else
3099      lresize := resize (arg            => to_x01(l),
3100                         exponent_width => exponent_width,
3101                         fraction_width => fraction_width,
3102                         denormalize_in => denormalize,
3103                         denormalize    => denormalize);
3104      rresize := resize (arg            => to_x01(r),
3105                         exponent_width => exponent_width,
3106                         fraction_width => fraction_width,
3107                         denormalize_in => denormalize,
3108                         denormalize    => denormalize);
3109      if to_x01(l(l'high)) = to_x01(r(r'high)) then              -- sign bits
3110        expl := UNSIGNED(lresize(exponent_width-1 downto 0));
3111        expr := UNSIGNED(rresize(exponent_width-1 downto 0));
3112        if expl = expr then
3113          fractl := UNSIGNED (to_slv(lresize(-1 downto -fraction_width)));
3114          fractr := UNSIGNED (to_slv(rresize(-1 downto -fraction_width)));
3115          if to_x01(l(l'high)) = '0' then     -- positive number
3116            is_greater_than := fractl > fractr;
3117          else
3118            is_greater_than := fractl < fractr;                  -- negative
3119          end if;
3120        else
3121          if to_x01(l(l'high)) = '0' then     -- positive number
3122            is_greater_than := expl > expr;
3123          else
3124            is_greater_than := expl < expr;   -- negative
3125          end if;
3126        end if;
3127      else
3128        lfptype := classfp (l, check_error);
3129        rfptype := classfp (r, check_error);
3130        if (lfptype = pos_zero and rfptype = neg_zero) then
3131          is_greater_than := false;     -- 0 > -0 returns false.
3132        else
3133          is_greater_than := to_x01(l(l'high)) < to_x01(r(r'high));
3134        end if;
3135      end if;
3136    end if;
3137    if check_error then
3138      is_unordered := Unordered (x => l,
3139                                 y => r);
3140    else
3141      is_unordered := false;
3142    end if;
3143    return is_greater_than and not is_unordered;
3144  end function gt;
3145
3146  -- purpose: /= function
3147  function ne (                         -- not equal /=
3148    l, r                 : UNRESOLVED_float;
3149    constant check_error : BOOLEAN := float_check_error;
3150    constant denormalize : BOOLEAN := float_denormalize)
3151    return BOOLEAN is
3152    variable is_equal, is_unordered : BOOLEAN;
3153  begin
3154    is_equal := eq (l           => l,
3155                    r           => r,
3156                    check_error => false,
3157                    denormalize => denormalize);
3158    if check_error then
3159      is_unordered := Unordered (x => l,
3160                                 y => r);
3161    else
3162      is_unordered := false;
3163    end if;
3164    return not (is_equal and not is_unordered);
3165  end function ne;
3166
3167  function le (                               -- less than or equal to <=
3168    l, r                 : UNRESOLVED_float;  -- floating point input
3169    constant check_error : BOOLEAN := float_check_error;
3170    constant denormalize : BOOLEAN := float_denormalize)
3171    return BOOLEAN is
3172    variable is_greater_than, is_unordered : BOOLEAN;
3173  begin
3174    is_greater_than := gt (l           => l,
3175                           r           => r,
3176                           check_error => false,
3177                           denormalize => denormalize);
3178    if check_error then
3179      is_unordered := Unordered (x => l,
3180                                 y => r);
3181    else
3182      is_unordered := false;
3183    end if;
3184    return not is_greater_than and not is_unordered;
3185  end function le;
3186
3187  function ge (                               -- greater than or equal to >=
3188    l, r                 : UNRESOLVED_float;  -- floating point input
3189    constant check_error : BOOLEAN := float_check_error;
3190    constant denormalize : BOOLEAN := float_denormalize)
3191    return BOOLEAN is
3192    variable is_less_than, is_unordered : BOOLEAN;
3193  begin
3194    is_less_than := lt (l           => l,
3195                        r           => r,
3196                        check_error => false,
3197                        denormalize => denormalize);
3198    if check_error then
3199      is_unordered := Unordered (x => l,
3200                                 y => r);
3201    else
3202      is_unordered := false;
3203    end if;
3204    return not is_less_than and not is_unordered;
3205  end function ge;
3206
3207  function \?=\ (L, R : UNRESOLVED_float) return STD_ULOGIC is
3208    constant fraction_width         : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
3209    constant exponent_width         : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
3210    variable lfptype, rfptype       : valid_fpstate;
3211    variable is_equal, is_unordered : STD_ULOGIC;
3212    variable lresize, rresize       : UNRESOLVED_float (exponent_width downto -fraction_width);
3213  begin  -- ?=
3214    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
3215      return 'X';
3216    else
3217      lfptype := classfp (l, float_check_error);
3218      rfptype := classfp (r, float_check_error);
3219    end if;
3220    if (lfptype = neg_zero or lfptype = pos_zero) and
3221      (rfptype = neg_zero or rfptype = pos_zero) then
3222      is_equal := '1';
3223    else
3224      lresize := resize (arg            => l,
3225                         exponent_width => exponent_width,
3226                         fraction_width => fraction_width,
3227                         denormalize_in => float_denormalize,
3228                         denormalize    => float_denormalize);
3229      rresize := resize (arg            => r,
3230                         exponent_width => exponent_width,
3231                         fraction_width => fraction_width,
3232                         denormalize_in => float_denormalize,
3233                         denormalize    => float_denormalize);
3234      is_equal := \?=\ (to_sulv(lresize), to_sulv(rresize));
3235    end if;
3236    if (float_check_error) then
3237      if (lfptype = nan or lfptype = quiet_nan or
3238          rfptype = nan or rfptype = quiet_nan) then
3239        is_unordered := '1';
3240      else
3241        is_unordered := '0';
3242      end if;
3243    else
3244      is_unordered := '0';
3245    end if;
3246    return is_equal and not is_unordered;
3247  end function \?=\;
3248
3249  function \?/=\ (L, R : UNRESOLVED_float) return STD_ULOGIC is
3250    constant fraction_width         : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
3251    constant exponent_width         : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
3252    variable lfptype, rfptype       : valid_fpstate;
3253    variable is_equal, is_unordered : STD_ULOGIC;
3254    variable lresize, rresize       : UNRESOLVED_float (exponent_width downto -fraction_width);
3255  begin  -- ?/=
3256    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
3257      return 'X';
3258    else
3259      lfptype := classfp (l, float_check_error);
3260      rfptype := classfp (r, float_check_error);
3261    end if;
3262    if (lfptype = neg_zero or lfptype = pos_zero) and
3263      (rfptype = neg_zero or rfptype = pos_zero) then
3264      is_equal := '1';
3265    else
3266      lresize := resize (arg            => l,
3267                         exponent_width => exponent_width,
3268                         fraction_width => fraction_width,
3269                         denormalize_in => float_denormalize,
3270                         denormalize    => float_denormalize);
3271      rresize := resize (arg            => r,
3272                         exponent_width => exponent_width,
3273                         fraction_width => fraction_width,
3274                         denormalize_in => float_denormalize,
3275                         denormalize    => float_denormalize);
3276      is_equal := \?=\ (to_sulv(lresize), to_sulv(rresize));
3277    end if;
3278    if (float_check_error) then
3279      if (lfptype = nan or lfptype = quiet_nan or
3280          rfptype = nan or rfptype = quiet_nan) then
3281        is_unordered := '1';
3282      else
3283        is_unordered := '0';
3284      end if;
3285    else
3286      is_unordered := '0';
3287    end if;
3288    return not (is_equal and not is_unordered);
3289  end function \?/=\;
3290
3291  function \?>\ (L, R : UNRESOLVED_float) return STD_ULOGIC is
3292    constant fraction_width : NATURAL := -mine(l'low, r'low);
3293    variable founddash      : BOOLEAN := false;
3294  begin
3295    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
3296      return 'X';
3297    else
3298      for i in L'range loop
3299        if L(i) = '-' then
3300          founddash := true;
3301        end if;
3302      end loop;
3303      for i in R'range loop
3304        if R(i) = '-' then
3305          founddash := true;
3306        end if;
3307      end loop;
3308      if founddash then
3309        report float_pkg'instance_name
3310          & " ""?>"": '-' found in compare string"
3311          severity error;
3312        return 'X';
3313      elsif is_x(l) or is_x(r) then
3314        return 'X';
3315      elsif l > r then
3316        return '1';
3317      else
3318        return '0';
3319      end if;
3320    end if;
3321  end function \?>\;
3322
3323  function \?>=\ (L, R : UNRESOLVED_float) return STD_ULOGIC is
3324    constant fraction_width : NATURAL := -mine(l'low, r'low);
3325    variable founddash      : BOOLEAN := false;
3326  begin
3327    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
3328      return 'X';
3329    else
3330      for i in L'range loop
3331        if L(i) = '-' then
3332          founddash := true;
3333        end if;
3334      end loop;
3335      for i in R'range loop
3336        if R(i) = '-' then
3337          founddash := true;
3338        end if;
3339      end loop;
3340      if founddash then
3341        report float_pkg'instance_name
3342          & " ""?>="": '-' found in compare string"
3343          severity error;
3344        return 'X';
3345      elsif is_x(l) or is_x(r) then
3346        return 'X';
3347      elsif l >= r then
3348        return '1';
3349      else
3350        return '0';
3351      end if;
3352    end if;
3353  end function \?>=\;
3354
3355  function \?<\ (L, R : UNRESOLVED_float) return STD_ULOGIC is
3356    constant fraction_width : NATURAL := -mine(l'low, r'low);
3357    variable founddash      : BOOLEAN := false;
3358  begin
3359    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
3360      return 'X';
3361    else
3362      for i in L'range loop
3363        if L(i) = '-' then
3364          founddash := true;
3365        end if;
3366      end loop;
3367      for i in R'range loop
3368        if R(i) = '-' then
3369          founddash := true;
3370        end if;
3371      end loop;
3372      if founddash then
3373        report float_pkg'instance_name
3374          & " ""?<"": '-' found in compare string"
3375          severity error;
3376        return 'X';
3377      elsif is_x(l) or is_x(r) then
3378        return 'X';
3379      elsif l < r then
3380        return '1';
3381      else
3382        return '0';
3383      end if;
3384    end if;
3385  end function \?<\;
3386
3387  function \?<=\ (L, R : UNRESOLVED_float) return STD_ULOGIC is
3388    constant fraction_width : NATURAL := -mine(l'low, r'low);
3389    variable founddash      : BOOLEAN := false;
3390  begin
3391    if (fraction_width = 0 or l'length < 7 or r'length < 7) then
3392      return 'X';
3393    else
3394      for i in L'range loop
3395        if L(i) = '-' then
3396          founddash := true;
3397        end if;
3398      end loop;
3399      for i in R'range loop
3400        if R(i) = '-' then
3401          founddash := true;
3402        end if;
3403      end loop;
3404      if founddash then
3405        report float_pkg'instance_name
3406          & " ""?<="": '-' found in compare string"
3407          severity error;
3408        return 'X';
3409      elsif is_x(l) or is_x(r) then
3410        return 'X';
3411      elsif l <= r then
3412        return '1';
3413      else
3414        return '0';
3415      end if;
3416    end if;
3417  end function \?<=\;
3418
3419  function std_match (L, R : UNRESOLVED_float) return BOOLEAN is
3420  begin
3421    if (L'high = R'high and L'low = R'low) then
3422      return std_match(to_sulv(L), to_sulv(R));
3423    else
3424      report float_pkg'instance_name
3425        & "STD_MATCH: L'RANGE /= R'RANGE, returning FALSE"
3426        severity warning;
3427      return false;
3428    end if;
3429  end function std_match;
3430
3431  function find_rightmost (arg : UNRESOLVED_float; y : STD_ULOGIC) return INTEGER is
3432  begin
3433    for_loop : for i in arg'reverse_range loop
3434      if \?=\ (arg(i), y) = '1' then
3435        return i;
3436      end if;
3437    end loop;
3438    return arg'high+1;                  -- return out of bounds 'high
3439  end function find_rightmost;
3440
3441  function find_leftmost (arg : UNRESOLVED_float; y : STD_ULOGIC) return INTEGER is
3442  begin
3443    for_loop : for i in arg'range loop
3444      if \?=\ (arg(i), y) = '1' then
3445        return i;
3446      end if;
3447    end loop;
3448    return arg'low-1;                   -- return out of bounds 'low
3449  end function find_leftmost;
3450
3451  -- These override the defaults for the compare operators.
3452  function "=" (l, r : UNRESOLVED_float) return BOOLEAN is
3453  begin
3454    return eq(l, r);
3455  end function "=";
3456
3457  function "/=" (l, r : UNRESOLVED_float) return BOOLEAN is
3458  begin
3459    return ne(l, r);
3460  end function "/=";
3461
3462  function ">=" (l, r : UNRESOLVED_float) return BOOLEAN is
3463  begin
3464    return ge(l, r);
3465  end function ">=";
3466
3467  function "<=" (l, r : UNRESOLVED_float) return BOOLEAN is
3468  begin
3469    return le(l, r);
3470  end function "<=";
3471
3472  function ">" (l, r : UNRESOLVED_float) return BOOLEAN is
3473  begin
3474    return gt(l, r);
3475  end function ">";
3476
3477  function "<" (l, r : UNRESOLVED_float) return BOOLEAN is
3478  begin
3479    return lt(l, r);
3480  end function "<";
3481
3482  -- purpose: maximum of two numbers (overrides default)
3483  function maximum (
3484    L, R : UNRESOLVED_float)
3485    return UNRESOLVED_float is
3486    constant fraction_width   : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
3487    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
3488    variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width);
3489  begin
3490    if ((L'length < 1) or (R'length < 1)) then return NAFP;
3491    end if;
3492    lresize := resize (l, exponent_width, fraction_width);
3493    rresize := resize (r, exponent_width, fraction_width);
3494    if lresize > rresize then return lresize;
3495    else return rresize;
3496    end if;
3497  end function maximum;
3498
3499  function minimum (
3500    L, R : UNRESOLVED_float)
3501    return UNRESOLVED_float is
3502    constant fraction_width   : NATURAL := -mine(l'low, r'low);  -- length of FP output fraction
3503    constant exponent_width   : NATURAL := maximum(l'high, r'high);  -- length of FP output exponent
3504    variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width);
3505  begin
3506    if ((L'length < 1) or (R'length < 1)) then return NAFP;
3507    end if;
3508    lresize := resize (l, exponent_width, fraction_width);
3509    rresize := resize (r, exponent_width, fraction_width);
3510    if lresize > rresize then return rresize;
3511    else return lresize;
3512    end if;
3513  end function minimum;
3514
3515  -----------------------------------------------------------------------------
3516  -- conversion functions
3517  -----------------------------------------------------------------------------
3518
3519  -- Converts a floating point number of one format into another format
3520  function resize (
3521    arg                     : UNRESOLVED_float;        -- Floating point input
3522    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
3523    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
3524    constant round_style    : round_type := float_round_style;  -- rounding option
3525    constant check_error    : BOOLEAN    := float_check_error;
3526    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
3527    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
3528    return UNRESOLVED_float is
3529    constant in_fraction_width : NATURAL := -arg'low;  -- length of FP output fraction
3530    constant in_exponent_width : NATURAL := arg'high;  -- length of FP output exponent
3531    variable result            : UNRESOLVED_float (exponent_width downto -fraction_width);
3532                                        -- result value
3533    variable fptype            : valid_fpstate;
3534    variable expon_in          : SIGNED (in_exponent_width-1 downto 0);
3535    variable fract_in          : UNSIGNED (in_fraction_width downto 0);
3536    variable round             : BOOLEAN;
3537    variable expon_out         : SIGNED (exponent_width-1 downto 0);  -- output fract
3538    variable fract_out         : UNSIGNED (fraction_width downto 0);  -- output fract
3539    variable passguard         : NATURAL;
3540  begin
3541    fptype := classfp(arg, check_error);
3542    if ((fptype = pos_denormal or fptype = neg_denormal) and denormalize_in
3543        and (in_exponent_width < exponent_width
3544             or in_fraction_width < fraction_width))
3545      or in_exponent_width > exponent_width
3546      or in_fraction_width > fraction_width then
3547      -- size reduction
3548      classcase : case fptype is
3549        when isx =>
3550          result := (others => 'X');
3551        when nan | quiet_nan =>
3552          result := qnanfp (fraction_width => fraction_width,
3553                            exponent_width => exponent_width);
3554        when pos_inf =>
3555          result := pos_inffp (fraction_width => fraction_width,
3556                               exponent_width => exponent_width);
3557        when neg_inf =>
3558          result := neg_inffp (fraction_width => fraction_width,
3559                               exponent_width => exponent_width);
3560        when pos_zero | neg_zero =>
3561          result := zerofp (fraction_width => fraction_width,   -- hate -0
3562                            exponent_width => exponent_width);
3563        when others =>
3564          break_number (
3565            arg         => arg,
3566            fptyp       => fptype,
3567            denormalize => denormalize_in,
3568            fract       => fract_in,
3569            expon       => expon_in);
3570          if fraction_width > in_fraction_width and denormalize_in then
3571            -- You only get here if you have a denormal input
3572            fract_out := (others => '0');              -- pad with zeros
3573            fract_out (fraction_width downto
3574                       fraction_width - in_fraction_width) := fract_in;
3575            result := normalize (
3576              fract          => fract_out,
3577              expon          => expon_in,
3578              sign           => arg(arg'high),
3579              fraction_width => fraction_width,
3580              exponent_width => exponent_width,
3581              round_style    => round_style,
3582              denormalize    => denormalize,
3583              nguard         => 0);
3584          else
3585            result := normalize (
3586              fract          => fract_in,
3587              expon          => expon_in,
3588              sign           => arg(arg'high),
3589              fraction_width => fraction_width,
3590              exponent_width => exponent_width,
3591              round_style    => round_style,
3592              denormalize    => denormalize,
3593              nguard         => in_fraction_width - fraction_width);
3594          end if;
3595      end case classcase;
3596    else                                -- size increase or the same size
3597      if exponent_width > in_exponent_width then
3598        expon_in := SIGNED(arg (in_exponent_width-1 downto 0));
3599        if fptype = pos_zero or fptype = neg_zero then
3600          result (exponent_width-1 downto 0) := (others => '0');
3601        elsif expon_in = -1 then        -- inf or nan (shorts out check_error)
3602          result (exponent_width-1 downto 0) := (others => '1');
3603        else
3604          -- invert top BIT
3605          expon_in(expon_in'high)            := not expon_in(expon_in'high);
3606          expon_out := resize (expon_in, expon_out'length);  -- signed expand
3607          -- Flip it back.
3608          expon_out(expon_out'high)          := not expon_out(expon_out'high);
3609          result (exponent_width-1 downto 0) := UNRESOLVED_float(expon_out);
3610        end if;
3611        result (exponent_width) := arg (in_exponent_width);     -- sign
3612      else                              -- exponent_width = in_exponent_width
3613        result (exponent_width downto 0) := arg (in_exponent_width downto 0);
3614      end if;
3615      if fraction_width > in_fraction_width then
3616        result (-1 downto -fraction_width) := (others => '0');  -- zeros
3617        result (-1 downto -in_fraction_width) :=
3618          arg (-1 downto -in_fraction_width);
3619      else                              -- fraction_width = in_fraciton_width
3620        result (-1 downto -fraction_width) :=
3621          arg (-1 downto -in_fraction_width);
3622      end if;
3623    end if;
3624    return result;
3625  end function resize;
3626
3627  function resize (
3628    arg                     : UNRESOLVED_float;  -- floating point input
3629    size_res                : UNRESOLVED_float;
3630    constant round_style    : round_type := float_round_style;  -- rounding option
3631    constant check_error    : BOOLEAN    := float_check_error;
3632    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
3633    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
3634    return UNRESOLVED_float is
3635    variable result : UNRESOLVED_float (size_res'left downto size_res'right);
3636  begin
3637    if (result'length < 1) then
3638      return result;
3639    else
3640      result := resize (arg            => arg,
3641                        exponent_width => size_res'high,
3642                        fraction_width => -size_res'low,
3643                        round_style    => round_style,
3644                        check_error    => check_error,
3645                        denormalize_in => denormalize_in,
3646                        denormalize    => denormalize);
3647      return result;
3648    end if;
3649  end function resize;
3650
3651  function to_float32 (
3652    arg                     : UNRESOLVED_float;
3653    constant round_style    : round_type := float_round_style;  -- rounding option
3654    constant check_error    : BOOLEAN    := float_check_error;
3655    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
3656    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
3657    return UNRESOLVED_float32 is
3658  begin
3659    return resize (arg            => arg,
3660                   exponent_width => float32'high,
3661                   fraction_width => -float32'low,
3662                   round_style    => round_style,
3663                   check_error    => check_error,
3664                   denormalize_in => denormalize_in,
3665                   denormalize    => denormalize);
3666  end function to_float32;
3667
3668  function to_float64 (
3669    arg                     : UNRESOLVED_float;
3670    constant round_style    : round_type := float_round_style;  -- rounding option
3671    constant check_error    : BOOLEAN    := float_check_error;
3672    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
3673    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
3674    return UNRESOLVED_float64 is
3675  begin
3676    return resize (arg            => arg,
3677                   exponent_width => float64'high,
3678                   fraction_width => -float64'low,
3679                   round_style    => round_style,
3680                   check_error    => check_error,
3681                   denormalize_in => denormalize_in,
3682                   denormalize    => denormalize);
3683  end function to_float64;
3684
3685  function to_float128 (
3686    arg                     : UNRESOLVED_float;
3687    constant round_style    : round_type := float_round_style;  -- rounding option
3688    constant check_error    : BOOLEAN    := float_check_error;
3689    constant denormalize_in : BOOLEAN    := float_denormalize;  -- Use IEEE extended FP
3690    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
3691    return UNRESOLVED_float128 is
3692  begin
3693    return resize (arg            => arg,
3694                   exponent_width => float128'high,
3695                   fraction_width => -float128'low,
3696                   round_style    => round_style,
3697                   check_error    => check_error,
3698                   denormalize_in => denormalize_in,
3699                   denormalize    => denormalize);
3700  end function to_float128;
3701
3702  -- to_float (Real)
3703  -- typically not Synthesizable unless the input is a constant.
3704  function to_float (
3705    arg                     : REAL;
3706    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
3707    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
3708    constant round_style    : round_type := float_round_style;  -- rounding option
3709    constant denormalize    : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
3710    return UNRESOLVED_float is
3711    variable result     : UNRESOLVED_float (exponent_width downto -fraction_width);
3712    variable arg_real   : REAL;         -- Real version of argument
3713    variable validfp    : boundary_type;      -- Check for valid results
3714    variable exp        : INTEGER;      -- Integer version of exponent
3715    variable expon      : UNSIGNED (exponent_width - 1 downto 0);
3716                                        -- Unsigned version of exp.
3717    constant expon_base : SIGNED (exponent_width-1 downto 0) :=
3718      gen_expon_base(exponent_width);   -- exponent offset
3719    variable fract     : UNSIGNED (fraction_width-1 downto 0);
3720    variable frac      : REAL;          -- Real version of fraction
3721    constant roundfrac : REAL := 2.0 ** (-2 - fract'high);  -- used for rounding
3722    variable round     : BOOLEAN;       -- to round or not to round
3723  begin
3724    result   := (others => '0');
3725    arg_real := arg;
3726    if arg_real < 0.0 then
3727      result (exponent_width) := '1';
3728      arg_real                := - arg_real;  -- Make it positive.
3729    else
3730      result (exponent_width) := '0';
3731    end if;
3732    test_boundary (arg            => arg_real,
3733                   fraction_width => fraction_width,
3734                   exponent_width => exponent_width,
3735                   denormalize    => denormalize,
3736                   btype          => validfp,
3737                   log2i          => exp);
3738    if validfp = zero then
3739      return result;                    -- Result initialized to "0".
3740    elsif validfp = infinity then
3741      result (exponent_width - 1 downto 0) := (others => '1');  -- Exponent all "1"
3742                                        -- return infinity.
3743      return result;
3744    else
3745      if validfp = denormal then        -- Exponent will default to "0".
3746        expon := (others => '0');
3747        frac  := arg_real * (2.0 ** (to_integer(expon_base)-1));
3748      else                              -- Number less than 1. "normal" number
3749        expon := UNSIGNED (to_signed (exp-1, exponent_width));
3750        expon(exponent_width-1) := not expon(exponent_width-1);
3751        frac := (arg_real / 2.0 ** exp) - 1.0;  -- Number less than 1.
3752      end if;
3753      for i in 0 to fract'high loop
3754        if frac >= 2.0 ** (-1 - i) then
3755          fract (fract'high - i) := '1';
3756          frac := frac - 2.0 ** (-1 - i);
3757        else
3758          fract (fract'high - i) := '0';
3759        end if;
3760      end loop;
3761      round := false;
3762      case round_style is
3763        when round_nearest =>
3764          if frac > roundfrac or ((frac = roundfrac) and fract(0) = '1') then
3765            round := true;
3766          end if;
3767        when round_inf =>
3768          if frac /= 0.0 and result(exponent_width) = '0' then
3769            round := true;
3770          end if;
3771        when round_neginf =>
3772          if frac /= 0.0 and result(exponent_width) = '1' then
3773            round := true;
3774          end if;
3775        when others =>
3776          null;                         -- don't round
3777      end case;
3778      if (round) then
3779        if and_reduce (fract) = '1' then      -- fraction is all "1"
3780          expon := expon + 1;
3781          fract := (others => '0');
3782        else
3783          fract := fract + 1;
3784        end if;
3785      end if;
3786      result (exponent_width-1 downto 0) := UNRESOLVED_float(expon);
3787      result (-1 downto -fraction_width) := UNRESOLVED_float(fract);
3788      return result;
3789    end if;
3790  end function to_float;
3791
3792  -- to_float (Integer)
3793  function to_float (
3794    arg                     : INTEGER;
3795    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
3796    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
3797    constant round_style    : round_type := float_round_style)  -- rounding option
3798    return UNRESOLVED_float is
3799    variable result     : UNRESOLVED_float (exponent_width downto -fraction_width);
3800    variable arg_int    : NATURAL;      -- Natural version of argument
3801    variable expon      : SIGNED (exponent_width-1 downto 0);
3802    variable exptmp     : SIGNED (exponent_width-1 downto 0);
3803    -- Unsigned version of exp.
3804    constant expon_base : SIGNED (exponent_width-1 downto 0) :=
3805      gen_expon_base(exponent_width);   -- exponent offset
3806    variable fract     : UNSIGNED (fraction_width-1 downto 0) := (others => '0');
3807    variable fracttmp  : UNSIGNED (fraction_width-1 downto 0);
3808    variable round     : BOOLEAN;
3809    variable shift     : NATURAL;
3810    variable shiftr    : NATURAL;
3811    variable roundfrac : NATURAL;       -- used in rounding
3812  begin
3813    if arg < 0 then
3814      result (exponent_width) := '1';
3815      arg_int                 := -arg;  -- Make it positive.
3816    else
3817      result (exponent_width) := '0';
3818      arg_int                 := arg;
3819    end if;
3820    if arg_int = 0 then
3821      result := zerofp (fraction_width => fraction_width,
3822                        exponent_width => exponent_width);
3823    else
3824      -- If the number is larger than we can represent in this number system
3825      -- we need to return infinity.
3826      shift := log2(arg_int);
3827      if shift > to_integer(expon_base) then
3828        -- worry about infinity
3829        if result (exponent_width) = '0' then
3830          result := pos_inffp (fraction_width => fraction_width,
3831                               exponent_width => exponent_width);
3832        else
3833          -- return negative infinity.
3834          result := neg_inffp (fraction_width => fraction_width,
3835                               exponent_width => exponent_width);
3836        end if;
3837      else                              -- Normal number (can't be denormal)
3838        -- Compute Exponent
3839        expon   := to_signed (shift-1, expon'length);  -- positive fraction.
3840        -- Compute Fraction
3841        arg_int := arg_int - 2**shift;  -- Subtract off the 1.0
3842        shiftr  := shift;
3843        for I in fract'high downto maximum (fract'high - shift + 1, 0) loop
3844          shiftr := shiftr - 1;
3845          if (arg_int >= 2**shiftr) then
3846            arg_int  := arg_int - 2**shiftr;
3847            fract(I) := '1';
3848          else
3849            fract(I) := '0';
3850          end if;
3851        end loop;
3852        -- Rounding routine
3853        round := false;
3854        if arg_int > 0 then
3855          roundfrac := 2**(shiftr-1);
3856          case round_style is
3857            when round_nearest =>
3858              if arg_int > roundfrac or
3859                ((arg_int = roundfrac) and fract(0) = '1') then
3860                round := true;
3861              end if;
3862            when round_inf =>
3863              if arg_int /= 0 and result (exponent_width) = '0' then
3864                round := true;
3865              end if;
3866            when round_neginf =>
3867              if arg_int /= 0 and result (exponent_width) = '1' then
3868                round := true;
3869              end if;
3870            when others =>
3871              null;
3872          end case;
3873        end if;
3874        if round then
3875          fp_round(fract_in  => fract,
3876                   expon_in  => expon,
3877                   fract_out => fracttmp,
3878                   expon_out => exptmp);
3879          fract := fracttmp;
3880          expon := exptmp;
3881        end if;
3882        -- Put the number together and return
3883        expon(exponent_width-1)            := not expon(exponent_width-1);
3884        result (exponent_width-1 downto 0) := UNRESOLVED_float(expon);
3885        result (-1 downto -fraction_width) := UNRESOLVED_float(fract);
3886      end if;
3887    end if;
3888    return result;
3889  end function to_float;
3890
3891  -- to_float (unsigned)
3892  function to_float (
3893    arg                     : UNSIGNED;
3894    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
3895    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
3896    constant round_style    : round_type := float_round_style)  -- rounding option
3897    return UNRESOLVED_float is
3898    variable result   : UNRESOLVED_float (exponent_width downto -fraction_width);
3899    constant ARG_LEFT : INTEGER := ARG'length-1;
3900    alias XARG        : UNSIGNED(ARG_LEFT downto 0) is ARG;
3901    variable sarg     : SIGNED (ARG_LEFT+1 downto 0);  -- signed version of arg
3902  begin
3903    if arg'length < 1 then
3904      return NAFP;
3905    end if;
3906    sarg (XARG'range) := SIGNED (XARG);
3907    sarg (sarg'high)  := '0';
3908    result := to_float (arg            => sarg,
3909                        exponent_width => exponent_width,
3910                        fraction_width => fraction_width,
3911                        round_style    => round_style);
3912    return result;
3913  end function to_float;
3914
3915  -- to_float (signed)
3916  function to_float (
3917    arg                     : SIGNED;
3918    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
3919    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
3920    constant round_style    : round_type := float_round_style)  -- rounding option
3921    return UNRESOLVED_float is
3922    variable result     : UNRESOLVED_float (exponent_width downto -fraction_width);
3923    constant ARG_LEFT   : INTEGER := ARG'length-1;
3924    alias XARG          : SIGNED(ARG_LEFT downto 0) is ARG;
3925    variable arg_int    : UNSIGNED(xarg'range);  -- Real version of argument
3926    variable argb2      : UNSIGNED(xarg'high/2 downto 0);  -- log2 of input
3927    variable rexp       : SIGNED (exponent_width - 1 downto 0);
3928    variable exp        : SIGNED (exponent_width - 1 downto 0);
3929    -- signed version of exp.
3930    variable expon      : UNSIGNED (exponent_width - 1 downto 0);
3931    -- Unsigned version of exp.
3932    constant expon_base : SIGNED (exponent_width-1 downto 0) :=
3933      gen_expon_base(exponent_width);   -- exponent offset
3934    variable round  : BOOLEAN;
3935    variable fract  : UNSIGNED (fraction_width-1 downto 0);
3936    variable rfract : UNSIGNED (fraction_width-1 downto 0);
3937    variable sign   : STD_ULOGIC;         -- sign bit
3938  begin
3939    if arg'length < 1 then
3940      return NAFP;
3941    end if;
3942    if Is_X (xarg) then
3943      result := (others => 'X');
3944    elsif (xarg = 0) then
3945      result := zerofp (fraction_width => fraction_width,
3946                        exponent_width => exponent_width);
3947    else                                -- Normal number (can't be denormal)
3948      sign := to_X01(xarg (xarg'high));
3949      arg_int := UNSIGNED(abs (to_01(xarg)));
3950      -- Compute Exponent
3951      argb2 := to_unsigned(find_leftmost(arg_int, '1'), argb2'length);  -- Log2
3952      if argb2 > UNSIGNED(expon_base) then
3953        result := pos_inffp (fraction_width => fraction_width,
3954                             exponent_width => exponent_width);
3955        result (exponent_width) := sign;
3956      else
3957        exp     := SIGNED(resize(argb2, exp'length));
3958        arg_int := shift_left (arg_int, arg_int'high-to_integer(exp));
3959        if (arg_int'high > fraction_width) then
3960          fract := arg_int (arg_int'high-1 downto (arg_int'high-fraction_width));
3961          round := check_round (
3962            fract_in    => fract (0),
3963            sign        => sign,
3964            remainder   => arg_int((arg_int'high-fraction_width-1)
3965                                   downto 0),
3966            round_style => round_style);
3967          if round then
3968            fp_round(fract_in  => fract,
3969                     expon_in  => exp,
3970                     fract_out => rfract,
3971                     expon_out => rexp);
3972          else
3973            rfract := fract;
3974            rexp   := exp;
3975          end if;
3976        else
3977          rexp   := exp;
3978          rfract := (others => '0');
3979          rfract (fraction_width-1 downto fraction_width-1-(arg_int'high-1)) :=
3980            arg_int (arg_int'high-1 downto 0);
3981        end if;
3982        result (exponent_width) := sign;
3983        expon := UNSIGNED (rexp-1);
3984        expon(exponent_width-1)            := not expon(exponent_width-1);
3985        result (exponent_width-1 downto 0) := UNRESOLVED_float(expon);
3986        result (-1 downto -fraction_width) := UNRESOLVED_float(rfract);
3987      end if;
3988    end if;
3989    return result;
3990  end function to_float;
3991
3992  -- std_logic_vector to float
3993  function to_float (
3994    arg                     : STD_ULOGIC_VECTOR;
3995    constant exponent_width : NATURAL := float_exponent_width;  -- length of FP output exponent
3996    constant fraction_width : NATURAL := float_fraction_width)  -- length of FP output fraction
3997    return UNRESOLVED_float is
3998    variable fpvar : UNRESOLVED_float (exponent_width downto -fraction_width);
3999  begin
4000    if arg'length < 1 then
4001      return NAFP;
4002    end if;
4003    fpvar := UNRESOLVED_float(arg);
4004    return fpvar;
4005  end function to_float;
4006
4007  -- purpose: converts a ufixed to a floating point
4008  function to_float (
4009    arg                     : UNRESOLVED_ufixed;  -- unsigned fixed point input
4010    constant exponent_width : NATURAL    := float_exponent_width;  -- width of exponent
4011    constant fraction_width : NATURAL    := float_fraction_width;  -- width of fraction
4012    constant round_style    : round_type := float_round_style;  -- rounding
4013    constant denormalize    : BOOLEAN    := float_denormalize)  -- use ieee extensions
4014    return UNRESOLVED_float is
4015    variable sarg   : sfixed (arg'high+1 downto arg'low);  -- Signed version of arg
4016    variable result : UNRESOLVED_float (exponent_width downto -fraction_width);
4017  begin  -- function to_float
4018    if (arg'length < 1) then
4019      return NAFP;
4020    end if;
4021    sarg (arg'range) := sfixed (arg);
4022    sarg (sarg'high) := '0';
4023    result := to_float (arg            => sarg,
4024                        exponent_width => exponent_width,
4025                        fraction_width => fraction_width,
4026                        round_style    => round_style,
4027                        denormalize    => denormalize);
4028    return result;
4029  end function to_float;
4030
4031  function to_float (
4032    arg                     : UNRESOLVED_sfixed;    -- signed fixed point
4033    constant exponent_width : NATURAL    := float_exponent_width;  -- length of FP output exponent
4034    constant fraction_width : NATURAL    := float_fraction_width;  -- length of FP output fraction
4035    constant round_style    : round_type := float_round_style;  -- rounding
4036    constant denormalize    : BOOLEAN    := float_denormalize)  -- rounding option
4037    return UNRESOLVED_float is
4038    constant integer_width     : INTEGER := arg'high;
4039    constant in_fraction_width : INTEGER := arg'low;
4040    variable xresult     : sfixed (integer_width downto in_fraction_width);
4041    variable result      : UNRESOLVED_float (exponent_width downto -fraction_width);
4042    variable arg_int     : UNSIGNED(integer_width - in_fraction_width
4043                                    downto 0);  -- unsigned version of argument
4044    variable argx        : SIGNED (integer_width - in_fraction_width downto 0);
4045    variable exp, exptmp : SIGNED (exponent_width + 1 downto 0);
4046    variable expon       : UNSIGNED (exponent_width - 1 downto 0);
4047    -- Unsigned version of exp.
4048    constant expon_base  : SIGNED (exponent_width-1 downto 0) :=
4049      gen_expon_base(exponent_width);   -- exponent offset
4050    variable fract, fracttmp : UNSIGNED (fraction_width-1 downto 0) :=
4051      (others => '0');
4052    variable round : BOOLEAN := false;
4053  begin
4054    if (arg'length < 1) then
4055      return NAFP;
4056    end if;
4057    xresult := to_01(arg, 'X');
4058    argx    := SIGNED(to_slv(xresult));
4059    if (Is_X (arg)) then
4060      result := (others => 'X');
4061    elsif (argx = 0) then
4062      result := (others => '0');
4063    else
4064      result := (others => '0');        -- zero out the result
4065      if argx(argx'left) = '1' then     -- toss the sign bit
4066        result (exponent_width) := '1';     -- Negative number
4067        arg_int := UNSIGNED(to_x01(not STD_LOGIC_VECTOR (argx))) + 1; -- Make it positive with two's complement
4068      else
4069        result (exponent_width) := '0';
4070        arg_int := UNSIGNED(to_x01(STD_LOGIC_VECTOR (argx))); -- new line: direct conversion to unsigned
4071      end if;
4072      -- Compute Exponent
4073      exp     := to_signed(find_leftmost(arg_int, '1'), exp'length);  -- Log2
4074      if exp + in_fraction_width > expon_base then  -- return infinity
4075        result (-1 downto -fraction_width)  := (others => '0');
4076        result (exponent_width -1 downto 0) := (others => '1');
4077        return result;
4078      elsif (denormalize and
4079             (exp + in_fraction_width <= -resize(expon_base, exp'length))) then
4080        exp := -resize(expon_base, exp'length);
4081        -- shift by a constant
4082        arg_int := shift_left (arg_int,
4083                               (arg_int'high + to_integer(expon_base)
4084                                + in_fraction_width - 1));
4085        if (arg_int'high > fraction_width) then
4086          fract := arg_int (arg_int'high-1 downto (arg_int'high-fraction_width));
4087          round := check_round (
4088            fract_in    => arg_int(arg_int'high-fraction_width),
4089            sign        => result(result'high),
4090            remainder   => arg_int((arg_int'high-fraction_width-1)
4091                                   downto 0),
4092            round_style => round_style);
4093          if (round) then
4094            fp_round (fract_in => arg_int (arg_int'high-1 downto
4095                                           (arg_int'high-fraction_width)),
4096                      expon_in  => exp,
4097                      fract_out => fract,
4098                      expon_out => exptmp);
4099            exp := exptmp;
4100          end if;
4101        else
4102          fract (fraction_width-1 downto fraction_width-1-(arg_int'high-1)) :=
4103            arg_int (arg_int'high-1 downto 0);
4104        end if;
4105      else
4106        arg_int := shift_left (arg_int, arg_int'high-to_integer(exp));
4107        exp     := exp + in_fraction_width;
4108        if (arg_int'high > fraction_width) then
4109          fract := arg_int (arg_int'high-1 downto (arg_int'high-fraction_width));
4110          round := check_round (
4111            fract_in    => fract(0),
4112            sign        => result(result'high),
4113            remainder   => arg_int((arg_int'high-fraction_width-1)
4114                                   downto 0),
4115            round_style => round_style);
4116          if (round) then
4117            fp_round (fract_in  => fract,
4118                      expon_in  => exp,
4119                      fract_out => fracttmp,
4120                      expon_out => exptmp);
4121            fract := fracttmp;
4122            exp   := exptmp;
4123          end if;
4124        else
4125          fract (fraction_width-1 downto fraction_width-1-(arg_int'high-1)) :=
4126            arg_int (arg_int'high-1 downto 0);
4127        end if;
4128      end if;
4129      expon := UNSIGNED (resize(exp-1, exponent_width));
4130      expon(exponent_width-1)            := not expon(exponent_width-1);
4131      result (exponent_width-1 downto 0) := UNRESOLVED_float(expon);
4132      result (-1 downto -fraction_width) := UNRESOLVED_float(fract);
4133    end if;
4134    return result;
4135  end function to_float;
4136
4137  -- size_res functions
4138  -- Integer to float
4139  function to_float (
4140    arg                  : INTEGER;
4141    size_res             : UNRESOLVED_float;
4142    constant round_style : round_type := float_round_style)  -- rounding option
4143    return UNRESOLVED_float is
4144    variable result : UNRESOLVED_float (size_res'left downto size_res'right);
4145  begin
4146    if (result'length < 1) then
4147      return result;
4148    else
4149      result := to_float (arg            => arg,
4150                          exponent_width => size_res'high,
4151                          fraction_width => -size_res'low,
4152                          round_style    => round_style);
4153      return result;
4154    end if;
4155  end function to_float;
4156
4157  -- real to float
4158  function to_float (
4159    arg                  : REAL;
4160    size_res             : UNRESOLVED_float;
4161    constant round_style : round_type := float_round_style;  -- rounding option
4162    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
4163    return UNRESOLVED_float is
4164    variable result : UNRESOLVED_float (size_res'left downto size_res'right);
4165  begin
4166    if (result'length < 1) then
4167      return result;
4168    else
4169      result := to_float (arg            => arg,
4170                          exponent_width => size_res'high,
4171                          fraction_width => -size_res'low,
4172                          round_style    => round_style,
4173                          denormalize    => denormalize);
4174      return result;
4175    end if;
4176  end function to_float;
4177
4178  -- unsigned to float
4179  function to_float (
4180    arg                  : UNSIGNED;
4181    size_res             : UNRESOLVED_float;
4182    constant round_style : round_type := float_round_style)  -- rounding option
4183    return UNRESOLVED_float is
4184    variable result : UNRESOLVED_float (size_res'left downto size_res'right);
4185  begin
4186    if (result'length < 1) then
4187      return result;
4188    else
4189      result := to_float (arg            => arg,
4190                          exponent_width => size_res'high,
4191                          fraction_width => -size_res'low,
4192                          round_style    => round_style);
4193      return result;
4194    end if;
4195  end function to_float;
4196
4197  -- signed to float
4198  function to_float (
4199    arg                  : SIGNED;
4200    size_res             : UNRESOLVED_float;
4201    constant round_style : round_type := float_round_style)  -- rounding
4202    return UNRESOLVED_float is
4203    variable result : UNRESOLVED_float (size_res'left downto size_res'right);
4204  begin
4205    if (result'length < 1) then
4206      return result;
4207    else
4208      result := to_float (arg            => arg,
4209                          exponent_width => size_res'high,
4210                          fraction_width => -size_res'low,
4211                          round_style    => round_style);
4212      return result;
4213    end if;
4214  end function to_float;
4215
4216  -- std_ulogic_vector to float
4217  function to_float (
4218    arg      : STD_ULOGIC_VECTOR;
4219    size_res : UNRESOLVED_float)
4220    return UNRESOLVED_float is
4221    variable result : UNRESOLVED_float (size_res'left downto size_res'right);
4222  begin
4223    if (result'length < 1) then
4224      return result;
4225    else
4226      result := to_float (arg            => arg,
4227                          exponent_width => size_res'high,
4228                          fraction_width => -size_res'low);
4229      return result;
4230    end if;
4231  end function to_float;
4232
4233  -- unsigned fixed point to float
4234  function to_float (
4235    arg                  : UNRESOLVED_ufixed;  -- unsigned fixed point input
4236    size_res             : UNRESOLVED_float;
4237    constant round_style : round_type := float_round_style;  -- rounding
4238    constant denormalize : BOOLEAN    := float_denormalize)  -- use ieee extensions
4239    return UNRESOLVED_float is
4240    variable result : UNRESOLVED_float (size_res'left downto size_res'right);
4241  begin
4242    if (result'length < 1) then
4243      return result;
4244    else
4245      result := to_float (arg            => arg,
4246                          exponent_width => size_res'high,
4247                          fraction_width => -size_res'low,
4248                          round_style    => round_style,
4249                          denormalize    => denormalize);
4250      return result;
4251    end if;
4252  end function to_float;
4253
4254  -- signed fixed point to float
4255  function to_float (
4256    arg                  : UNRESOLVED_sfixed;
4257    size_res             : UNRESOLVED_float;
4258    constant round_style : round_type := float_round_style;  -- rounding
4259    constant denormalize : BOOLEAN    := float_denormalize)  -- rounding option
4260    return UNRESOLVED_float is
4261    variable result : UNRESOLVED_float (size_res'left downto size_res'right);
4262  begin
4263    if (result'length < 1) then
4264      return result;
4265    else
4266      result := to_float (arg            => arg,
4267                          exponent_width => size_res'high,
4268                          fraction_width => -size_res'low,
4269                          round_style    => round_style,
4270                          denormalize    => denormalize);
4271      return result;
4272    end if;
4273  end function to_float;
4274
4275  -- to_integer (float)
4276  function to_integer (
4277    arg                  : UNRESOLVED_float;   -- floating point input
4278    constant round_style : round_type := float_round_style;  -- rounding option
4279    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
4280    return INTEGER is
4281    variable validfp : valid_fpstate;   -- Valid FP state
4282    variable frac    : UNSIGNED (-arg'low downto 0);         -- Fraction
4283    variable fract   : UNSIGNED (1-arg'low downto 0);        -- Fraction
4284    variable expon   : SIGNED (arg'high-1 downto 0);
4285    variable isign   : STD_ULOGIC;      -- internal version of sign
4286    variable round   : STD_ULOGIC;      -- is rounding needed?
4287    variable result  : INTEGER;
4288    variable base    : INTEGER;         -- Integer exponent
4289  begin
4290    validfp := classfp (arg, check_error);
4291    classcase : case validfp is
4292      when isx | nan | quiet_nan | pos_zero | neg_zero | pos_denormal | neg_denormal =>
4293        result := 0;                    -- return 0
4294      when pos_inf =>
4295        result := INTEGER'high;
4296      when neg_inf =>
4297        result := INTEGER'low;
4298      when others =>
4299        break_number (
4300          arg         => arg,
4301          fptyp       => validfp,
4302          denormalize => false,
4303          fract       => frac,
4304          expon       => expon);
4305        fract (fract'high)            := '0';  -- Add extra bit for 0.6 case
4306        fract (fract'high-1 downto 0) := frac;
4307        isign                         := to_x01 (arg (arg'high));
4308        base                          := to_integer (expon) + 1;
4309        if base < -1 then
4310          result := 0;
4311        elsif base >= frac'high then
4312          result := to_integer (fract) * 2**(base - frac'high);
4313        else                            -- We need to round
4314          if base = -1 then             -- trap for 0.6 case.
4315            result := 0;
4316          else
4317            result := to_integer (fract (frac'high downto frac'high-base));
4318          end if;
4319          -- rounding routine
4320          case round_style is
4321            when round_nearest =>
4322              if frac'high - base > 1 then
4323                round := fract (frac'high - base - 1) and
4324                         (fract (frac'high - base)
4325                          or (or_reduce (fract (frac'high - base - 2 downto 0))));
4326              else
4327                round := fract (frac'high - base - 1) and
4328                         fract (frac'high - base);
4329              end if;
4330            when round_inf =>
4331              round := fract(frac'high - base - 1) and not isign;
4332            when round_neginf =>
4333              round := fract(frac'high - base - 1) and isign;
4334            when others =>
4335              round := '0';
4336          end case;
4337          if round = '1' then
4338            result := result + 1;
4339          end if;
4340        end if;
4341        if isign = '1' then
4342          result := - result;
4343        end if;
4344    end case classcase;
4345    return result;
4346  end function to_integer;
4347
4348  -- to_unsigned (float)
4349  function to_unsigned (
4350    arg                  : UNRESOLVED_float;  -- floating point input
4351    constant size        : NATURAL;     -- length of output
4352    constant round_style : round_type := float_round_style;  -- rounding option
4353    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
4354    return UNSIGNED is
4355    variable validfp : valid_fpstate;   -- Valid FP state
4356    variable frac    : UNSIGNED (size-1 downto 0);           -- Fraction
4357    variable sign    : STD_ULOGIC;      -- not used
4358  begin
4359    validfp := classfp (arg, check_error);
4360    classcase : case validfp is
4361      when isx | nan | quiet_nan =>
4362        frac := (others => 'X');
4363      when pos_zero | neg_inf | neg_zero | neg_normal | pos_denormal | neg_denormal =>
4364        frac := (others => '0');        -- return 0
4365      when pos_inf =>
4366        frac := (others => '1');
4367      when others =>
4368        float_to_unsigned (
4369          arg         => arg,
4370          frac        => frac,
4371          sign        => sign,
4372          denormalize => false,
4373          bias        => 0,
4374          round_style => round_style);
4375    end case classcase;
4376    return (frac);
4377  end function to_unsigned;
4378
4379  -- to_signed (float)
4380  function to_signed (
4381    arg                  : UNRESOLVED_float;  -- floating point input
4382    constant size        : NATURAL;     -- length of output
4383    constant round_style : round_type := float_round_style;  -- rounding option
4384    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
4385    return SIGNED is
4386    variable sign    : STD_ULOGIC;      -- true if negative
4387    variable validfp : valid_fpstate;   -- Valid FP state
4388    variable frac    : UNSIGNED (size-1 downto 0);           -- Fraction
4389    variable result  : SIGNED (size-1 downto 0);
4390  begin
4391    validfp := classfp (arg, check_error);
4392    classcase : case validfp is
4393      when isx | nan | quiet_nan =>
4394        result := (others => 'X');
4395      when pos_zero | neg_zero | pos_denormal | neg_denormal =>
4396        result := (others => '0');      -- return 0
4397      when pos_inf =>
4398        result               := (others => '1');
4399        result (result'high) := '0';
4400      when neg_inf =>
4401        result               := (others => '0');
4402        result (result'high) := '1';
4403      when others =>
4404        float_to_unsigned (
4405          arg         => arg,
4406          sign        => sign,
4407          frac        => frac,
4408          denormalize => false,
4409          bias        => 0,
4410          round_style => round_style);
4411        result (size-1)          := '0';
4412        result (size-2 downto 0) := SIGNED(frac (size-2 downto 0));
4413        if sign = '1' then
4414          -- Because the most negative signed number is 1 less than the most
4415          -- positive signed number, we need this code.
4416          if frac(frac'high) = '1' then       -- return most negative number
4417            result               := (others => '0');
4418            result (result'high) := '1';
4419          else
4420            result := -result;
4421          end if;
4422        else
4423          if frac(frac'high) = '1' then       -- return most positive number
4424            result               := (others => '1');
4425            result (result'high) := '0';
4426          end if;
4427        end if;
4428    end case classcase;
4429    return result;
4430  end function to_signed;
4431
4432  -- purpose: Converts a float to ufixed
4433  function to_ufixed (
4434    arg                     : UNRESOLVED_float;            -- fp input
4435    constant left_index     : INTEGER;  -- integer part
4436    constant right_index    : INTEGER;  -- fraction part
4437    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;  -- saturate
4438    constant round_style    : fixed_round_style_type    := fixed_round_style;  -- rounding
4439    constant check_error    : BOOLEAN                   := float_check_error;  -- check for errors
4440    constant denormalize    : BOOLEAN                   := float_denormalize)
4441    return UNRESOLVED_ufixed is
4442    constant fraction_width : INTEGER                    := -mine(arg'low, arg'low);  -- length of FP output fraction
4443    constant exponent_width : INTEGER                    := arg'high;  -- length of FP output exponent
4444    constant size           : INTEGER                    := left_index - right_index + 4;  -- unsigned size
4445    variable expon_base     : INTEGER;  -- exponent offset
4446    variable validfp        : valid_fpstate;               -- Valid FP state
4447    variable exp            : INTEGER;  -- Exponent
4448    variable expon          : UNSIGNED (exponent_width-1 downto 0);  -- Vectorized exponent
4449    -- Base to divide fraction by
4450    variable frac           : UNSIGNED (size-1 downto 0) := (others => '0');  -- Fraction
4451    variable frac_shift     : UNSIGNED (size-1 downto 0);  -- Fraction shifted
4452    variable shift          : INTEGER;
4453    variable result_big     : UNRESOLVED_ufixed (left_index downto right_index-3);
4454    variable result         : UNRESOLVED_ufixed (left_index downto right_index);  -- result
4455  begin  -- function to_ufixed
4456    validfp := classfp (arg, check_error);
4457    classcase : case validfp is
4458      when isx | nan | quiet_nan =>
4459        frac := (others => 'X');
4460      when pos_zero | neg_inf | neg_zero | neg_normal | neg_denormal =>
4461        frac := (others => '0');        -- return 0
4462      when pos_inf =>
4463        frac := (others => '1');        -- always saturate
4464      when others =>
4465        expon_base := 2**(exponent_width-1) -1;            -- exponent offset
4466        -- Figure out the fraction
4467        if (validfp = pos_denormal) and denormalize then
4468          exp              := -expon_base +1;
4469          frac (frac'high) := '0';      -- Remove the "1.0".
4470        else
4471          -- exponent /= '0', normal floating point
4472          expon                   := UNSIGNED(arg (exponent_width-1 downto 0));
4473          expon(exponent_width-1) := not expon(exponent_width-1);
4474          exp                     := to_integer (SIGNED(expon)) +1;
4475          frac (frac'high)        := '1';   -- Add the "1.0".
4476        end if;
4477        shift := (frac'high - 3 + right_index) - exp;
4478        if fraction_width > frac'high then  -- Can only use size-2 bits
4479          frac (frac'high-1 downto 0) := UNSIGNED (to_slv (arg(-1 downto
4480                                                               -frac'high)));
4481        else                            -- can use all bits
4482          frac (frac'high-1 downto frac'high-fraction_width) :=
4483            UNSIGNED (to_slv (arg(-1 downto -fraction_width)));
4484        end if;
4485        frac_shift := frac srl shift;
4486        if shift < 0 then               -- Overflow
4487          frac := (others => '1');
4488        else
4489          frac := frac_shift;
4490        end if;
4491    end case classcase;
4492    result_big := to_ufixed (
4493      arg         => STD_ULOGIC_VECTOR(frac),
4494      left_index  => left_index,
4495      right_index => (right_index-3));
4496    result := resize (arg            => result_big,
4497                      left_index     => left_index,
4498                      right_index    => right_index,
4499                      round_style    => round_style,
4500                      overflow_style => overflow_style);
4501    return result;
4502  end function to_ufixed;
4503
4504  -- purpose: Converts a float to sfixed
4505  function to_sfixed (
4506    arg                     : UNRESOLVED_float;  -- fp input
4507    constant left_index     : INTEGER;  -- integer part
4508    constant right_index    : INTEGER;  -- fraction part
4509    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;  -- saturate
4510    constant round_style    : fixed_round_style_type    := fixed_round_style;  -- rounding
4511    constant check_error    : BOOLEAN                   := float_check_error;  -- check for errors
4512    constant denormalize    : BOOLEAN                   := float_denormalize)
4513    return UNRESOLVED_sfixed is
4514    constant fraction_width : INTEGER                    := -mine(arg'low, arg'low);  -- length of FP output fraction
4515    constant exponent_width : INTEGER                    := arg'high;  -- length of FP output exponent
4516    constant size           : INTEGER                    := left_index - right_index + 4;  -- unsigned size
4517    variable expon_base     : INTEGER;  -- exponent offset
4518    variable validfp        : valid_fpstate;     -- Valid FP state
4519    variable exp            : INTEGER;  -- Exponent
4520    variable sign           : BOOLEAN;  -- true if negative
4521    variable expon          : UNSIGNED (exponent_width-1 downto 0);  -- Vectorized exponent
4522    -- Base to divide fraction by
4523    variable frac           : UNSIGNED (size-2 downto 0) := (others => '0');  -- Fraction
4524    variable frac_shift     : UNSIGNED (size-2 downto 0);  -- Fraction shifted
4525    variable shift          : INTEGER;
4526    variable rsigned        : SIGNED (size-1 downto 0);  -- signed version of result
4527    variable result_big     : UNRESOLVED_sfixed (left_index downto right_index-3);
4528    variable result         : UNRESOLVED_sfixed (left_index downto right_index)
4529      := (others => '0');               -- result
4530  begin  -- function to_sfixed
4531    validfp := classfp (arg, check_error);
4532    classcase : case validfp is
4533      when isx | nan | quiet_nan =>
4534        result := (others => 'X');
4535      when pos_zero | neg_zero =>
4536        result := (others => '0');      -- return 0
4537      when neg_inf =>
4538        result (left_index) := '1';     -- return smallest negative number
4539      when pos_inf =>
4540        result              := (others => '1');  -- return largest number
4541        result (left_index) := '0';
4542      when others =>
4543        expon_base := 2**(exponent_width-1) -1;  -- exponent offset
4544        if arg(exponent_width) = '0' then
4545          sign := false;
4546        else
4547          sign := true;
4548        end if;
4549        -- Figure out the fraction
4550        if (validfp = pos_denormal or validfp = neg_denormal)
4551          and denormalize then
4552          exp              := -expon_base +1;
4553          frac (frac'high) := '0';      -- Add the "1.0".
4554        else
4555          -- exponent /= '0', normal floating point
4556          expon                   := UNSIGNED(arg (exponent_width-1 downto 0));
4557          expon(exponent_width-1) := not expon(exponent_width-1);
4558          exp                     := to_integer (SIGNED(expon)) +1;
4559          frac (frac'high)        := '1';        -- Add the "1.0".
4560        end if;
4561        shift := (frac'high - 3 + right_index) - exp;
4562        if fraction_width > frac'high then       -- Can only use size-2 bits
4563          frac (frac'high-1 downto 0) := UNSIGNED (to_slv (arg(-1 downto
4564                                                               -frac'high)));
4565        else                            -- can use all bits
4566          frac (frac'high-1 downto frac'high-fraction_width) :=
4567            UNSIGNED (to_slv (arg(-1 downto -fraction_width)));
4568        end if;
4569        frac_shift := frac srl shift;
4570        if shift < 0 then               -- Overflow
4571          frac := (others => '1');
4572        else
4573          frac := frac_shift;
4574        end if;
4575        if not sign then
4576          rsigned := SIGNED("0" & frac);
4577        else
4578          rsigned := -(SIGNED("0" & frac));
4579        end if;
4580        result_big := to_sfixed (
4581          arg         => STD_LOGIC_VECTOR(rsigned),
4582          left_index  => left_index,
4583          right_index => (right_index-3));
4584        result := resize (arg            => result_big,
4585                          left_index     => left_index,
4586                          right_index    => right_index,
4587                          round_style    => round_style,
4588                          overflow_style => overflow_style);
4589    end case classcase;
4590    return result;
4591  end function to_sfixed;
4592
4593  -- size_res versions
4594  -- float to unsigned
4595  function to_unsigned (
4596    arg                  : UNRESOLVED_float;  -- floating point input
4597    size_res             : UNSIGNED;
4598    constant round_style : round_type := float_round_style;  -- rounding option
4599    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
4600    return UNSIGNED is
4601    variable result : UNSIGNED (size_res'range);
4602  begin
4603    if (SIZE_RES'length = 0) then
4604      return result;
4605    else
4606      result := to_unsigned (
4607        arg         => arg,
4608        size        => size_res'length,
4609        round_style => round_style,
4610        check_error => check_error);
4611      return result;
4612    end if;
4613  end function to_unsigned;
4614
4615  -- float to signed
4616  function to_signed (
4617    arg                  : UNRESOLVED_float;  -- floating point input
4618    size_res             : SIGNED;
4619    constant round_style : round_type := float_round_style;  -- rounding option
4620    constant check_error : BOOLEAN    := float_check_error)  -- check for errors
4621    return SIGNED is
4622    variable result : SIGNED (size_res'range);
4623  begin
4624    if (SIZE_RES'length = 0) then
4625      return result;
4626    else
4627      result := to_signed (
4628        arg         => arg,
4629        size        => size_res'length,
4630        round_style => round_style,
4631        check_error => check_error);
4632      return result;
4633    end if;
4634  end function to_signed;
4635
4636  -- purpose: Converts a float to unsigned fixed point
4637  function to_ufixed (
4638    arg                     : UNRESOLVED_float;  -- fp input
4639    size_res                : UNRESOLVED_ufixed;
4640    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;  -- saturate
4641    constant round_style    : fixed_round_style_type    := fixed_round_style;  -- rounding
4642    constant check_error    : BOOLEAN                   := float_check_error;  -- check for errors
4643    constant denormalize    : BOOLEAN                   := float_denormalize)
4644    return UNRESOLVED_ufixed is
4645    variable result : UNRESOLVED_ufixed (size_res'left downto size_res'right);
4646  begin
4647    if (result'length < 1) then
4648      return result;
4649    else
4650      result := to_ufixed (
4651        arg            => arg,
4652        left_index     => size_res'high,
4653        right_index    => size_res'low,
4654        overflow_style => overflow_style,
4655        round_style    => round_style,
4656        check_error    => check_error,
4657        denormalize    => denormalize);
4658      return result;
4659    end if;
4660  end function to_ufixed;
4661
4662  -- float to signed fixed point
4663  function to_sfixed (
4664    arg                     : UNRESOLVED_float;  -- fp input
4665    size_res                : UNRESOLVED_sfixed;
4666    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;  -- saturate
4667    constant round_style    : fixed_round_style_type    := fixed_round_style;  -- rounding
4668    constant check_error    : BOOLEAN                   := float_check_error;  -- check for errors
4669    constant denormalize    : BOOLEAN                   := float_denormalize)
4670    return UNRESOLVED_sfixed is
4671    variable result : UNRESOLVED_sfixed (size_res'left downto size_res'right);
4672  begin
4673    if (result'length < 1) then
4674      return result;
4675    else
4676      result := to_sfixed (
4677        arg            => arg,
4678        left_index     => size_res'high,
4679        right_index    => size_res'low,
4680        overflow_style => overflow_style,
4681        round_style    => round_style,
4682        check_error    => check_error,
4683        denormalize    => denormalize);
4684      return result;
4685    end if;
4686  end function to_sfixed;
4687
4688  -- to_real (float)
4689  -- typically not Synthesizable unless the input is a constant.
4690  function to_real (
4691    arg                  : UNRESOLVED_float;        -- floating point input
4692    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
4693    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
4694    return REAL is
4695    constant fraction_width : INTEGER := -mine(arg'low, arg'low);  -- length of FP output fraction
4696    constant exponent_width : INTEGER := arg'high;  -- length of FP output exponent
4697    variable sign           : REAL;     -- Sign, + or - 1
4698    variable exp            : INTEGER;  -- Exponent
4699    variable expon_base     : INTEGER;  -- exponent offset
4700    variable frac           : REAL    := 0.0;       -- Fraction
4701    variable validfp        : valid_fpstate;        -- Valid FP state
4702    variable expon          : UNSIGNED (exponent_width - 1 downto 0)
4703      := (others => '1');               -- Vectorized exponent
4704  begin
4705    validfp := classfp (arg, check_error);
4706    classcase : case validfp is
4707      when isx | pos_zero | neg_zero | nan | quiet_nan =>
4708        return 0.0;
4709      when neg_inf =>
4710        return REAL'low;                -- Negative infinity.
4711      when pos_inf =>
4712        return REAL'high;               -- Positive infinity
4713      when others =>
4714        expon_base := 2**(exponent_width-1) -1;
4715        if to_X01(arg(exponent_width)) = '0' then
4716          sign := 1.0;
4717        else
4718          sign := -1.0;
4719        end if;
4720        -- Figure out the fraction
4721        for i in 0 to fraction_width-1 loop
4722          if to_X01(arg (-1 - i)) = '1' then
4723            frac := frac + (2.0 **(-1 - i));
4724          end if;
4725        end loop;  -- i
4726        if validfp = pos_normal or validfp = neg_normal or not denormalize then
4727          -- exponent /= '0', normal floating point
4728          expon                   := UNSIGNED(arg (exponent_width-1 downto 0));
4729          expon(exponent_width-1) := not expon(exponent_width-1);
4730          exp                     := to_integer (SIGNED(expon)) +1;
4731          sign                    := sign * (2.0 ** exp) * (1.0 + frac);
4732        else  -- exponent = '0', IEEE extended floating point
4733          exp  := 1 - expon_base;
4734          sign := sign * (2.0 ** exp) * frac;
4735        end if;
4736        return sign;
4737    end case classcase;
4738  end function to_real;
4739
4740  -- For Verilog compatability
4741  function realtobits (arg : REAL) return STD_ULOGIC_VECTOR is
4742    variable result : float64;          -- 64 bit floating point
4743  begin
4744    result := to_float (arg => arg,
4745                        exponent_width => float64'high,
4746                        fraction_width => -float64'low);
4747    return to_sulv (result);
4748  end function realtobits;
4749
4750  function bitstoreal (arg : STD_ULOGIC_VECTOR) return REAL is
4751    variable arg64 : float64;           -- arg converted to float
4752  begin
4753    arg64 := to_float (arg => arg,
4754                       exponent_width => float64'high,
4755                       fraction_width => -float64'low);
4756    return to_real (arg64);
4757  end function bitstoreal;
4758
4759  -- purpose: Removes meta-logical values from FP string
4760  function to_01 (
4761    arg  : UNRESOLVED_float;            -- floating point input
4762    XMAP : STD_LOGIC := '0')
4763    return UNRESOLVED_float is
4764    variable result : UNRESOLVED_float (arg'range);
4765  begin  -- function to_01
4766    if (arg'length < 1) then
4767      assert NO_WARNING
4768        report float_pkg'instance_name
4769        & "TO_01: null detected, returning NULL"
4770        severity warning;
4771      return NAFP;
4772    end if;
4773    result := UNRESOLVED_float (STD_LOGIC_VECTOR(to_01(UNSIGNED(to_slv(arg)), XMAP)));
4774    return result;
4775  end function to_01;
4776
4777  function Is_X
4778    (arg : UNRESOLVED_float)
4779    return BOOLEAN is
4780  begin
4781    return Is_X (to_slv(arg));
4782  end function Is_X;
4783
4784  function to_X01 (arg : UNRESOLVED_float) return UNRESOLVED_float is
4785    variable result : UNRESOLVED_float (arg'range);
4786  begin
4787    if (arg'length < 1) then
4788      assert NO_WARNING
4789        report float_pkg'instance_name
4790        & "TO_X01: null detected, returning NULL"
4791        severity warning;
4792      return NAFP;
4793    else
4794      result := UNRESOLVED_float (to_X01(to_slv(arg)));
4795      return result;
4796    end if;
4797  end function to_X01;
4798
4799  function to_X01Z (arg : UNRESOLVED_float) return UNRESOLVED_float is
4800    variable result : UNRESOLVED_float (arg'range);
4801  begin
4802    if (arg'length < 1) then
4803      assert NO_WARNING
4804        report float_pkg'instance_name
4805        & "TO_X01Z: null detected, returning NULL"
4806        severity warning;
4807      return NAFP;
4808    else
4809      result := UNRESOLVED_float (to_X01Z(to_slv(arg)));
4810      return result;
4811    end if;
4812  end function to_X01Z;
4813
4814  function to_UX01 (arg : UNRESOLVED_float) return UNRESOLVED_float is
4815    variable result : UNRESOLVED_float (arg'range);
4816  begin
4817    if (arg'length < 1) then
4818      assert NO_WARNING
4819        report float_pkg'instance_name
4820        & "TO_UX01: null detected, returning NULL"
4821        severity warning;
4822      return NAFP;
4823    else
4824      result := UNRESOLVED_float (to_UX01(to_slv(arg)));
4825      return result;
4826    end if;
4827  end function to_UX01;
4828
4829  -- These allows the base math functions to use the default values
4830  -- of their parameters.  Thus they do full IEEE floating point.
4831  function "+" (l, r : UNRESOLVED_float) return UNRESOLVED_float is
4832  begin
4833    return add (l, r);
4834  end function "+";
4835
4836  function "-" (l, r : UNRESOLVED_float) return UNRESOLVED_float is
4837  begin
4838    return subtract (l, r);
4839  end function "-";
4840
4841  function "*" (l, r : UNRESOLVED_float) return UNRESOLVED_float is
4842  begin
4843    return multiply (l, r);
4844  end function "*";
4845
4846  function "/" (l, r : UNRESOLVED_float) return UNRESOLVED_float is
4847  begin
4848    return divide (l, r);
4849  end function "/";
4850
4851  function "rem" (l, r : UNRESOLVED_float) return UNRESOLVED_float is
4852  begin
4853    return remainder (l, r);
4854  end function "rem";
4855
4856  function "mod" (l, r : UNRESOLVED_float) return UNRESOLVED_float is
4857  begin
4858    return modulo (l, r);
4859  end function "mod";
4860
4861  -- overloaded versions
4862  function "+" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float is
4863    variable r_float : UNRESOLVED_float (l'range);
4864  begin
4865    r_float := to_float (r, l'high, -l'low);
4866    return add (l, r_float);
4867  end function "+";
4868
4869  function "+" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float is
4870    variable l_float : UNRESOLVED_float (r'range);
4871  begin
4872    l_float := to_float(l, r'high, -r'low);
4873    return add (l_float, r);
4874  end function "+";
4875
4876  function "+" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float is
4877    variable r_float : UNRESOLVED_float (l'range);
4878  begin
4879    r_float := to_float (r, l'high, -l'low);
4880    return add (l, r_float);
4881  end function "+";
4882
4883  function "+" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float is
4884    variable l_float : UNRESOLVED_float (r'range);
4885  begin
4886    l_float := to_float(l, r'high, -r'low);
4887    return add (l_float, r);
4888  end function "+";
4889
4890  function "-" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float is
4891    variable r_float : UNRESOLVED_float (l'range);
4892  begin
4893    r_float := to_float (r, l'high, -l'low);
4894    return subtract (l, r_float);
4895  end function "-";
4896
4897  function "-" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float is
4898    variable l_float : UNRESOLVED_float (r'range);
4899  begin
4900    l_float := to_float(l, r'high, -r'low);
4901    return subtract (l_float, r);
4902  end function "-";
4903
4904  function "-" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float is
4905    variable r_float : UNRESOLVED_float (l'range);
4906  begin
4907    r_float := to_float (r, l'high, -l'low);
4908    return subtract (l, r_float);
4909  end function "-";
4910
4911  function "-" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float is
4912    variable l_float : UNRESOLVED_float (r'range);
4913  begin
4914    l_float := to_float(l, r'high, -r'low);
4915    return subtract (l_float, r);
4916  end function "-";
4917
4918  function "*" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float is
4919    variable r_float : UNRESOLVED_float (l'range);
4920  begin
4921    r_float := to_float (r, l'high, -l'low);
4922    return multiply (l, r_float);
4923  end function "*";
4924
4925  function "*" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float is
4926    variable l_float : UNRESOLVED_float (r'range);
4927  begin
4928    l_float := to_float(l, r'high, -r'low);
4929    return multiply (l_float, r);
4930  end function "*";
4931
4932  function "*" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float is
4933    variable r_float : UNRESOLVED_float (l'range);
4934  begin
4935    r_float := to_float (r, l'high, -l'low);
4936    return multiply (l, r_float);
4937  end function "*";
4938
4939  function "*" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float is
4940    variable l_float : UNRESOLVED_float (r'range);
4941  begin
4942    l_float := to_float(l, r'high, -r'low);
4943    return multiply (l_float, r);
4944  end function "*";
4945
4946  function "/" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float is
4947    variable r_float : UNRESOLVED_float (l'range);
4948  begin
4949    r_float := to_float (r, l'high, -l'low);
4950    return divide (l, r_float);
4951  end function "/";
4952
4953  function "/" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float is
4954    variable l_float : UNRESOLVED_float (r'range);
4955  begin
4956    l_float := to_float(l, r'high, -r'low);
4957    return divide (l_float, r);
4958  end function "/";
4959
4960  function "/" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float is
4961    variable r_float : UNRESOLVED_float (l'range);
4962  begin
4963    r_float := to_float (r, l'high, -l'low);
4964    return divide (l, r_float);
4965  end function "/";
4966
4967  function "/" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float is
4968    variable l_float : UNRESOLVED_float (r'range);
4969  begin
4970    l_float := to_float(l, r'high, -r'low);
4971    return divide (l_float, r);
4972  end function "/";
4973
4974  function "rem" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float is
4975    variable r_float : UNRESOLVED_float (l'range);
4976  begin
4977    r_float := to_float (r, l'high, -l'low);
4978    return remainder (l, r_float);
4979  end function "rem";
4980
4981  function "rem" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float is
4982    variable l_float : UNRESOLVED_float (r'range);
4983  begin
4984    l_float := to_float(l, r'high, -r'low);
4985    return remainder (l_float, r);
4986  end function "rem";
4987
4988  function "rem" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float is
4989    variable r_float : UNRESOLVED_float (l'range);
4990  begin
4991    r_float := to_float (r, l'high, -l'low);
4992    return remainder (l, r_float);
4993  end function "rem";
4994
4995  function "rem" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float is
4996    variable l_float : UNRESOLVED_float (r'range);
4997  begin
4998    l_float := to_float(l, r'high, -r'low);
4999    return remainder (l_float, r);
5000  end function "rem";
5001
5002  function "mod" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float is
5003    variable r_float : UNRESOLVED_float (l'range);
5004  begin
5005    r_float := to_float (r, l'high, -l'low);
5006    return modulo (l, r_float);
5007  end function "mod";
5008
5009  function "mod" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float is
5010    variable l_float : UNRESOLVED_float (r'range);
5011  begin
5012    l_float := to_float(l, r'high, -r'low);
5013    return modulo (l_float, r);
5014  end function "mod";
5015
5016  function "mod" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float is
5017    variable r_float : UNRESOLVED_float (l'range);
5018  begin
5019    r_float := to_float (r, l'high, -l'low);
5020    return modulo (l, r_float);
5021  end function "mod";
5022
5023  function "mod" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float is
5024    variable l_float : UNRESOLVED_float (r'range);
5025  begin
5026    l_float := to_float(l, r'high, -r'low);
5027    return modulo (l_float, r);
5028  end function "mod";
5029
5030  function "=" (l : UNRESOLVED_float; r : REAL) return BOOLEAN is
5031    variable r_float : UNRESOLVED_float (l'range);
5032  begin
5033    r_float := to_float (r, l'high, -l'low);
5034    return eq (l, r_float);
5035  end function "=";
5036
5037  function "/=" (l : UNRESOLVED_float; r : REAL) return BOOLEAN is
5038    variable r_float : UNRESOLVED_float (l'range);
5039  begin
5040    r_float := to_float (r, l'high, -l'low);
5041    return ne (l, r_float);
5042  end function "/=";
5043
5044  function ">=" (l : UNRESOLVED_float; r : REAL) return BOOLEAN is
5045    variable r_float : UNRESOLVED_float (l'range);
5046  begin
5047    r_float := to_float (r, l'high, -l'low);
5048    return ge (l, r_float);
5049  end function ">=";
5050
5051  function "<=" (l : UNRESOLVED_float; r : REAL) return BOOLEAN is
5052    variable r_float : UNRESOLVED_float (l'range);
5053  begin
5054    r_float := to_float (r, l'high, -l'low);
5055    return le (l, r_float);
5056  end function "<=";
5057
5058  function ">" (l : UNRESOLVED_float; r : REAL) return BOOLEAN is
5059    variable r_float : UNRESOLVED_float (l'range);
5060  begin
5061    r_float := to_float (r, l'high, -l'low);
5062    return gt (l, r_float);
5063  end function ">";
5064
5065  function "<" (l : UNRESOLVED_float; r : REAL) return BOOLEAN is
5066    variable r_float : UNRESOLVED_float (l'range);
5067  begin
5068    r_float := to_float (r, l'high, -l'low);
5069    return lt (l, r_float);
5070  end function "<";
5071
5072  function "=" (l : REAL; r : UNRESOLVED_float) return BOOLEAN is
5073    variable l_float : UNRESOLVED_float (r'range);
5074  begin
5075    l_float := to_float(l, r'high, -r'low);
5076    return eq (l_float, r);
5077  end function "=";
5078
5079  function "/=" (l : REAL; r : UNRESOLVED_float) return BOOLEAN is
5080    variable l_float : UNRESOLVED_float (r'range);
5081  begin
5082    l_float := to_float(l, r'high, -r'low);
5083    return ne (l_float, r);
5084  end function "/=";
5085
5086  function ">=" (l : REAL; r : UNRESOLVED_float) return BOOLEAN is
5087    variable l_float : UNRESOLVED_float (r'range);
5088  begin
5089    l_float := to_float(l, r'high, -r'low);
5090    return ge (l_float, r);
5091  end function ">=";
5092
5093  function "<=" (l : REAL; r : UNRESOLVED_float) return BOOLEAN is
5094    variable l_float : UNRESOLVED_float (r'range);
5095  begin
5096    l_float := to_float(l, r'high, -r'low);
5097    return le (l_float, r);
5098  end function "<=";
5099
5100  function ">" (l : REAL; r : UNRESOLVED_float) return BOOLEAN is
5101    variable l_float : UNRESOLVED_float (r'range);
5102  begin
5103    l_float := to_float(l, r'high, -r'low);
5104    return gt (l_float, r);
5105  end function ">";
5106
5107  function "<" (l : REAL; r : UNRESOLVED_float) return BOOLEAN is
5108    variable l_float : UNRESOLVED_float (r'range);
5109  begin
5110    l_float := to_float(l, r'high, -r'low);
5111    return lt (l_float, r);
5112  end function "<";
5113
5114  function "=" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN is
5115    variable r_float : UNRESOLVED_float (l'range);
5116  begin
5117    r_float := to_float (r, l'high, -l'low);
5118    return eq (l, r_float);
5119  end function "=";
5120
5121  function "/=" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN is
5122    variable r_float : UNRESOLVED_float (l'range);
5123  begin
5124    r_float := to_float (r, l'high, -l'low);
5125    return ne (l, r_float);
5126  end function "/=";
5127
5128  function ">=" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN is
5129    variable r_float : UNRESOLVED_float (l'range);
5130  begin
5131    r_float := to_float (r, l'high, -l'low);
5132    return ge (l, r_float);
5133  end function ">=";
5134
5135  function "<=" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN is
5136    variable r_float : UNRESOLVED_float (l'range);
5137  begin
5138    r_float := to_float (r, l'high, -l'low);
5139    return le (l, r_float);
5140  end function "<=";
5141
5142  function ">" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN is
5143    variable r_float : UNRESOLVED_float (l'range);
5144  begin
5145    r_float := to_float (r, l'high, -l'low);
5146    return gt (l, r_float);
5147  end function ">";
5148
5149  function "<" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN is
5150    variable r_float : UNRESOLVED_float (l'range);
5151  begin
5152    r_float := to_float (r, l'high, -l'low);
5153    return lt (l, r_float);
5154  end function "<";
5155
5156  function "=" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN is
5157    variable l_float : UNRESOLVED_float (r'range);
5158  begin
5159    l_float := to_float(l, r'high, -r'low);
5160    return eq (l_float, r);
5161  end function "=";
5162
5163  function "/=" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN is
5164    variable l_float : UNRESOLVED_float (r'range);
5165  begin
5166    l_float := to_float(l, r'high, -r'low);
5167    return ne (l_float, r);
5168  end function "/=";
5169
5170  function ">=" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN is
5171    variable l_float : UNRESOLVED_float (r'range);
5172  begin
5173    l_float := to_float(l, r'high, -r'low);
5174    return ge (l_float, r);
5175  end function ">=";
5176
5177  function "<=" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN is
5178    variable l_float : UNRESOLVED_float (r'range);
5179  begin
5180    l_float := to_float(l, r'high, -r'low);
5181    return le (l_float, r);
5182  end function "<=";
5183
5184  function ">" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN is
5185    variable l_float : UNRESOLVED_float (r'range);
5186  begin
5187    l_float := to_float(l, r'high, -r'low);
5188    return gt (l_float, r);
5189  end function ">";
5190
5191  function "<" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN is
5192    variable l_float : UNRESOLVED_float (r'range);
5193  begin
5194    l_float := to_float(l, r'high, -r'low);
5195    return lt (l_float, r);
5196  end function "<";
5197
5198  -- ?= overloads
5199  function \?=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC is
5200    variable r_float : UNRESOLVED_float (l'range);
5201  begin
5202    r_float := to_float (r, l'high, -l'low);
5203    return \?=\ (l, r_float);
5204  end function \?=\;
5205
5206  function \?/=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC is
5207    variable r_float : UNRESOLVED_float (l'range);
5208  begin
5209    r_float := to_float (r, l'high, -l'low);
5210    return \?/=\ (l, r_float);
5211  end function \?/=\;
5212
5213  function \?>\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC is
5214    variable r_float : UNRESOLVED_float (l'range);
5215  begin
5216    r_float := to_float (r, l'high, -l'low);
5217    return \?>\ (l, r_float);
5218  end function \?>\;
5219
5220  function \?>=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC is
5221    variable r_float : UNRESOLVED_float (l'range);
5222  begin
5223    r_float := to_float (r, l'high, -l'low);
5224    return \?>=\ (l, r_float);
5225  end function \?>=\;
5226
5227  function \?<\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC is
5228    variable r_float : UNRESOLVED_float (l'range);
5229  begin
5230    r_float := to_float (r, l'high, -l'low);
5231    return \?<\ (l, r_float);
5232  end function \?<\;
5233
5234  function \?<=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC is
5235    variable r_float : UNRESOLVED_float (l'range);
5236  begin
5237    r_float := to_float (r, l'high, -l'low);
5238    return \?<=\ (l, r_float);
5239  end function \?<=\;
5240
5241  -- real and float
5242  function \?=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC is
5243    variable l_float : UNRESOLVED_float (r'range);
5244  begin
5245    l_float := to_float (l, r'high, -r'low);
5246    return \?=\ (l_float, r);
5247  end function \?=\;
5248
5249  function \?/=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC is
5250    variable l_float : UNRESOLVED_float (r'range);
5251  begin
5252    l_float := to_float (l, r'high, -r'low);
5253    return \?/=\ (l_float, r);
5254  end function \?/=\;
5255
5256  function \?>\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC is
5257    variable l_float : UNRESOLVED_float (r'range);
5258  begin
5259    l_float := to_float (l, r'high, -r'low);
5260    return \?>\ (l_float, r);
5261  end function \?>\;
5262
5263  function \?>=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC is
5264    variable l_float : UNRESOLVED_float (r'range);
5265  begin
5266    l_float := to_float (l, r'high, -r'low);
5267    return \?>=\ (l_float, r);
5268  end function \?>=\;
5269
5270  function \?<\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC is
5271    variable l_float : UNRESOLVED_float (r'range);
5272  begin
5273    l_float := to_float (l, r'high, -r'low);
5274    return \?<\ (l_float, r);
5275  end function \?<\;
5276
5277  function \?<=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC is
5278    variable l_float : UNRESOLVED_float (r'range);
5279  begin
5280    l_float := to_float (l, r'high, -r'low);
5281    return \?<=\ (l_float, r);
5282  end function \?<=\;
5283
5284  -- ?= overloads
5285  function \?=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC is
5286    variable r_float : UNRESOLVED_float (l'range);
5287  begin
5288    r_float := to_float (r, l'high, -l'low);
5289    return \?=\ (l, r_float);
5290  end function \?=\;
5291
5292  function \?/=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC is
5293    variable r_float : UNRESOLVED_float (l'range);
5294  begin
5295    r_float := to_float (r, l'high, -l'low);
5296    return \?/=\ (l, r_float);
5297  end function \?/=\;
5298
5299  function \?>\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC is
5300    variable r_float : UNRESOLVED_float (l'range);
5301  begin
5302    r_float := to_float (r, l'high, -l'low);
5303    return \?>\ (l, r_float);
5304  end function \?>\;
5305
5306  function \?>=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC is
5307    variable r_float : UNRESOLVED_float (l'range);
5308  begin
5309    r_float := to_float (r, l'high, -l'low);
5310    return \?>=\ (l, r_float);
5311  end function \?>=\;
5312
5313  function \?<\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC is
5314    variable r_float : UNRESOLVED_float (l'range);
5315  begin
5316    r_float := to_float (r, l'high, -l'low);
5317    return \?<\ (l, r_float);
5318  end function \?<\;
5319
5320  function \?<=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC is
5321    variable r_float : UNRESOLVED_float (l'range);
5322  begin
5323    r_float := to_float (r, l'high, -l'low);
5324    return \?<=\ (l, r_float);
5325  end function \?<=\;
5326
5327  -- integer and float
5328  function \?=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC is
5329    variable l_float : UNRESOLVED_float (r'range);
5330  begin
5331    l_float := to_float (l, r'high, -r'low);
5332    return \?=\ (l_float, r);
5333  end function \?=\;
5334
5335  function \?/=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC is
5336    variable l_float : UNRESOLVED_float (r'range);
5337  begin
5338    l_float := to_float (l, r'high, -r'low);
5339    return \?/=\ (l_float, r);
5340  end function \?/=\;
5341
5342  function \?>\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC is
5343    variable l_float : UNRESOLVED_float (r'range);
5344  begin
5345    l_float := to_float (l, r'high, -r'low);
5346    return \?>\ (l_float, r);
5347  end function \?>\;
5348
5349  function \?>=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC is
5350    variable l_float : UNRESOLVED_float (r'range);
5351  begin
5352    l_float := to_float (l, r'high, -r'low);
5353    return \?>=\ (l_float, r);
5354  end function \?>=\;
5355
5356  function \?<\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC is
5357    variable l_float : UNRESOLVED_float (r'range);
5358  begin
5359    l_float := to_float (l, r'high, -r'low);
5360    return \?<\ (l_float, r);
5361  end function \?<\;
5362
5363  function \?<=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC is
5364    variable l_float : UNRESOLVED_float (r'range);
5365  begin
5366    l_float := to_float (l, r'high, -r'low);
5367    return \?<=\ (l_float, r);
5368  end function \?<=\;
5369
5370  -- minimum and maximum overloads
5371  function minimum (l : UNRESOLVED_float; r : REAL)
5372    return UNRESOLVED_float is
5373    variable r_float : UNRESOLVED_float (l'range);
5374  begin
5375    r_float := to_float (r, l'high, -l'low);
5376    return minimum (l, r_float);
5377  end function minimum;
5378
5379  function maximum (l : UNRESOLVED_float; r : REAL)
5380    return UNRESOLVED_float is
5381    variable r_float : UNRESOLVED_float (l'range);
5382  begin
5383    r_float := to_float (r, l'high, -l'low);
5384    return maximum (l, r_float);
5385  end function maximum;
5386
5387  function minimum (l : REAL; r : UNRESOLVED_float)
5388    return UNRESOLVED_float is
5389    variable l_float : UNRESOLVED_float (r'range);
5390  begin
5391    l_float := to_float (l, r'high, -r'low);
5392    return minimum (l_float, r);
5393  end function minimum;
5394
5395  function maximum (l : REAL; r : UNRESOLVED_float)
5396    return UNRESOLVED_float is
5397    variable l_float : UNRESOLVED_float (r'range);
5398  begin
5399    l_float := to_float (l, r'high, -r'low);
5400    return maximum (l_float, r);
5401  end function maximum;
5402
5403  function minimum (l : UNRESOLVED_float; r : INTEGER)
5404    return UNRESOLVED_float is
5405    variable r_float : UNRESOLVED_float (l'range);
5406  begin
5407    r_float := to_float (r, l'high, -l'low);
5408    return minimum (l, r_float);
5409  end function minimum;
5410
5411  function maximum (l : UNRESOLVED_float; r : INTEGER)
5412    return UNRESOLVED_float is
5413    variable r_float : UNRESOLVED_float (l'range);
5414  begin
5415    r_float := to_float (r, l'high, -l'low);
5416    return maximum (l, r_float);
5417  end function maximum;
5418
5419  function minimum (l : INTEGER; r : UNRESOLVED_float)
5420    return UNRESOLVED_float is
5421    variable l_float : UNRESOLVED_float (r'range);
5422  begin
5423    l_float := to_float (l, r'high, -r'low);
5424    return minimum (l_float, r);
5425  end function minimum;
5426
5427  function maximum (l : INTEGER; r : UNRESOLVED_float)
5428    return UNRESOLVED_float is
5429    variable l_float : UNRESOLVED_float (r'range);
5430  begin
5431    l_float := to_float (l, r'high, -r'low);
5432    return maximum (l_float, r);
5433  end function maximum;
5434
5435  ----------------------------------------------------------------------------
5436  -- logical functions
5437  ----------------------------------------------------------------------------
5438  function "not" (L : UNRESOLVED_float) return UNRESOLVED_float is
5439    variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0);  -- force downto
5440  begin
5441    RESULT := not to_sulv(L);
5442    return to_float (RESULT, L'high, -L'low);
5443  end function "not";
5444
5445  function "and" (L, R : UNRESOLVED_float) return UNRESOLVED_float is
5446    variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0);  -- force downto
5447   begin
5448     if (L'high = R'high and L'low = R'low) then
5449      RESULT := to_sulv(L) and to_sulv(R);
5450    else
5451      assert NO_WARNING
5452        report float_pkg'instance_name
5453        & """and"": Range error L'RANGE /= R'RANGE"
5454        severity warning;
5455      RESULT := (others => 'X');
5456    end if;
5457    return to_float (RESULT, L'high, -L'low);
5458  end function "and";
5459
5460  function "or" (L, R : UNRESOLVED_float) return UNRESOLVED_float is
5461    variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0);  -- force downto
5462  begin
5463     if (L'high = R'high and L'low = R'low) then
5464      RESULT := to_sulv(L) or to_sulv(R);
5465    else
5466      assert NO_WARNING
5467        report float_pkg'instance_name
5468        & """or"": Range error L'RANGE /= R'RANGE"
5469        severity warning;
5470      RESULT := (others => 'X');
5471    end if;
5472    return to_float (RESULT, L'high, -L'low);
5473  end function "or";
5474
5475  function "nand" (L, R : UNRESOLVED_float) return UNRESOLVED_float is
5476    variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0);  -- force downto
5477  begin
5478     if (L'high = R'high and L'low = R'low) then
5479      RESULT := to_sulv(L) nand to_sulv(R);
5480    else
5481      assert NO_WARNING
5482        report float_pkg'instance_name
5483        & """nand"": Range error L'RANGE /= R'RANGE"
5484        severity warning;
5485      RESULT := (others => 'X');
5486    end if;
5487    return to_float (RESULT, L'high, -L'low);
5488  end function "nand";
5489
5490  function "nor" (L, R : UNRESOLVED_float) return UNRESOLVED_float is
5491    variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0);  -- force downto
5492  begin
5493     if (L'high = R'high and L'low = R'low) then
5494      RESULT := to_sulv(L) nor to_sulv(R);
5495    else
5496      assert NO_WARNING
5497        report float_pkg'instance_name
5498        & """nor"": Range error L'RANGE /= R'RANGE"
5499        severity warning;
5500      RESULT := (others => 'X');
5501    end if;
5502    return to_float (RESULT, L'high, -L'low);
5503  end function "nor";
5504
5505  function "xor" (L, R : UNRESOLVED_float) return UNRESOLVED_float is
5506    variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0);  -- force downto
5507  begin
5508     if (L'high = R'high and L'low = R'low) then
5509      RESULT := to_sulv(L) xor to_sulv(R);
5510    else
5511      assert NO_WARNING
5512        report float_pkg'instance_name
5513        & """xor"": Range error L'RANGE /= R'RANGE"
5514        severity warning;
5515      RESULT := (others => 'X');
5516    end if;
5517    return to_float (RESULT, L'high, -L'low);
5518  end function "xor";
5519
5520  function "xnor" (L, R : UNRESOLVED_float) return UNRESOLVED_float is
5521    variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0);  -- force downto
5522  begin
5523     if (L'high = R'high and L'low = R'low) then
5524      RESULT := to_sulv(L) xnor to_sulv(R);
5525    else
5526      assert NO_WARNING
5527        report float_pkg'instance_name
5528        & """xnor"": Range error L'RANGE /= R'RANGE"
5529        severity warning;
5530      RESULT := (others => 'X');
5531    end if;
5532    return to_float (RESULT, L'high, -L'low);
5533  end function "xnor";
5534
5535  -- Vector and std_ulogic functions, same as functions in numeric_std
5536  function "and" (L : STD_ULOGIC; R : UNRESOLVED_float)
5537    return UNRESOLVED_float is
5538    variable result : UNRESOLVED_float (R'range);
5539  begin
5540    for i in result'range loop
5541      result(i) := L and R(i);
5542    end loop;
5543    return result;
5544  end function "and";
5545
5546  function "and" (L : UNRESOLVED_float; R : STD_ULOGIC)
5547    return UNRESOLVED_float is
5548    variable result : UNRESOLVED_float (L'range);
5549  begin
5550    for i in result'range loop
5551      result(i) := L(i) and R;
5552    end loop;
5553    return result;
5554  end function "and";
5555
5556  function "or" (L : STD_ULOGIC; R : UNRESOLVED_float)
5557    return UNRESOLVED_float is
5558    variable result : UNRESOLVED_float (R'range);
5559  begin
5560    for i in result'range loop
5561      result(i) := L or R(i);
5562    end loop;
5563    return result;
5564  end function "or";
5565
5566  function "or" (L : UNRESOLVED_float; R : STD_ULOGIC)
5567    return UNRESOLVED_float is
5568    variable result : UNRESOLVED_float (L'range);
5569  begin
5570    for i in result'range loop
5571      result(i) := L(i) or R;
5572    end loop;
5573    return result;
5574  end function "or";
5575
5576  function "nand" (L : STD_ULOGIC; R : UNRESOLVED_float)
5577    return UNRESOLVED_float is
5578    variable result : UNRESOLVED_float (R'range);
5579  begin
5580    for i in result'range loop
5581      result(i) := L nand R(i);
5582    end loop;
5583    return result;
5584  end function "nand";
5585
5586  function "nand" (L : UNRESOLVED_float; R : STD_ULOGIC)
5587    return UNRESOLVED_float is
5588    variable result : UNRESOLVED_float (L'range);
5589  begin
5590    for i in result'range loop
5591      result(i) := L(i) nand R;
5592    end loop;
5593    return result;
5594  end function "nand";
5595
5596  function "nor" (L : STD_ULOGIC; R : UNRESOLVED_float)
5597    return UNRESOLVED_float is
5598    variable result : UNRESOLVED_float (R'range);
5599  begin
5600    for i in result'range loop
5601      result(i) := L nor R(i);
5602    end loop;
5603    return result;
5604  end function "nor";
5605
5606  function "nor" (L : UNRESOLVED_float; R : STD_ULOGIC)
5607    return UNRESOLVED_float is
5608    variable result : UNRESOLVED_float (L'range);
5609  begin
5610    for i in result'range loop
5611      result(i) := L(i) nor R;
5612    end loop;
5613    return result;
5614  end function "nor";
5615
5616  function "xor" (L : STD_ULOGIC; R : UNRESOLVED_float)
5617    return UNRESOLVED_float is
5618    variable result : UNRESOLVED_float (R'range);
5619  begin
5620    for i in result'range loop
5621      result(i) := L xor R(i);
5622    end loop;
5623    return result;
5624  end function "xor";
5625
5626  function "xor" (L : UNRESOLVED_float; R : STD_ULOGIC)
5627    return UNRESOLVED_float is
5628    variable result : UNRESOLVED_float (L'range);
5629  begin
5630    for i in result'range loop
5631      result(i) := L(i) xor R;
5632    end loop;
5633    return result;
5634  end function "xor";
5635
5636  function "xnor" (L : STD_ULOGIC; R : UNRESOLVED_float)
5637    return UNRESOLVED_float is
5638    variable result : UNRESOLVED_float (R'range);
5639  begin
5640    for i in result'range loop
5641      result(i) := L xnor R(i);
5642    end loop;
5643    return result;
5644  end function "xnor";
5645
5646  function "xnor" (L : UNRESOLVED_float; R : STD_ULOGIC)
5647    return UNRESOLVED_float is
5648    variable result : UNRESOLVED_float (L'range);
5649  begin
5650    for i in result'range loop
5651      result(i) := L(i) xnor R;
5652    end loop;
5653    return result;
5654  end function "xnor";
5655
5656  -- Reduction operator_reduces, same as numeric_std functions
5657
5658  function and_reduce (l : UNRESOLVED_float) return STD_ULOGIC is
5659  begin
5660    return and_reduce (to_sulv(l));
5661  end function and_reduce;
5662
5663  function nand_reduce (l : UNRESOLVED_float) return STD_ULOGIC is
5664  begin
5665    return nand_reduce (to_sulv(l));
5666  end function nand_reduce;
5667
5668  function or_reduce (l : UNRESOLVED_float) return STD_ULOGIC is
5669  begin
5670    return or_reduce (to_sulv(l));
5671  end function or_reduce;
5672
5673  function nor_reduce (l : UNRESOLVED_float) return STD_ULOGIC is
5674  begin
5675    return nor_reduce (to_sulv(l));
5676  end function nor_reduce;
5677
5678  function xor_reduce (l : UNRESOLVED_float) return STD_ULOGIC is
5679  begin
5680    return xor_reduce (to_sulv(l));
5681  end function xor_reduce;
5682
5683  function xnor_reduce (l : UNRESOLVED_float) return STD_ULOGIC is
5684  begin
5685    return xnor_reduce (to_sulv(l));
5686  end function xnor_reduce;
5687
5688  -----------------------------------------------------------------------------
5689  -- Recommended Functions from the IEEE 754 Appendix
5690  -----------------------------------------------------------------------------
5691  -- returns x with the sign of y.
5692  function Copysign (
5693    x, y : UNRESOLVED_float)            -- floating point input
5694    return UNRESOLVED_float is
5695  begin
5696    return y(y'high) & x (x'high-1 downto x'low);
5697  end function Copysign;
5698
5699  -- Returns y * 2**n for integral values of N without computing 2**n
5700  function Scalb (
5701    y                    : UNRESOLVED_float;      -- floating point input
5702    N                    : INTEGER;     -- exponent to add
5703    constant round_style : round_type := float_round_style;  -- rounding option
5704    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
5705    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
5706    return UNRESOLVED_float is
5707    constant fraction_width : NATURAL := -mine(y'low, y'low);  -- length of FP output fraction
5708    constant exponent_width : NATURAL := y'high;  -- length of FP output exponent
5709    variable arg, result    : UNRESOLVED_float (exponent_width downto -fraction_width);  -- internal argument
5710    variable expon          : SIGNED (exponent_width-1 downto 0);  -- Vectorized exp
5711    variable exp            : SIGNED (exponent_width downto 0);
5712    variable ufract         : UNSIGNED (fraction_width downto 0);
5713    constant expon_base     : SIGNED (exponent_width-1 downto 0)
5714      := gen_expon_base(exponent_width);          -- exponent offset
5715    variable fptype : valid_fpstate;
5716  begin
5717    -- This can be done by simply adding N to the exponent.
5718    arg    := to_01 (y, 'X');
5719    fptype := classfp(arg, check_error);
5720    classcase : case fptype is
5721      when isx =>
5722        result := (others => 'X');
5723      when nan | quiet_nan =>
5724        -- Return quiet NAN, IEEE754-1985-7.1,1
5725        result := qnanfp (fraction_width => fraction_width,
5726                          exponent_width => exponent_width);
5727      when others =>
5728        break_number (
5729          arg         => arg,
5730          fptyp       => fptype,
5731          denormalize => denormalize,
5732          fract       => ufract,
5733          expon       => expon);
5734        exp := resize (expon, exp'length) + N;
5735        result := normalize (
5736          fract          => ufract,
5737          expon          => exp,
5738          sign           => to_x01 (arg (arg'high)),
5739          fraction_width => fraction_width,
5740          exponent_width => exponent_width,
5741          round_style    => round_style,
5742          denormalize    => denormalize,
5743          nguard         => 0);
5744    end case classcase;
5745    return result;
5746  end function Scalb;
5747
5748  -- Returns y * 2**n for integral values of N without computing 2**n
5749  function Scalb (
5750    y                    : UNRESOLVED_float;  -- floating point input
5751    N                    : SIGNED;      -- exponent to add
5752    constant round_style : round_type := float_round_style;  -- rounding option
5753    constant check_error : BOOLEAN    := float_check_error;  -- check for errors
5754    constant denormalize : BOOLEAN    := float_denormalize)  -- Use IEEE extended FP
5755    return UNRESOLVED_float is
5756    variable n_int : INTEGER;
5757  begin
5758    n_int := to_integer(N);
5759    return Scalb (y           => y,
5760                  N           => n_int,
5761                  round_style => round_style,
5762                  check_error => check_error,
5763                  denormalize => denormalize);
5764  end function Scalb;
5765
5766  -- returns the unbiased exponent of x
5767  function Logb (
5768    x : UNRESOLVED_float)               -- floating point input
5769    return INTEGER is
5770    constant fraction_width : NATURAL := -mine (x'low, x'low);  -- length of FP output fraction
5771    constant exponent_width : NATURAL := x'high;  -- length of FP output exponent
5772    variable result         : INTEGER;  -- result
5773    variable arg            : UNRESOLVED_float (exponent_width downto -fraction_width);  -- internal argument
5774    variable expon          : SIGNED (exponent_width - 1 downto 0);
5775    variable fract          : UNSIGNED (fraction_width downto 0);
5776    constant expon_base     : INTEGER := 2**(exponent_width-1) -1;  -- exponent
5777                                        -- offset +1
5778    variable fptype         : valid_fpstate;
5779  begin
5780    -- Just return the exponent.
5781    arg    := to_01 (x, 'X');
5782    fptype := classfp(arg);
5783    classcase : case fptype is
5784      when isx | nan | quiet_nan =>
5785        -- Return quiet NAN, IEEE754-1985-7.1,1
5786        result := 0;
5787      when pos_denormal | neg_denormal =>
5788        fract (fraction_width) := '0';
5789        fract (fraction_width-1 downto 0) :=
5790          UNSIGNED (to_slv(arg(-1 downto -fraction_width)));
5791        result := find_leftmost (fract, '1')      -- Find the first "1"
5792                  - fraction_width;     -- subtract the length we want
5793        result := -expon_base + 1 + result;
5794      when others =>
5795        expon                   := SIGNED(arg (exponent_width - 1 downto 0));
5796        expon(exponent_width-1) := not expon(exponent_width-1);
5797        expon                   := expon + 1;
5798        result                  := to_integer (expon);
5799    end case classcase;
5800    return result;
5801  end function Logb;
5802
5803  -- returns the unbiased exponent of x
5804  function Logb (
5805    x : UNRESOLVED_float)               -- floating point input
5806    return SIGNED is
5807    constant exponent_width : NATURAL := x'high;  -- length of FP output exponent
5808    variable result         : SIGNED (exponent_width - 1 downto 0);  -- result
5809  begin
5810    -- Just return the exponent.
5811    result := to_signed (Logb (x), exponent_width);
5812    return result;
5813  end function Logb;
5814
5815  -- returns the next representable neighbor of x in the direction toward y
5816  function Nextafter (
5817    x, y                 : UNRESOLVED_float;      -- floating point input
5818    constant check_error : BOOLEAN := float_check_error;  -- check for errors
5819    constant denormalize : BOOLEAN := float_denormalize)
5820    return UNRESOLVED_float is
5821    constant fraction_width : NATURAL := -mine(x'low, x'low);  -- length of FP output fraction
5822    constant exponent_width : NATURAL := x'high;  -- length of FP output exponent
5823    function "=" (
5824      l, r : UNRESOLVED_float)          -- inputs
5825      return BOOLEAN is
5826    begin  -- function "="
5827      return eq (l           => l,
5828                 r           => r,
5829                 check_error => false);
5830    end function "=";
5831    function ">" (
5832      l, r : UNRESOLVED_float)          -- inputs
5833      return BOOLEAN is
5834    begin  -- function ">"
5835      return gt (l           => l,
5836                 r           => r,
5837                 check_error => false);
5838    end function ">";
5839    variable fract              : UNSIGNED (fraction_width-1 downto 0);
5840    variable expon              : UNSIGNED (exponent_width-1 downto 0);
5841    variable sign               : STD_ULOGIC;
5842    variable result             : UNRESOLVED_float (exponent_width downto -fraction_width);
5843    variable validfpx, validfpy : valid_fpstate;  -- Valid FP state
5844  begin  -- fp_Nextafter
5845    -- If Y > X, add one to the fraction, otherwise subtract.
5846    validfpx := classfp (x, check_error);
5847    validfpy := classfp (y, check_error);
5848    if validfpx = isx or validfpy = isx then
5849      result := (others => 'X');
5850      return result;
5851    elsif (validfpx = nan or validfpy = nan) then
5852      return nanfp (fraction_width => fraction_width,
5853                    exponent_width => exponent_width);
5854    elsif (validfpx = quiet_nan or validfpy = quiet_nan) then
5855      return qnanfp (fraction_width => fraction_width,
5856                     exponent_width => exponent_width);
5857    elsif x = y then                    -- Return X
5858      return x;
5859    else
5860      fract := UNSIGNED (to_slv (x (-1 downto -fraction_width)));  -- Fraction
5861      expon := UNSIGNED (x (exponent_width - 1 downto 0));     -- exponent
5862      sign  := x(exponent_width);       -- sign bit
5863      if (y > x) then
5864        -- Increase the number given
5865        if validfpx = neg_inf then
5866          -- return most negative number
5867          expon     := (others => '1');
5868          expon (0) := '0';
5869          fract     := (others => '1');
5870        elsif validfpx = pos_zero or validfpx = neg_zero then
5871          -- return smallest denormal number
5872          sign     := '0';
5873          expon    := (others => '0');
5874          fract    := (others => '0');
5875          fract(0) := '1';
5876        elsif validfpx = pos_normal then
5877          if and_reduce (fract) = '1' then        -- fraction is all "1".
5878            if and_reduce (expon (exponent_width-1 downto 1)) = '1'
5879              and expon (0) = '0' then
5880                                        -- Exponent is one away from infinity.
5881              assert NO_WARNING
5882                report float_pkg'instance_name
5883                & "FP_NEXTAFTER: NextAfter overflow"
5884                severity warning;
5885              return pos_inffp (fraction_width => fraction_width,
5886                                exponent_width => exponent_width);
5887            else
5888              expon := expon + 1;
5889              fract := (others => '0');
5890            end if;
5891          else
5892            fract := fract + 1;
5893          end if;
5894        elsif validfpx = pos_denormal then
5895          if and_reduce (fract) = '1' then        -- fraction is all "1".
5896            -- return smallest possible normal number
5897            expon    := (others => '0');
5898            expon(0) := '1';
5899            fract    := (others => '0');
5900          else
5901            fract := fract + 1;
5902          end if;
5903        elsif validfpx = neg_normal then
5904          if or_reduce (fract) = '0' then         -- fraction is all "0".
5905            if or_reduce (expon (exponent_width-1 downto 1)) = '0' and
5906              expon (0) = '1' then      -- Smallest exponent
5907              -- return the largest negative denormal number
5908              expon := (others => '0');
5909              fract := (others => '1');
5910            else
5911              expon := expon - 1;
5912              fract := (others => '1');
5913            end if;
5914          else
5915            fract := fract - 1;
5916          end if;
5917        elsif validfpx = neg_denormal then
5918          if or_reduce (fract(fract'high downto 1)) = '0'
5919            and fract (0) = '1' then    -- Smallest possible fraction
5920            return zerofp (fraction_width => fraction_width,
5921                           exponent_width => exponent_width);
5922          else
5923            fract := fract - 1;
5924          end if;
5925        end if;
5926      else
5927        -- Decrease the number
5928        if validfpx = pos_inf then
5929          -- return most positive number
5930          expon     := (others => '1');
5931          expon (0) := '0';
5932          fract     := (others => '1');
5933        elsif validfpx = pos_zero
5934          or classfp (x) = neg_zero then
5935          -- return smallest negative denormal number
5936          sign     := '1';
5937          expon    := (others => '0');
5938          fract    := (others => '0');
5939          fract(0) := '1';
5940        elsif validfpx = neg_normal then
5941          if and_reduce (fract) = '1' then        -- fraction is all "1".
5942            if and_reduce (expon (exponent_width-1 downto 1)) = '1'
5943              and expon (0) = '0' then
5944                                        -- Exponent is one away from infinity.
5945              assert NO_WARNING
5946                report float_pkg'instance_name
5947                & "FP_NEXTAFTER: NextAfter overflow"
5948                severity warning;
5949              return neg_inffp (fraction_width => fraction_width,
5950                                exponent_width => exponent_width);
5951            else
5952              expon := expon + 1;       -- Fraction overflow
5953              fract := (others => '0');
5954            end if;
5955          else
5956            fract := fract + 1;
5957          end if;
5958        elsif validfpx = neg_denormal then
5959          if and_reduce (fract) = '1' then        -- fraction is all "1".
5960            -- return smallest possible normal number
5961            expon    := (others => '0');
5962            expon(0) := '1';
5963            fract    := (others => '0');
5964          else
5965            fract := fract + 1;
5966          end if;
5967        elsif validfpx = pos_normal then
5968          if or_reduce (fract) = '0' then         -- fraction is all "0".
5969            if or_reduce (expon (exponent_width-1 downto 1)) = '0' and
5970              expon (0) = '1' then      -- Smallest exponent
5971              -- return the largest positive denormal number
5972              expon := (others => '0');
5973              fract := (others => '1');
5974            else
5975              expon := expon - 1;
5976              fract := (others => '1');
5977            end if;
5978          else
5979            fract := fract - 1;
5980          end if;
5981        elsif validfpx = pos_denormal then
5982          if or_reduce (fract(fract'high downto 1)) = '0'
5983            and fract (0) = '1' then    -- Smallest possible fraction
5984            return zerofp (fraction_width => fraction_width,
5985                           exponent_width => exponent_width);
5986          else
5987            fract := fract - 1;
5988          end if;
5989        end if;
5990      end if;
5991      result (-1 downto -fraction_width)  := UNRESOLVED_float(fract);
5992      result (exponent_width -1 downto 0) := UNRESOLVED_float(expon);
5993      result (exponent_width)             := sign;
5994      return result;
5995    end if;
5996  end function Nextafter;
5997
5998  -- Returns True if X is unordered with Y.
5999  function Unordered (
6000    x, y : UNRESOLVED_float)            -- floating point input
6001    return BOOLEAN is
6002    variable lfptype, rfptype : valid_fpstate;
6003  begin
6004    lfptype := classfp (x);
6005    rfptype := classfp (y);
6006    if (lfptype = nan or lfptype = quiet_nan or
6007        rfptype = nan or rfptype = quiet_nan or
6008        lfptype = isx or rfptype = isx) then
6009      return true;
6010    else
6011      return false;
6012    end if;
6013  end function Unordered;
6014
6015  function Finite (
6016    x : UNRESOLVED_float)
6017    return BOOLEAN is
6018    variable fp_state : valid_fpstate;  -- fp state
6019  begin
6020    fp_state := Classfp (x);
6021    if (fp_state = pos_inf) or (fp_state = neg_inf) then
6022      return true;
6023    else
6024      return false;
6025    end if;
6026  end function Finite;
6027
6028  function Isnan (
6029    x : UNRESOLVED_float)
6030    return BOOLEAN is
6031    variable fp_state : valid_fpstate;  -- fp state
6032  begin
6033    fp_state := Classfp (x);
6034    if (fp_state = nan) or (fp_state = quiet_nan) then
6035      return true;
6036    else
6037      return false;
6038    end if;
6039  end function Isnan;
6040
6041  -- Function to return constants.
6042  function zerofp (
6043    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
6044    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
6045    return UNRESOLVED_float is
6046    constant result : UNRESOLVED_float (exponent_width downto -fraction_width) :=
6047      (others => '0');                                          -- zero
6048  begin
6049    return result;
6050  end function zerofp;
6051
6052  function nanfp (
6053    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
6054    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
6055    return UNRESOLVED_float is
6056    variable result : UNRESOLVED_float (exponent_width downto -fraction_width) :=
6057      (others => '0');                  -- zero
6058  begin
6059    result (exponent_width-1 downto 0) := (others => '1');
6060    -- Exponent all "1"
6061    result (-1) := '1';  -- MSB of Fraction "1"
6062    -- Note: From W. Khan "IEEE Standard 754 for Binary Floating Point"
6063    -- The difference between a signaling NAN and a quiet NAN is that
6064    -- the MSB of the Fraction is a "1" in a Signaling NAN, and is a
6065    -- "0" in a quiet NAN.
6066    return result;
6067  end function nanfp;
6068
6069  function qnanfp (
6070    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
6071    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
6072    return UNRESOLVED_float is
6073    variable result : UNRESOLVED_float (exponent_width downto -fraction_width) :=
6074      (others => '0');                  -- zero
6075  begin
6076    result (exponent_width-1 downto 0) := (others => '1');
6077    -- Exponent all "1"
6078    result (-fraction_width)           := '1';  -- LSB of Fraction "1"
6079    -- (Could have been any bit)
6080    return result;
6081  end function qnanfp;
6082
6083  function pos_inffp (
6084    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
6085    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
6086    return UNRESOLVED_float is
6087    variable result : UNRESOLVED_float (exponent_width downto -fraction_width) :=
6088      (others => '0');                  -- zero
6089  begin
6090    result (exponent_width-1 downto 0) := (others => '1');  -- Exponent all "1"
6091    return result;
6092  end function pos_inffp;
6093
6094  function neg_inffp (
6095    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
6096    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
6097    return UNRESOLVED_float is
6098    variable result : UNRESOLVED_float (exponent_width downto -fraction_width) :=
6099      (others => '0');                  -- zero
6100  begin
6101    result (exponent_width downto 0) := (others => '1');  -- top bits all "1"
6102    return result;
6103  end function neg_inffp;
6104
6105  function neg_zerofp (
6106    constant exponent_width : NATURAL := float_exponent_width;  -- exponent
6107    constant fraction_width : NATURAL := float_fraction_width)  -- fraction
6108    return UNRESOLVED_float is
6109    variable result : UNRESOLVED_float (exponent_width downto -fraction_width) :=
6110      (others => '0');                                          -- zero
6111  begin
6112    result (exponent_width) := '1';
6113    return result;
6114  end function neg_zerofp;
6115
6116  -- size_res versions
6117  function zerofp (
6118    size_res : UNRESOLVED_float)        -- variable is only use for sizing
6119    return UNRESOLVED_float is
6120  begin
6121    return zerofp (
6122      exponent_width => size_res'high,
6123      fraction_width => -size_res'low);
6124  end function zerofp;
6125
6126  function nanfp (
6127    size_res : UNRESOLVED_float)        -- variable is only use for sizing
6128    return UNRESOLVED_float is
6129  begin
6130    return nanfp (
6131      exponent_width => size_res'high,
6132      fraction_width => -size_res'low);
6133  end function nanfp;
6134
6135  function qnanfp (
6136    size_res : UNRESOLVED_float)        -- variable is only use for sizing
6137    return UNRESOLVED_float is
6138  begin
6139    return qnanfp (
6140      exponent_width => size_res'high,
6141      fraction_width => -size_res'low);
6142  end function qnanfp;
6143
6144  function pos_inffp (
6145    size_res : UNRESOLVED_float)        -- variable is only use for sizing
6146    return UNRESOLVED_float is
6147  begin
6148    return pos_inffp (
6149      exponent_width => size_res'high,
6150      fraction_width => -size_res'low);
6151  end function pos_inffp;
6152
6153  function neg_inffp (
6154    size_res : UNRESOLVED_float)        -- variable is only use for sizing
6155    return UNRESOLVED_float is
6156  begin
6157    return neg_inffp (
6158      exponent_width => size_res'high,
6159      fraction_width => -size_res'low);
6160  end function neg_inffp;
6161
6162  function neg_zerofp (
6163    size_res : UNRESOLVED_float)        -- variable is only use for sizing
6164    return UNRESOLVED_float is
6165  begin
6166    return neg_zerofp (
6167      exponent_width => size_res'high,
6168      fraction_width => -size_res'low);
6169  end function neg_zerofp;
6170
6171-- rtl_synthesis off
6172-- pragma synthesis_off
6173
6174  --%%% these functions are copied from std_logic_1164 (VHDL-200X edition)
6175  -- Textio functions
6176  -- purpose: writes float into a line (NOTE changed basetype)
6177  type MVL9plus is ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-', error);
6178  type char_indexed_by_MVL9 is array (STD_ULOGIC) of CHARACTER;
6179  type MVL9_indexed_by_char is array (CHARACTER) of STD_ULOGIC;
6180  type MVL9plus_indexed_by_char is array (CHARACTER) of MVL9plus;
6181
6182  constant NBSP         : CHARACTER            := CHARACTER'val(160);  -- space character
6183  constant MVL9_to_char : char_indexed_by_MVL9 := "UX01ZWLH-";
6184  constant char_to_MVL9 : MVL9_indexed_by_char :=
6185    ('U' => 'U', 'X' => 'X', '0' => '0', '1' => '1', 'Z' => 'Z',
6186     'W' => 'W', 'L' => 'L', 'H' => 'H', '-' => '-', others => 'U');
6187  constant char_to_MVL9plus : MVL9plus_indexed_by_char :=
6188    ('U' => 'U', 'X' => 'X', '0' => '0', '1' => '1', 'Z' => 'Z',
6189     'W' => 'W', 'L' => 'L', 'H' => 'H', '-' => '-', others => error);
6190  constant NUS : STRING(2 to 1) := (others => ' ');
6191
6192  -- purpose: Skips white space
6193  procedure skip_whitespace (
6194    L : inout LINE) is
6195    variable readOk : BOOLEAN;
6196    variable c      : CHARACTER;
6197  begin
6198    while L /= null and L.all'length /= 0 loop
6199      if (L.all(1) = ' ' or L.all(1) = NBSP or L.all(1) = HT) then
6200        read (l, c, readOk);
6201      else
6202        exit;
6203      end if;
6204    end loop;
6205  end procedure skip_whitespace;
6206
6207-- %%% Replicated textio functions
6208  function to_ostring (value : STD_LOGIC_VECTOR) return STRING is
6209    constant ne     : INTEGER := (value'length+2)/3;
6210    variable pad    : STD_LOGIC_VECTOR(0 to (ne*3 - value'length) - 1);
6211    variable ivalue : STD_LOGIC_VECTOR(0 to ne*3 - 1);
6212    variable result : STRING(1 to ne);
6213    variable tri    : STD_LOGIC_VECTOR(0 to 2);
6214  begin
6215    if value'length < 1 then
6216      return NUS;
6217    else
6218      if value (value'left) = 'Z' then
6219        pad := (others => 'Z');
6220      else
6221        pad := (others => '0');
6222      end if;
6223      ivalue := pad & value;
6224      for i in 0 to ne-1 loop
6225        tri := To_X01Z(ivalue(3*i to 3*i+2));
6226        case tri is
6227          when o"0"   => result(i+1) := '0';
6228          when o"1"   => result(i+1) := '1';
6229          when o"2"   => result(i+1) := '2';
6230          when o"3"   => result(i+1) := '3';
6231          when o"4"   => result(i+1) := '4';
6232          when o"5"   => result(i+1) := '5';
6233          when o"6"   => result(i+1) := '6';
6234          when o"7"   => result(i+1) := '7';
6235          when "ZZZ"  => result(i+1) := 'Z';
6236          when others => result(i+1) := 'X';
6237        end case;
6238      end loop;
6239      return result;
6240    end if;
6241  end function to_ostring;
6242  -------------------------------------------------------------------
6243  function to_hstring (value : STD_LOGIC_VECTOR) return STRING is
6244    constant ne     : INTEGER := (value'length+3)/4;
6245    variable pad    : STD_LOGIC_VECTOR(0 to (ne*4 - value'length) - 1);
6246    variable ivalue : STD_LOGIC_VECTOR(0 to ne*4 - 1);
6247    variable result : STRING(1 to ne);
6248    variable quad   : STD_LOGIC_VECTOR(0 to 3);
6249  begin
6250    if value'length < 1 then
6251      return NUS;
6252    else
6253      if value (value'left) = 'Z' then
6254        pad := (others => 'Z');
6255      else
6256        pad := (others => '0');
6257      end if;
6258      ivalue := pad & value;
6259      for i in 0 to ne-1 loop
6260        quad := To_X01Z(ivalue(4*i to 4*i+3));
6261        case quad is
6262          when x"0"   => result(i+1) := '0';
6263          when x"1"   => result(i+1) := '1';
6264          when x"2"   => result(i+1) := '2';
6265          when x"3"   => result(i+1) := '3';
6266          when x"4"   => result(i+1) := '4';
6267          when x"5"   => result(i+1) := '5';
6268          when x"6"   => result(i+1) := '6';
6269          when x"7"   => result(i+1) := '7';
6270          when x"8"   => result(i+1) := '8';
6271          when x"9"   => result(i+1) := '9';
6272          when x"A"   => result(i+1) := 'A';
6273          when x"B"   => result(i+1) := 'B';
6274          when x"C"   => result(i+1) := 'C';
6275          when x"D"   => result(i+1) := 'D';
6276          when x"E"   => result(i+1) := 'E';
6277          when x"F"   => result(i+1) := 'F';
6278          when "ZZZZ" => result(i+1) := 'Z';
6279          when others => result(i+1) := 'X';
6280        end case;
6281      end loop;
6282      return result;
6283    end if;
6284  end function to_hstring;
6285  procedure Char2TriBits (C           :     CHARACTER;
6286                          RESULT      : out STD_LOGIC_VECTOR(2 downto 0);
6287                          GOOD        : out BOOLEAN;
6288                          ISSUE_ERROR : in  BOOLEAN) is
6289  begin
6290    case c is
6291      when '0' => result := o"0"; good := true;
6292      when '1' => result := o"1"; good := true;
6293      when '2' => result := o"2"; good := true;
6294      when '3' => result := o"3"; good := true;
6295      when '4' => result := o"4"; good := true;
6296      when '5' => result := o"5"; good := true;
6297      when '6' => result := o"6"; good := true;
6298      when '7' => result := o"7"; good := true;
6299      when 'Z' => result := "ZZZ"; good := true;
6300      when 'X' => result := "XXX"; good := true;
6301      when others =>
6302        assert not ISSUE_ERROR
6303          report float_pkg'instance_name
6304          & "OREAD Error: Read a '" & c &
6305          "', expected an Octal character (0-7)."
6306          severity error;
6307        result := "UUU";
6308        good   := false;
6309    end case;
6310  end procedure Char2TriBits;
6311
6312  procedure OREAD (L    : inout LINE; VALUE : out STD_LOGIC_VECTOR;
6313                   GOOD : out   BOOLEAN) is
6314    variable ok    : BOOLEAN;
6315    variable c     : CHARACTER;
6316    constant ne    : INTEGER := (VALUE'length+2)/3;
6317    constant pad   : INTEGER := ne*3 - VALUE'length;
6318    variable sv    : STD_LOGIC_VECTOR(0 to ne*3 - 1);
6319    variable i     : INTEGER;
6320    variable lastu : BOOLEAN := false;           -- last character was an "_"
6321  begin
6322    VALUE := (VALUE'range => 'U');               -- initialize to a "U"
6323    Skip_whitespace (L);
6324    if VALUE'length > 0 then
6325      read (l, c, ok);
6326      i := 0;
6327      while i < ne loop
6328        -- Bail out if there was a bad read
6329        if not ok then
6330          good := false;
6331          return;
6332        elsif c = '_' then
6333          if i = 0 then
6334            good := false;                       -- Begins with an "_"
6335            return;
6336          elsif lastu then
6337            good := false;                       -- "__" detected
6338            return;
6339          else
6340            lastu := true;
6341          end if;
6342        else
6343          Char2TriBits(c, sv(3*i to 3*i+2), ok, false);
6344          if not ok then
6345            good := false;
6346            return;
6347          end if;
6348          i := i + 1;
6349          lastu := false;
6350        end if;
6351        if i < ne then
6352          read(L, c, ok);
6353        end if;
6354      end loop;
6355      if or_reduce (sv (0 to pad-1)) = '1' then  -- %%% replace with "or"
6356        good := false;                           -- vector was truncated.
6357      else
6358        good  := true;
6359        VALUE := sv (pad to sv'high);
6360      end if;
6361    else
6362      good := true;                              -- read into a null array
6363    end if;
6364  end procedure OREAD;
6365
6366  -- Hex Read and Write procedures for STD_ULOGIC_VECTOR.
6367  -- Modified from the original to be more forgiving.
6368
6369  procedure Char2QuadBits (C           :     CHARACTER;
6370                           RESULT      : out STD_LOGIC_VECTOR(3 downto 0);
6371                           GOOD        : out BOOLEAN;
6372                           ISSUE_ERROR : in  BOOLEAN) is
6373  begin
6374    case c is
6375      when '0'       => result := x"0"; good := true;
6376      when '1'       => result := x"1"; good := true;
6377      when '2'       => result := x"2"; good := true;
6378      when '3'       => result := x"3"; good := true;
6379      when '4'       => result := x"4"; good := true;
6380      when '5'       => result := x"5"; good := true;
6381      when '6'       => result := x"6"; good := true;
6382      when '7'       => result := x"7"; good := true;
6383      when '8'       => result := x"8"; good := true;
6384      when '9'       => result := x"9"; good := true;
6385      when 'A' | 'a' => result := x"A"; good := true;
6386      when 'B' | 'b' => result := x"B"; good := true;
6387      when 'C' | 'c' => result := x"C"; good := true;
6388      when 'D' | 'd' => result := x"D"; good := true;
6389      when 'E' | 'e' => result := x"E"; good := true;
6390      when 'F' | 'f' => result := x"F"; good := true;
6391      when 'Z'       => result := "ZZZZ"; good := true;
6392      when 'X'       => result := "XXXX"; good := true;
6393      when others =>
6394        assert not ISSUE_ERROR
6395          report float_pkg'instance_name
6396          & "HREAD Error: Read a '" & c &
6397          "', expected a Hex character (0-F)."
6398          severity error;
6399        result := "UUUU";
6400        good   := false;
6401    end case;
6402  end procedure Char2QuadBits;
6403
6404  procedure HREAD (L    : inout LINE; VALUE : out STD_LOGIC_VECTOR;
6405                   GOOD : out   BOOLEAN) is
6406    variable ok    : BOOLEAN;
6407    variable c     : CHARACTER;
6408    constant ne    : INTEGER := (VALUE'length+3)/4;
6409    constant pad   : INTEGER := ne*4 - VALUE'length;
6410    variable sv    : STD_LOGIC_VECTOR(0 to ne*4 - 1);
6411    variable i     : INTEGER;
6412    variable lastu : BOOLEAN := false;  -- last character was an "_"
6413  begin
6414    VALUE := (VALUE'range => 'U');      -- initialize to a "U"
6415    Skip_whitespace (L);
6416    if VALUE'length > 0 then
6417      read (l, c, ok);
6418      i := 0;
6419      while i < ne loop
6420        -- Bail out if there was a bad read
6421        if not ok then
6422          good := false;
6423          return;
6424        elsif c = '_' then
6425          if i = 0 then
6426            good := false;              -- Begins with an "_"
6427            return;
6428          elsif lastu then
6429            good := false;              -- "__" detected
6430            return;
6431          else
6432            lastu := true;
6433          end if;
6434        else
6435          Char2QuadBits(c, sv(4*i to 4*i+3), ok, false);
6436          if not ok then
6437            good := false;
6438            return;
6439          end if;
6440          i := i + 1;
6441          lastu := false;
6442        end if;
6443        if i < ne then
6444          read(L, c, ok);
6445        end if;
6446      end loop;
6447      if or_reduce (sv (0 to pad-1)) = '1' then  -- %%% replace with "or"
6448        good := false;                  -- vector was truncated.
6449      else
6450        good  := true;
6451        VALUE := sv (pad to sv'high);
6452      end if;
6453    else
6454      good := true;                     -- Null input string, skips whitespace
6455    end if;
6456  end procedure HREAD;
6457
6458-- %%% END replicated textio functions
6459
6460  -- purpose: Checks the punctuation in a line
6461  procedure check_punctuation (
6462    arg   : in  STRING;
6463    colon : out BOOLEAN;                -- There was a colon in the line
6464    dot   : out BOOLEAN;                -- There was a dot in the line
6465    good  : out BOOLEAN;                -- True if enough characters found
6466    chars : in INTEGER) is
6467    -- Examples.  Legal inputs are "0000000", "0000.000", "0:000:000"
6468    alias xarg            : STRING (1 to arg'length) is arg;  -- make it downto range
6469    variable icolon, idot : BOOLEAN;    -- internal
6470    variable j : INTEGER := 0;          -- charters read
6471  begin
6472    good   := false;
6473    icolon := false;
6474    idot   := false;
6475    for i in 1 to arg'length loop
6476      if xarg(i) = ' ' or xarg(i) = NBSP or xarg(i) = HT or j = chars then
6477        exit;
6478      elsif xarg(i) = ':' then
6479        icolon := true;
6480      elsif xarg(i) = '.' then
6481        idot := true;
6482      elsif xarg (i) /= '_' then
6483        j := j + 1;
6484      end if;
6485    end loop;
6486    if j = chars then
6487      good := true;                     -- There are enough charactes to read
6488    end if;
6489    colon := icolon;
6490    if idot and icolon then
6491      dot := false;
6492    else
6493      dot := idot;
6494    end if;
6495  end procedure check_punctuation;
6496
6497  -- purpose: Searches a line for a ":" and replaces it with a ".".
6498  procedure fix_colon (
6499    arg   : inout STRING;
6500    chars : in integer) is
6501    alias xarg            : STRING (1 to arg'length) is arg;  -- make it downto range
6502    variable j : INTEGER := 0;          -- charters read
6503  begin
6504    for i in 1 to arg'length loop
6505      if xarg(i) = ' ' or xarg(i) = NBSP or xarg(i) = HT or j > chars then
6506        exit;
6507      elsif xarg(i) = ':' then
6508        xarg (i) := '.';
6509      elsif xarg (i) /= '_' then
6510        j := j + 1;
6511      end if;
6512    end loop;
6513  end procedure fix_colon;
6514
6515  procedure WRITE (
6516    L         : inout LINE;              -- input line
6517    VALUE     : in    UNRESOLVED_float;  -- floating point input
6518    JUSTIFIED : in    SIDE  := right;
6519    FIELD     : in    WIDTH := 0) is
6520    variable s     : STRING(1 to value'high - value'low +3);
6521    variable sindx : INTEGER;
6522  begin  -- function write
6523    s(1)  := MVL9_to_char(STD_ULOGIC(VALUE(VALUE'high)));
6524    s(2)  := ':';
6525    sindx := 3;
6526    for i in VALUE'high-1 downto 0 loop
6527      s(sindx) := MVL9_to_char(STD_ULOGIC(VALUE(i)));
6528      sindx    := sindx + 1;
6529    end loop;
6530    s(sindx) := ':';
6531    sindx    := sindx + 1;
6532    for i in -1 downto VALUE'low loop
6533      s(sindx) := MVL9_to_char(STD_ULOGIC(VALUE(i)));
6534      sindx    := sindx + 1;
6535    end loop;
6536    WRITE (L, s, JUSTIFIED, FIELD);
6537  end procedure WRITE;
6538
6539  procedure READ (L : inout LINE; VALUE : out UNRESOLVED_float) is
6540    -- Possible data:  0:0000:0000000
6541    --                 000000000000
6542    variable c      : CHARACTER;
6543    variable mv     : UNRESOLVED_float (VALUE'range);
6544    variable readOk : BOOLEAN;
6545    variable lastu  : BOOLEAN := false;         -- last character was an "_"
6546    variable i      : INTEGER;          -- index variable
6547  begin  -- READ
6548    VALUE := (VALUE'range => 'U');      -- initialize to a "U"
6549    Skip_whitespace (L);
6550    READ (l, c, readOk);
6551    if VALUE'length > 0 then
6552      i := value'high;
6553      readloop : loop
6554        if readOk = false then          -- Bail out if there was a bad read
6555          report float_pkg'instance_name
6556            & "READ(float): "
6557            & "Error end of file encountered."
6558            severity error;
6559          return;
6560        elsif c = ' ' or c = CR or c = HT then  -- reading done.
6561          if (i /= value'low) then
6562            report float_pkg'instance_name
6563              & "READ(float): "
6564              & "Warning: Value truncated."
6565              severity warning;
6566            return;
6567          end if;
6568        elsif c = '_' then
6569          if i = value'high then        -- Begins with an "_"
6570            report float_pkg'instance_name
6571              & "READ(float): "
6572              & "String begins with an ""_""" severity error;
6573            return;
6574          elsif lastu then              -- "__" detected
6575            report float_pkg'instance_name
6576              & "READ(float): "
6577              & "Two underscores detected in input string ""__"""
6578              severity error;
6579            return;
6580          else
6581            lastu := true;
6582          end if;
6583        elsif c = ':' or c = '.' then   -- separator, ignore
6584          if not (i = -1 or i = value'high-1) then
6585            report float_pkg'instance_name
6586              & "READ(float):  "
6587              & "Warning: Separator point does not match number format: '"
6588              & c & "' encountered at location " & INTEGER'image(i) & "."
6589              severity warning;
6590          end if;
6591          lastu := false;
6592        elsif (char_to_MVL9plus(c) = error) then
6593          report float_pkg'instance_name
6594            & "READ(float): "
6595            & "Error: Character '" & c & "' read, expected STD_ULOGIC literal."
6596            severity error;
6597          return;
6598        else
6599          mv (i) := char_to_MVL9(c);
6600          i := i - 1;
6601          if i < value'low then
6602            VALUE := mv;
6603            return;
6604          end if;
6605          lastu := false;
6606        end if;
6607        READ (l, c, readOk);
6608      end loop readloop;
6609    end if;
6610  end procedure READ;
6611
6612  procedure READ (L : inout LINE; VALUE : out UNRESOLVED_float; GOOD : out BOOLEAN) is
6613    -- Possible data:  0:0000:0000000
6614    --                 000000000000
6615    variable c      : CHARACTER;
6616    variable mv     : UNRESOLVED_float (VALUE'range);
6617    variable lastu  : BOOLEAN := false;         -- last character was an "_"
6618    variable i      : INTEGER;          -- index variable
6619    variable readOk : BOOLEAN;
6620  begin  -- READ
6621    VALUE := (VALUE'range => 'U');      -- initialize to a "U"
6622    Skip_whitespace (L);
6623    READ (l, c, readOk);
6624    if VALUE'length > 0 then
6625      i := value'high;
6626      good := false;
6627      readloop : loop
6628        if readOk = false then          -- Bail out if there was a bad read
6629          return;
6630        elsif c = ' ' or c = CR or c = HT then  -- reading done
6631          return;
6632        elsif c = '_' then
6633          if i = 0 then                 -- Begins with an "_"
6634            return;
6635          elsif lastu then              -- "__" detected
6636            return;
6637          else
6638            lastu := true;
6639          end if;
6640        elsif c = ':' or c = '.' then   -- separator, ignore
6641          -- good := (i = -1 or i = value'high-1);
6642          lastu := false;
6643        elsif (char_to_MVL9plus(c) = error) then
6644          return;
6645        else
6646          mv (i) := char_to_MVL9(c);
6647          i := i - 1;
6648          if i < value'low then
6649            good  := true;
6650            VALUE := mv;
6651            return;
6652          end if;
6653          lastu := false;
6654        end if;
6655        READ (l, c, readOk);
6656      end loop readloop;
6657    else
6658      good := true;                     -- read into a null array
6659    end if;
6660  end procedure READ;
6661
6662  procedure OWRITE (
6663    L         : inout LINE;              -- access type (pointer)
6664    VALUE     : in    UNRESOLVED_float;  -- value to write
6665    JUSTIFIED : in    SIDE  := right;    -- which side to justify text
6666    FIELD     : in    WIDTH := 0) is     -- width of field
6667  begin
6668    WRITE (L         => L,
6669           VALUE     => to_ostring(VALUE),
6670           JUSTIFIED => JUSTIFIED,
6671           FIELD     => FIELD);
6672  end procedure OWRITE;
6673
6674  procedure OREAD (L : inout LINE; VALUE : out UNRESOLVED_float) is
6675    constant ne         : INTEGER := ((value'length+2)/3) * 3;   -- pad
6676    variable slv        : STD_LOGIC_VECTOR (ne-1 downto 0);      -- slv
6677    variable slvu       : ufixed (VALUE'range);  -- Unsigned fixed point
6678    variable c          : CHARACTER;
6679    variable ok         : BOOLEAN;
6680    variable nybble     : STD_LOGIC_VECTOR (2 downto 0);         -- 3 bits
6681    variable colon, dot : BOOLEAN;
6682  begin
6683    VALUE := (VALUE'range => 'U');      -- initialize to a "U"
6684    Skip_whitespace (L);
6685    if VALUE'length > 0 then
6686      check_punctuation (arg   => L.all,
6687                         colon => colon,
6688                         dot   => dot,
6689                         good  => ok,
6690                         chars => ne/3);
6691      if not ok then
6692        report float_pkg'instance_name & "OREAD: "
6693          & "short string encounted: " & L.all
6694          & " needs to have " & integer'image (ne/3)
6695          & " valid octal characters."
6696          severity error;
6697        return;
6698      elsif dot then
6699        OREAD (L, slvu, ok);            -- read it like a UFIXED number
6700        if not ok then
6701          report float_pkg'instance_name & "OREAD: "
6702            & "error encounted reading STRING " & L.all
6703            severity error;
6704          return;
6705        else
6706          VALUE := UNRESOLVED_float (slvu);
6707        end if;
6708      elsif colon then
6709        OREAD (L, nybble, ok);          -- read the sign bit
6710        if not ok then
6711          report float_pkg'instance_name & "OREAD: "
6712            & "End of string encountered"
6713            severity error;
6714          return;
6715        elsif nybble (2 downto 1) /= "00" then
6716          report float_pkg'instance_name & "OREAD: "
6717            & "Illegal sign bit STRING encounted "
6718            severity error;
6719          return;
6720        end if;
6721        read (l, c, ok);                -- read the colon
6722        fix_colon (L.all, ne/3);         -- replaces the colon with a ".".
6723        OREAD (L, slvu (slvu'high-1 downto slvu'low), ok);  -- read it like a UFIXED number
6724        if not ok then
6725          report float_pkg'instance_name & "OREAD: "
6726            & "error encounted reading STRING " & L.all
6727            severity error;
6728          return;
6729        else
6730          slvu (slvu'high) := nybble (0);
6731          VALUE := UNRESOLVED_float (slvu);
6732        end if;
6733      else
6734        OREAD (L, slv, ok);
6735        if not ok then
6736          report float_pkg'instance_name & "OREAD: "
6737            & "Error encounted during read"
6738            severity error;
6739          return;
6740        end if;
6741        if (or_reduce (slv(ne-1 downto VALUE'high-VALUE'low+1)) = '1') then
6742          report float_pkg'instance_name & "OREAD: "
6743            & "Vector truncated."
6744            severity error;
6745          return;
6746        end if;
6747        VALUE := to_float (slv(VALUE'high-VALUE'low downto 0),
6748                           VALUE'high, -VALUE'low);
6749      end if;
6750    end if;
6751  end procedure OREAD;
6752
6753  procedure OREAD(L : inout LINE; VALUE : out UNRESOLVED_float; GOOD : out BOOLEAN) is
6754    constant ne         : INTEGER := ((value'length+2)/3) * 3;   -- pad
6755    variable slv        : STD_LOGIC_VECTOR (ne-1 downto 0);      -- slv
6756    variable slvu       : ufixed (VALUE'range);  -- Unsigned fixed point
6757    variable c          : CHARACTER;
6758    variable ok         : BOOLEAN;
6759    variable nybble     : STD_LOGIC_VECTOR (2 downto 0);         -- 3 bits
6760    variable colon, dot : BOOLEAN;
6761  begin
6762    VALUE := (VALUE'range => 'U');      -- initialize to a "U"
6763    GOOD  := false;
6764    Skip_whitespace (L);
6765    if VALUE'length > 0 then
6766      check_punctuation (arg   => L.all,
6767                         colon => colon,
6768                         dot   => dot,
6769                         good  => ok,
6770                         chars => ne/3);
6771      if not ok then
6772        return;
6773      elsif dot then
6774        OREAD (L, slvu, ok);            -- read it like a UFIXED number
6775        if not ok then
6776          return;
6777        else
6778          VALUE := UNRESOLVED_float (slvu);
6779        end if;
6780      elsif colon then
6781        OREAD (L, nybble, ok);          -- read the sign bit
6782        if not ok then
6783          return;
6784        elsif nybble (2 downto 1) /= "00" then
6785          return;
6786        end if;
6787        read (l, c, ok);                -- read the colon
6788        fix_colon (L.all, ne/3);         -- replaces the colon with a ".".
6789        OREAD (L, slvu (slvu'high-1 downto slvu'low), ok);  -- read it like a UFIXED number
6790        if not ok then
6791          return;
6792        else
6793          slvu (slvu'high) := nybble (0);
6794          VALUE := UNRESOLVED_float (slvu);
6795        end if;
6796      else
6797        OREAD (L, slv, ok);
6798        if not ok then
6799          return;
6800        end if;
6801        if (or_reduce (slv(ne-1 downto VALUE'high-VALUE'low+1)) = '1') then
6802          return;
6803        end if;
6804        VALUE := to_float (slv(VALUE'high-VALUE'low downto 0),
6805                           VALUE'high, -VALUE'low);
6806      end if;
6807      GOOD := true;
6808    end if;
6809  end procedure OREAD;
6810
6811  procedure HWRITE (
6812    L         : inout LINE;              -- access type (pointer)
6813    VALUE     : in    UNRESOLVED_float;  -- value to write
6814    JUSTIFIED : in    SIDE  := right;    -- which side to justify text
6815    FIELD     : in    WIDTH := 0) is     -- width of field
6816  begin
6817    WRITE (L         => L,
6818           VALUE     => to_hstring(VALUE),
6819           JUSTIFIED => JUSTIFIED,
6820           FIELD     => FIELD);
6821  end procedure HWRITE;
6822
6823  procedure HREAD (L : inout LINE; VALUE : out UNRESOLVED_float) is
6824    constant ne         : INTEGER := ((value'length+3)/4) * 4;   -- pad
6825    variable slv        : STD_LOGIC_VECTOR (ne-1 downto 0);      -- slv
6826    variable slvu       : ufixed (VALUE'range);  -- Unsigned fixed point
6827    variable c          : CHARACTER;
6828    variable ok         : BOOLEAN;
6829    variable nybble     : STD_LOGIC_VECTOR (3 downto 0);         -- 4 bits
6830    variable colon, dot : BOOLEAN;
6831  begin
6832    VALUE := (VALUE'range => 'U');      -- initialize to a "U"
6833    Skip_whitespace (L);
6834    if VALUE'length > 0 then
6835      check_punctuation (arg   => L.all,
6836                         colon => colon,
6837                         dot   => dot,
6838                         good  => ok,
6839                         chars => ne/4);
6840      if not ok then
6841        report float_pkg'instance_name & "HREAD: "
6842          & "short string encounted: " & L.all
6843          & " needs to have " & integer'image (ne/4)
6844          & " valid hex characters."
6845          severity error;
6846        return;
6847      elsif dot then
6848        HREAD (L, slvu, ok);            -- read it like a UFIXED number
6849        if not ok then
6850          report float_pkg'instance_name & "HREAD: "
6851            & "error encounted reading STRING " & L.all
6852            severity error;
6853          return;
6854        else
6855          VALUE := UNRESOLVED_float (slvu);
6856        end if;
6857      elsif colon then
6858        HREAD (L, nybble, ok);          -- read the sign bit
6859        if not ok then
6860          report float_pkg'instance_name & "HREAD: "
6861            & "End of string encountered"
6862            severity error;
6863          return;
6864        elsif nybble (3 downto 1) /= "000" then
6865          report float_pkg'instance_name & "HREAD: "
6866            & "Illegal sign bit STRING encounted "
6867            severity error;
6868          return;
6869        end if;
6870        read (l, c, ok);                -- read the colon
6871        fix_colon (L.all, ne/4);         -- replaces the colon with a ".".
6872        HREAD (L, slvu (slvu'high-1 downto slvu'low), ok);  -- read it like a UFIXED number
6873        if not ok then
6874          report float_pkg'instance_name & "HREAD: "
6875            & "error encounted reading STRING " & L.all
6876            severity error;
6877          return;
6878        else
6879          slvu (slvu'high) := nybble (0);
6880          VALUE := UNRESOLVED_float (slvu);
6881        end if;
6882      else
6883        HREAD (L, slv, ok);
6884        if not ok then
6885          report float_pkg'instance_name & "HREAD: "
6886            & "Error encounted during read"
6887            severity error;
6888          return;
6889        end if;
6890        if (or_reduce (slv(ne-1 downto VALUE'high-VALUE'low+1)) = '1') then
6891          report float_pkg'instance_name & "HREAD: "
6892            & "Vector truncated."
6893            severity error;
6894          return;
6895        end if;
6896        VALUE := to_float (slv(VALUE'high-VALUE'low downto 0),
6897                           VALUE'high, -VALUE'low);
6898      end if;
6899    end if;
6900  end procedure HREAD;
6901
6902  procedure HREAD (L : inout LINE; VALUE : out UNRESOLVED_float; GOOD : out BOOLEAN) is
6903    constant ne         : INTEGER := ((value'length+3)/4) * 4;   -- pad
6904    variable slv        : STD_LOGIC_VECTOR (ne-1 downto 0);      -- slv
6905    variable slvu       : ufixed (VALUE'range);  -- Unsigned fixed point
6906    variable c          : CHARACTER;
6907    variable ok         : BOOLEAN;
6908    variable nybble     : STD_LOGIC_VECTOR (3 downto 0);         -- 4 bits
6909    variable colon, dot : BOOLEAN;
6910  begin
6911    VALUE := (VALUE'range => 'U');      -- initialize to a "U"
6912    GOOD  := false;
6913    Skip_whitespace (L);
6914    if VALUE'length > 0 then
6915      check_punctuation (arg   => L.all,
6916                         colon => colon,
6917                         dot   => dot,
6918                         good  => ok,
6919                         chars => ne/4);
6920      if not ok then
6921        return;
6922      elsif dot then
6923        HREAD (L, slvu, ok);            -- read it like a UFIXED number
6924        if not ok then
6925          return;
6926        else
6927          VALUE := UNRESOLVED_float (slvu);
6928        end if;
6929      elsif colon then
6930        HREAD (L, nybble, ok);          -- read the sign bit
6931        if not ok then
6932          return;
6933        elsif nybble (3 downto 1) /= "000" then
6934          return;
6935        end if;
6936        read (l, c, ok);                -- read the colon
6937        fix_colon (L.all, ne/4);         -- replaces the colon with a ".".
6938        HREAD (L, slvu (slvu'high-1 downto slvu'low), ok);  -- read it like a UFIXED number
6939        if not ok then
6940          return;
6941        else
6942          slvu (slvu'high) := nybble (0);
6943          VALUE := UNRESOLVED_float (slvu);
6944        end if;
6945      else
6946        HREAD (L, slv, ok);
6947        if not ok then
6948          return;
6949        end if;
6950        if (or_reduce (slv(ne-1 downto VALUE'high-VALUE'low+1)) = '1') then
6951          return;
6952        end if;
6953        VALUE := to_float (slv(VALUE'high-VALUE'low downto 0),
6954                           VALUE'high, -VALUE'low);
6955      end if;
6956      GOOD := true;
6957    end if;
6958  end procedure HREAD;
6959
6960  function to_string (value : UNRESOLVED_float) return STRING is
6961    variable s     : STRING(1 to value'high - value'low +3);
6962    variable sindx : INTEGER;
6963  begin  -- function write
6964    s(1)  := MVL9_to_char(STD_ULOGIC(VALUE(VALUE'high)));
6965    s(2)  := ':';
6966    sindx := 3;
6967    for i in VALUE'high-1 downto 0 loop
6968      s(sindx) := MVL9_to_char(STD_ULOGIC(VALUE(i)));
6969      sindx    := sindx + 1;
6970    end loop;
6971    s(sindx) := ':';
6972    sindx    := sindx + 1;
6973    for i in -1 downto VALUE'low loop
6974      s(sindx) := MVL9_to_char(STD_ULOGIC(VALUE(i)));
6975      sindx    := sindx + 1;
6976    end loop;
6977    return s;
6978  end function to_string;
6979
6980  function to_hstring (value : UNRESOLVED_float) return STRING is
6981    variable slv : STD_LOGIC_VECTOR (value'length-1 downto 0);
6982  begin
6983    floop : for i in slv'range loop
6984      slv(i) := to_X01Z (value(i + value'low));
6985    end loop floop;
6986    return to_hstring (slv);
6987  end function to_hstring;
6988
6989  function to_ostring (value : UNRESOLVED_float) return STRING is
6990    variable slv : STD_LOGIC_VECTOR (value'length-1 downto 0);
6991  begin
6992    floop : for i in slv'range loop
6993      slv(i) := to_X01Z (value(i + value'low));
6994    end loop floop;
6995    return to_ostring (slv);
6996  end function to_ostring;
6997
6998  function from_string (
6999    bstring                 : STRING;   -- binary string
7000    constant exponent_width : NATURAL := float_exponent_width;
7001    constant fraction_width : NATURAL := float_fraction_width)
7002    return UNRESOLVED_float is
7003    variable result : UNRESOLVED_float (exponent_width downto -fraction_width);
7004    variable L      : LINE;
7005    variable good   : BOOLEAN;
7006  begin
7007    L := new STRING'(bstring);
7008    READ (L, result, good);
7009    deallocate (L);
7010    assert (good)
7011      report float_pkg'instance_name
7012      & "from_string: Bad string " & bstring
7013      severity error;
7014    return result;
7015  end function from_string;
7016
7017  function from_ostring (
7018    ostring                 : STRING;   -- Octal string
7019    constant exponent_width : NATURAL := float_exponent_width;
7020    constant fraction_width : NATURAL := float_fraction_width)
7021    return UNRESOLVED_float is
7022    variable result : UNRESOLVED_float (exponent_width downto -fraction_width);
7023    variable L      : LINE;
7024    variable good   : BOOLEAN;
7025  begin
7026    L := new STRING'(ostring);
7027    OREAD (L, result, good);
7028    deallocate (L);
7029    assert (good)
7030      report float_pkg'instance_name
7031      & "from_ostring: Bad string " & ostring
7032      severity error;
7033    return result;
7034  end function from_ostring;
7035
7036  function from_hstring (
7037    hstring                 : STRING;   -- hex string
7038    constant exponent_width : NATURAL := float_exponent_width;
7039    constant fraction_width : NATURAL := float_fraction_width)
7040    return UNRESOLVED_float is
7041    variable result : UNRESOLVED_float (exponent_width downto -fraction_width);
7042    variable L      : LINE;
7043    variable good   : BOOLEAN;
7044  begin
7045    L := new STRING'(hstring);
7046    HREAD (L, result, good);
7047    deallocate (L);
7048    assert (good)
7049      report float_pkg'instance_name
7050      & "from_hstring: Bad string " & hstring
7051      severity error;
7052    return result;
7053  end function from_hstring;
7054
7055  function from_string (
7056    bstring  : STRING;                  -- binary string
7057    size_res : UNRESOLVED_float)        -- used for sizing only
7058    return UNRESOLVED_float is
7059  begin
7060    return from_string (bstring        => bstring,
7061                        exponent_width => size_res'high,
7062                        fraction_width => -size_res'low);
7063  end function from_string;
7064
7065  function from_ostring (
7066    ostring  : STRING;                  -- Octal string
7067    size_res : UNRESOLVED_float)        -- used for sizing only
7068    return UNRESOLVED_float is
7069  begin
7070    return from_ostring (ostring        => ostring,
7071                         exponent_width => size_res'high,
7072                         fraction_width => -size_res'low);
7073  end function from_ostring;
7074
7075  function from_hstring (
7076    hstring  : STRING;                  -- hex string
7077    size_res : UNRESOLVED_float)        -- used for sizing only
7078    return UNRESOLVED_float is
7079  begin
7080    return from_hstring (hstring        => hstring,
7081                         exponent_width => size_res'high,
7082                         fraction_width => -size_res'low);
7083  end function from_hstring;
7084-- rtl_synthesis on
7085-- pragma synthesis_on
7086  function to_float (
7087    arg                     : STD_LOGIC_VECTOR;
7088    constant exponent_width : NATURAL := float_exponent_width;  -- length of FP output exponent
7089    constant fraction_width : NATURAL := float_fraction_width)  -- length of FP output fraction
7090    return UNRESOLVED_float is
7091  begin
7092    return to_float (
7093      arg            => to_stdulogicvector (arg),
7094      exponent_width => exponent_width,
7095      fraction_width => fraction_width);
7096  end function to_float;
7097
7098  function to_float (
7099    arg      : STD_LOGIC_VECTOR;
7100    size_res : UNRESOLVED_float)
7101    return UNRESOLVED_float is
7102  begin
7103    return to_float (
7104      arg      => to_stdulogicvector (arg),
7105      size_res => size_res);
7106  end function to_float;
7107
7108  -- For Verilog compatability
7109  function realtobits (arg : REAL) return STD_LOGIC_VECTOR is
7110    variable result : float64;          -- 64 bit floating point
7111  begin
7112    result := to_float (arg => arg,
7113                        exponent_width => float64'high,
7114                        fraction_width => -float64'low);
7115    return to_slv (result);
7116  end function realtobits;
7117
7118  function bitstoreal (arg : STD_LOGIC_VECTOR) return REAL is
7119    variable arg64 : float64;           -- arg converted to float
7120  begin
7121    arg64 := to_float (arg => arg,
7122                       exponent_width => float64'high,
7123                       fraction_width => -float64'low);
7124    return to_real (arg64);
7125  end function bitstoreal;
7126
7127end package body float_pkg;
7128