--------------------------------------------------------------------- -- -- Package body fix_std -- Fixed point arithmetic based on numeric_std -- Compile using VHDL-93 (required to support 'ASCENDING -- array attribute). -- --------------------------------------------------------------------- -- -- This document describes a VHDL package of definitions and subprograms -- intended to support the use of fixed-point arithmetic in test benches -- and synthesisable designs. This document and the package it describes -- are made freely available to the HDL design community without warranty -- of any kind. You are welcome to make use of this information for your -- own private study and in your own designs. If you make use of the -- package, you accept sole responsibility for its fitness for purpose -- and its suitability in your application. You are free to modify the -- package in any way, and to record your contribution to it, but this -- notice must appear in a prominent place in any modified or derived -- version of the package or its supporting documentation. -- -- The author wishes to thank his employer Doulos Ltd for making -- available the facilities used to develop, test and distribute this -- package. However, Doulos Ltd accepts no responsibility for the -- package's contents and cannot support it in any way. -- --------------------------------------------------------------------- -- Revision information: -- -- Version 0.1 06-May-2003 -- Alpha version, for review -- No division operators are provided, pending detailed -- consultation on their functionality. -- Some subprogram implementations are unnecessarily inefficient. -- Version 0.2 11-Jun-2003 -- Fixes aiming to make the package portable across all synthesis tools: -- * Removed deferred constants, made them package constants -- * Removed all variable initialisations in procedures, made them -- procedural initialisations in the code -- * Fixed definition of extract functions to return just one bit -- if their results would otherwise be null --------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; package body fix_std is -------------------------------------------------------------------- -- DEFERRED CONSTANTS -------------------------------------------------------------------- -- THESE CONSTANTS MAY BE ADJUSTED TO SUIT THE NEEDS OF SPECIFIC -- IMPLEMENTATIONS OR APPLICATIONS. -------------------------------------------------------------------- -- Fixed-point offset, the bit number (subscript) used for -- the bit in a UFix or SFix vector having binary weight 2^0 -- (the units bit). -- -- constant FixP : Fix_Subscr := 100; -- Default values for overflow and rounding modes: -- -- constant Fix_Default_Rounding : Fix_Rounding_Mode := clip_LS; -- constant Fix_Default_Overflow : Fix_Overflow_Mode := clip_MS; -------------------------------------------------------------------- -- END OF DEFERRED CONSTANTS -------------------------------------------------------------------- -------------------------------------------------------------------- -- IMPLEMENTATION CONSTANTS -------------------------------------------------------------------- -- THESE CONSTANTS MAY BE ADJUSTED TO SUIT THE NEEDS OF SPECIFIC -- IMPLEMENTATIONS OR APPLICATIONS. -------------------------------------------------------------------- -- Severity levels for various errors -- Concatenation errors - bad sign extension, discontiguous range etc -- These are only warnings - they just give the wrong answer. -- constant concat_severity : severity_level := WARNING; -- Subtype direction errors - the present implementation can't -- handle fixed-point objects with ascending ranges. These messages -- are intended to give early warning of problems that would -- definitely cause other fatal errors at elaboration or run time. -- constant direction_severity : severity_level := FAILURE; -- Assertion error message constants constant bad_direction_msg : string := " has ascending range"; constant concat_range_msg : string := "Concatenation bounds should have contiguous ranges"; constant concat_sxt_msg : string := "Concatenation corrupts sign of result"; constant concat_signLS_msg : string := "RHS of concatenation should be unsigned"; constant compare_meta_msg : string := "Metavalue detected in FIX_STD comparison, returning FALSE"; -------------------------------------------------------------------- -- END OF IMPLEMENTATION CONSTANTS -------------------------------------------------------------------- -------------------------------------------------------------------- -- DO NOT MODIFY ANY CODE BELOW THIS POINT. -------------------------------------------------------------------- -- Assumed bit width of INTEGER type in VHDL -- constant INT_WIDTH : positive := 32; -- Single-bit zero values subtype Izero_UFixT is UFix(FixP downto FixP); subtype Izero_SFixT is SFix(FixP downto FixP); subtype Fzero_UFixT is UFix(FixP-1 downto FixP-1); constant Izero_UFix: Izero_UFixT := "0"; constant Izero_SFix: Izero_SFixT := "0"; constant Fzero_UFix: Fzero_UFixT := "0"; -------------------------------------------------------------------- -- LOCAL PRIVATE SUBPROGRAMS -------------------------------------------------------------------- -- Min, Max: Find minimum and maximum of two integers. -- Useful for determining appropriate range for operation results. -- function Max(L, R: Fix_Subscr) return Fix_Subscr is begin if L>R then return L; else return R; end if; end; -- function Min(L, R: Fix_Subscr) return Fix_Subscr is begin if L FixP then return Span(U); else return U(U'LEFT downto FixP); end if; end; -- E.2. Return the fractional part of a UFix value function Frac(U: UFix) return UFix is begin if U'LEFT < FixP-1 then return Span(U); elsif U'RIGHT >= FixP then return Fzero_UFix; else return U(FixP-1 downto U'RIGHT); end if; end; -- E.3. Return the integral part of a SFix value function Int(S: SFix) return SFix is begin if S'LENGTH = 0 then return Izero_SFix; elsif S'LEFT <= FixP then return SFix'(FixP => S(S'LEFT)); elsif S'RIGHT > FixP then return Span(S); else return S(S'LEFT downto FixP); end if; end; -- E.4. Return the fractional part of a SFix value function Frac(S: SFix) return UFix is variable P: SFix(Max(S'LEFT, FixP) downto Min(S'RIGHT, FixP)); begin if S'LEFT < FixP then for I in FixP-1 downto S'LEFT+1 loop P(I) := S(S'LEFT); end loop; P(S'RANGE) := S; return UFix(S(FixP-1 downto S'RIGHT)); elsif S'RIGHT >= FixP then return Fzero_UFix; else return UFix(S(FixP-1 downto S'RIGHT)); end if; end; -- E.5. Widen a SFix value if necessary so that -- its range adjoins or spans the binary point function Span(S: SFix) return SFix is variable F: SFix(Max(S'LEFT, FixP) downto Min(S'RIGHT, FixP)); begin F(S'RANGE) := S; for I in F'LEFT downto S'LEFT+1 loop F(I) := S(S'LEFT); end loop; for I in S'RIGHT-1 downto F'RIGHT loop F(I) := '0'; end loop; return F; end; -- E.6. Widen a UFix value if necessary so that -- its range adjoins or spans the binary point function Span(U: UFix) return UFix is variable F: UFix(Max(U'LEFT, FixP-1) downto Min(U'RIGHT, FixP)); begin F(U'RANGE) := U; for I in F'LEFT downto U'LEFT+1 loop F(I) := '0'; end loop; for I in U'RIGHT-1 downto F'RIGHT loop F(I) := '0'; end loop; return F; end; --------------------------- -- T. Conversion functions --------------------------- -- T.1 to T.8: Unsigned conversions -- T.1. Resizing an existing UFix. Provide number of -- integer bits and number of fraction bits. -- function to_UFix( N : UFix; MSB_index : Fix_Subscr; LSB_index : Fix_Subscr := FixP; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return UFix is variable F: UFix(MSB_index downto LSB_index); begin Copy_V(F, N, overflow, rounding); return F; end; -- T.2. Resizing an existing SFix. Provide number of -- integer bits and number of fraction bits. -- function to_UFix( N : SFix; MSB_index : Fix_Subscr; LSB_index : Fix_Subscr := FixP; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return UFix is variable F: UFix(MSB_index downto LSB_index); begin Copy_V(F, N, overflow, rounding); return F; end; -- T.3. Conversion from integer to UFix. Provide number of -- integer bits and number of fraction bits. Note that -- negative input is tolerated! -- function to_UFix( N : integer; MSB_index : Fix_Subscr; LSB_index : Fix_Subscr := FixP; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return UFix is variable F: UFix(MSB_index downto LSB_index); begin Copy_V(F, N, overflow, rounding); return F; end; -- T.4. Conversion from unsigned to UFix. Provide subscripts of -- MS and (optionally) LS bit of the resulting UFix. -- function to_UFix( N : unsigned; MSB_index : Fix_Subscr; LSB_index : Fix_Subscr := FixP; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return UFix is variable F: UFix(MSB_index downto LSB_index); begin Copy_V(F, N, overflow, rounding); return F; end; -- T.5. Conversion from unsigned to UFix. Automatically set the -- range of the resulting UFix to match the unsigned value, -- as an integral UFix value with no fraction bits. -- function to_UFix( N : unsigned ) return UFix is variable F: UFix(FixP+N'LENGTH-1 downto FixP); begin F := UFix(N); return F; end; -- T.6. Conversion from UFix to unsigned. All integer bits are -- preserved (including adding LS scale bits if necessary). -- function to_unsigned( N : UFix; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return unsigned is variable F_UFix: UFix(N'LEFT downto FixP); variable F: unsigned(F_UFix'LENGTH-1 downto 0); begin Copy_V(F_UFix, N, rounding=>rounding); F := unsigned(F_UFix); return F; end; -- T.7. Conversion from UFix to unsigned. Caller specifies -- required number of bits in unsigned result. -- function to_unsigned( N : UFix; bits : positive; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return unsigned is variable F_UFix: UFix(FixP+bits-1 downto FixP); variable F: unsigned(F_UFix'LENGTH-1 downto 0); begin Copy_V(F_UFix, N, overflow, rounding); F := unsigned(F_UFix); return F; end; -- T.8. Conversion from UFix to integer. Up to 31 integer bits are -- preserved (including adding LS scale bits if necessary). -- function to_integer( N : UFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return integer is variable F_UFix: UFix(Min(FixP+INT_WIDTH-2, N'LEFT) downto FixP); begin Copy_V(F_UFix, N, overflow, rounding); return to_integer(unsigned(F_UFix)); end; -- T.9 to T.16: Signed conversions -- T.9. Resizing an existing UFix. Provide number of -- integer bits and number of fraction bits. -- function to_SFix( N : UFix; MSB_index : Fix_Subscr; LSB_index : Fix_Subscr := FixP; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return SFix is variable F: SFix(MSB_index downto LSB_index); begin Copy_V(F, N, overflow, rounding); return F; end; -- T.10. Resizing an existing SFix. Provide number of -- integer bits and number of fraction bits. -- function to_SFix( N : SFix; MSB_index : Fix_Subscr; LSB_index : Fix_Subscr := FixP; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return SFix is variable F: SFix(MSB_index downto LSB_index); begin Copy_V(F, N, overflow, rounding); return F; end; -- T.11. Conversion from integer to SFix. Provide number of -- integer bits and number of fraction bits. -- function to_SFix( N : integer; MSB_index : Fix_Subscr; LSB_index : Fix_Subscr := FixP; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return SFix is variable F: SFix(MSB_index downto LSB_index); begin Copy_V(F, N, overflow, rounding); return F; end; -- T.12. Conversion from signed to SFix. Provide subscripts of -- MS and (optionally) LS bit of the resulting SFix. -- function to_SFix( N : signed; MSB_index : Fix_Subscr; LSB_index : Fix_Subscr := FixP; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return SFix is variable F: SFix(MSB_index downto LSB_index); begin Copy_V(F, N, overflow, rounding); return F; end; -- T.13. Conversion from signed to SFix. Automatically set the -- range of the resulting SFix to match the signed value, -- as an integral SFix value with no fraction bits. -- function to_SFix( N : signed ) return SFix is variable F: SFix(FixP+N'LENGTH-1 downto FixP); begin F := SFix(N); return F; end; -- T.14. Conversion from SFix to signed. All integer bits are -- preserved (including adding LS scale bits if necessary). -- function to_signed( N : SFix; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return signed is variable F_SFix: SFix(N'LEFT downto FixP); variable F: signed(F_SFix'LENGTH-1 downto 0); begin Copy_V(F_SFix, N, rounding=>rounding); F := signed(F_SFix); return F; end; -- T.15. Conversion from SFix to signed. Caller specifies -- required number of bits in signed result. -- function to_signed( N : SFix; bits : positive; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return signed is variable F_SFix: UFix(FixP+bits-1 downto FixP); variable F: signed(F_SFix'LENGTH-1 downto 0); begin Copy_V(F_SFix, N, overflow, rounding); F := signed(F_SFix); return F; end; -- T.16. Conversion from SFix to integer. Up to 32 integer bits are -- preserved (including adding LS scale bits if necessary). -- function to_integer( N : SFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) return integer is variable F_SFix: SFix(Min(FixP+INT_WIDTH-1, N'LEFT) downto FixP); begin Copy_V(F_SFix, N, overflow, rounding); return to_integer(signed(F_SFix)); end; -- T.17. Conversion from UFix to SFix. This simply adds -- an extra more significant bit, set to zero. -- function to_SFix(U: UFix) return SFix is variable F: SFix(U'LEFT+1 downto U'RIGHT); begin F := SFix('0' & U); return F; end; ---------------------------------- -- V. Copy-to-variable procedures ---------------------------------- -- Range-aware copying of an expression into a variable. The -- ranges of destination variable and source expression are -- used to determine correct rounding, overflow and scaling -- behaviour. -- V.1 to V.5: Copy an expression into a UFix variable -- V.1. Copy UFix to UFix -- procedure Copy_V( target : out UFix; source : UFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is subtype target_T is UFix(target'RANGE); variable W: UFix(Max(target'LEFT, source'LEFT+1) downto Min(target'RIGHT, source'RIGHT)); constant HighZero: UFix(W'LEFT downto target'LEFT+1) := (others => '0'); begin assert not target'ASCENDING report "target" & bad_direction_msg severity direction_severity; assert not source'ASCENDING report "source" & bad_direction_msg severity direction_severity; W := (others => '0'); W(source'RANGE) := source; if target'RIGHT > source'RIGHT then case rounding is when clip_LS | towards_zero => null; when to_nearest => W(W'LEFT downto target'RIGHT-1) := UFix( unsigned(W(W'LEFT downto target'RIGHT-1)) + 1 ); end case; end if; target := W(target'RANGE); if HighZero'LENGTH > 0 then if unsigned(W(HighZero'RANGE)) /= unsigned(HighZero) then case overflow is when clip_MS => null; when saturate => target := target_T'(others => '1'); end case; end if; end if; end; -- V.2. Copy SFix to UFix -- procedure Copy_V( target : out UFix; source : SFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable W: SFix(Max(Source'LEFT, target'LEFT) downto target'RIGHT); constant target_zero: UFix(target'RANGE) := (others => '0'); begin assert not target'ASCENDING report "target" & bad_direction_msg severity direction_severity; assert not source'ASCENDING report "source" & bad_direction_msg severity direction_severity; W := (others => '0'); -- Rounding & sign-extend Copy_V(W, source, clip_MS, rounding); -- Saturation? if W < 0 and overflow = saturate then target := target_zero; else Copy_V(target, UFix(W), overflow, clip_LS); end if; end; -- V.3. Copy UNSIGNED to UFix -- procedure Copy_V( target : out UFix; source : unsigned; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is constant U: UFix(FixP+source'LENGTH-1 downto FixP) := UFix(source); begin Copy_V(target, U, overflow, rounding); end; -- V.4. Copy SIGNED to UFix -- procedure Copy_V( target : out UFix; source : signed; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is constant S: SFix(FixP+source'LENGTH-1 downto FixP) := SFix(source); begin Copy_V(target, S, overflow, rounding); end; -- V.5. Copy integer to UFix -- procedure Copy_V( target : out UFix; source : integer; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is constant N: signed(FixP+INT_WIDTH-1 downto FixP) := to_signed(source, INT_WIDTH); begin -- Cop-out, this is very inefficient, but will do for now. Copy_V(target, N, overflow, rounding); end; -- V.6 to V.10: Copy an expression into a SFix variable -- V.6. Copy UFix to SFix -- procedure Copy_V( target : out SFix; source : UFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is constant S: SFix(FixP+source'LENGTH downto FixP) := to_SFix(source); begin Copy_V(target, S, overflow, rounding); end; -- V.7. Copy SFix to SFix -- procedure Copy_V( target : out SFix; source : SFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is subtype target_T is SFix(target'RANGE); variable W: SFix(Max(target'LEFT, source'LEFT+1) downto Min(target'RIGHT, source'RIGHT)); variable HighSX: SFix(W'LEFT downto target'LEFT+1); begin for i in HighSX'RANGE loop HighSX(i) := source(source'LEFT); end loop; assert not target'ASCENDING report "target" & bad_direction_msg severity direction_severity; assert not source'ASCENDING report "source" & bad_direction_msg severity direction_severity; -- Make W a copy of source, duly extended at both ends W := (others => '0'); W(source'RANGE) := source; W(HighSX'RANGE) := HighSX; -- Do any rounding required if target'RIGHT > source'RIGHT then case rounding is when clip_LS => null; when towards_zero => if (to_UX01(W(W'LEFT)) = '1') -- it's negative? and (unsigned(W(target'RIGHT-1 downto W'RIGHT)) /= 0) -- round up? then W(W'LEFT downto target'RIGHT) := SFix( signed(W(W'LEFT downto target'RIGHT)) + 1 ); end if; when to_nearest => W(W'LEFT downto target'RIGHT-1) := SFix( signed(W(W'LEFT downto target'RIGHT-1)) + 1 ); end case; end if; -- Do any overflow required target := W(target'RANGE); if HighSX'LENGTH > 0 then if signed(W(HighSX'RANGE)) /= signed(HighSX) then case overflow is when clip_MS => null; when saturate => target := Target_T'(others => not W(W'LEFT)); target(target'LEFT) := W(W'LEFT); end case; end if; end if; end; -- V.8. Copy UNSIGNED to SFix -- procedure Copy_V( target : out SFix; source : unsigned; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is constant S: SFix(FixP+source'LENGTH downto FixP) := SFix('0' & source); begin Copy_V(target, S, overflow, rounding); end; -- V.9. Copy SIGNED to SFix -- procedure Copy_V( target : out SFix; source : signed; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is constant S: SFix(FixP+source'LENGTH-1 downto FixP) := SFix(source); begin Copy_V(target, S, overflow, rounding); end; -- V.10. Copy integer to SFix -- procedure Copy_V( target : out SFix; source : integer; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is constant N: signed(FixP+INT_WIDTH-1 downto FixP) := to_signed(source, INT_WIDTH); begin -- Cop-out, this is very inefficient, but will do for now. Copy_V(target, N, overflow, rounding); end; -------------------------------- -- S. Copy-to-signal procedures -------------------------------- -- -- Range-aware copying of an expression into a signal. The -- ranges of destination signal and source expression are -- used to determine correct rounding, overflow and scaling -- behaviour. -- S.1 to S.5: Copy an expression into a UFix signal -- -- S.1. Copy UFix to UFix -- procedure Copy_S( signal target : out UFix; source : UFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: UFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.1. Copy SFix to UFix -- procedure Copy_S( signal target : out UFix; source : SFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: UFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.3. Copy UNSIGNED to UFix -- procedure Copy_S( signal target : out UFix; source : unsigned; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: UFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.4. Copy SIGNED to UFix -- procedure Copy_S( signal target : out UFix; source : signed; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: UFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.5. Copy integer to UFix -- procedure Copy_S( signal target : out UFix; source : integer; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: UFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.6 to S.10: Copy an expression into a SFix signal -- -- S.6. Copy UFix to SFix -- procedure Copy_S( signal target : out SFix; source : UFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: SFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.7. Copy SFix to SFix -- procedure Copy_S( signal target : out SFix; source : SFix; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: SFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.8. Copy UNSIGNED to SFix -- procedure Copy_S( signal target : out SFix; source : unsigned; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: SFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.9. Copy SIGNED to SFix -- procedure Copy_S( signal target : out SFix; source : signed; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: SFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; -- S.10. Copy integer to SFix -- procedure Copy_S( signal target : out SFix; source : integer; overflow : Fix_Overflow_Mode := Fix_Default_Overflow; rounding : Fix_Rounding_Mode := Fix_Default_Rounding ) is variable V: SFix(target'RANGE); begin Copy_V(V, source, overflow, rounding); target <= V; end; ------------------------------------------------------------------ -- A. Arithmetic operations involving UFix, SFix and other -- numeric types. -- The operators are overloaded for most of the sensible -- combinations of SFix, UFix, UNSIGNED, SIGNED and INTEGER. -- -- IMPORTANT NOTE: -- Arithmetic operators return a result that is wide enough -- and precise enough so that no information is lost. THIS IS -- SIGNIFICANTLY DIFFERENT FROM THE BEHAVIOUR OF numeric_std. -- In the detailed description that follow, "scaling" means -- the numerical value (weight) of the least significant bit -- in a fixed-point value. -- -- ADDITION returns a result whose least significant bit -- is the same as the least significant bit in either operand, -- and whose most significant bit is one position higher than -- the most significant bit in either operand. Addition of -- two operands having the same bounds therefore results in -- a growth of one bit at the most significant end. Addition -- of an integer to a UFix or SFix is accomplished by first -- converting the integer to the same subtype as the other -- operand, thereby giving rise to one-bit growth; default -- truncation and rounding modes are used for the conversion. -- -- SUBTRACTION where one or both operands are signed behaves -- in the same way as addition. Subtraction where both operands -- are unsigned returns a result whose most significant bit -- position is the same as the most significant bit in either -- operand, and whose least significant bit is the same as the -- least significant bit in either operand. -- -- MULTIPLICATION returns a result whose width is the sum of -- the widths of its two operands, and whose scaling is the -- product of its two operands' scalings. -- -- UNARY NEGATION always gives a result having one more -- significant bit than the operand. -- -- ABSOLUTE VALUE always gives a result having exactly the -- same subtype as its operand. -- -- In binary operations where one operand is a fixed-point type -- and the other is an integer numeric type, the integer operand -- is first converted to a fixed-point type of the same subtype -- as the other operand using Copy_V with default rounding and -- overflow modes. The operation is then performed between two -- fixed-point operands in the normal way. -- ------------------------------------------------------------------ ------------------------------------ -- A.1. Unary "-" negation operator ------------------------------------ -- A.1.1. SFix := - UFix function "-" (R: UFix) return SFix is variable F: SFix(R'LEFT+1 downto R'RIGHT); begin F := SFix(-(signed('0' & R))); return F; end; -- A.1.2. SFix := - SFix function "-" (R: SFix) return SFix is variable F: SFix(R'LEFT+1 downto R'RIGHT); begin F := SFix(-(signed(R(R'LEFT) & R))); return F; end; -------------------------------------------- -- A.2. Unary "abs" absolute-value operator -------------------------------------------- -- A.2.1. SFix := abs SFix function "abs" (R: SFix) return SFix is variable F: SFix(R'RANGE); begin F := R; if to_X01(R(R'LEFT)) = '1' then F := SFix(-(signed(R))); end if; return F; end; ------------------------------------- -- A.3. Binary "+" addition operator ------------------------------------- -- A.3.1. UFix := UFix + UFix function "+" (L: UFix; R: UFix) return UFix is variable F: UFix(Max(L'LEFT, R'LEFT)+1 downto Min(L'Right, R'Right)); variable LU, RU: unsigned(F'RANGE); begin LU := (others => '0'); RU := (others => '0'); LU(L'RANGE) := unsigned(L); RU(R'RANGE) := unsigned(R); F := UFix(LU + RU); return F; end; -- A.3.2. UFix := UFix + unsigned function "+" (L: UFix; R: unsigned) return UFix is begin return L + to_UFix(R); end; -- A.3.3. UFix := unsigned + UFix function "+" (L: unsigned; R: UFix) return UFix is begin return R+L; end; -- A.3.4. UFix := UFix + natural function "+" (L: UFix; R: natural) return UFix is variable R_fp: UFix(L'RANGE); begin Copy_V(R_fp, R); return L + R_fp; end; -- A.3.5. UFix := natural + UFix function "+" (L: natural; R: UFix) return UFix is begin return R+L; end; -- A.3.6. SFix := SFix + SFix function "+" (L: SFix; R: SFix) return SFix is variable F: SFix(Max(L'LEFT, R'LEFT)+1 downto Min(L'Right, R'Right)); variable LS, RS: signed(F'RANGE); begin LS := (others => '0'); RS := (others => '0'); LS(L'RANGE) := signed(L); RS(R'RANGE) := signed(R); for i in LS'LEFT downto L'LEFT+1 loop LS(i) := L(L'LEFT); end loop; for i in RS'LEFT downto R'LEFT+1 loop RS(i) := R(R'LEFT); end loop; F := SFix(LS + RS); return F; end; -- A.3.7. SFix := SFix + UFix function "+" (L: SFix; R: UFix) return SFix is begin return L + SFix('0' & R); end; -- A.3.8. SFix := UFix + SFix function "+" (L: UFix; R: SFix) return SFix is begin return SFix('0' & L) + R; end; -- A.3.9. SFix := SFix + signed function "+" (L: SFix; R: signed) return SFix is begin return L + to_SFix(R); end; -- A.3.10. SFix := signed + SFix function "+" (L: signed; R: SFix) return SFix is begin return to_SFix(L) + R; end; -- A.3.11. SFix := SFix + integer function "+" (L: SFix; R: integer) return SFix is variable R_fp: SFix(L'RANGE); begin Copy_V(R_fp, R); return L + R_fp; end; -- A.3.12. SFix := integer + SFix function "+" (L: integer; R: SFix) return SFix is begin return R + L; end; ---------------------------------------- -- A.4. Binary "-" subtraction operator ---------------------------------------- -- -- NOTE: There is a special problem with subtraction -- operators that return a UFix result if that result -- goes negative. Our arbitrary decision is that we -- truncate most-significant bits in this case. If you -- wish to avoid the risk of this arbitrarily-defined -- truncation behaviour, change one or more of your -- operands to SFix and get a SFix result using this -- idiom: -- SFix := UFix + (-UFix) -- or copy one of the UFix operands into a SFix that's -- one bit wider, before performing the operation. -- -- Subtractions returning a UFix result take unsigned -- operands and do not exhibit bit growth. -- Subtractions returning a SFix result take signed or -- unsigned operands and exhibit one-bit growth like addition. -- A.4.1. UFix := UFix - UFix function "-" (L: UFix; R: UFix) return UFix is variable F, LW, RW: UFix(Max(L'LEFT, R'LEFT) downto Min(L'RIGHT, R'RIGHT)); begin LW := (others => '0'); RW := (others => '0'); LW(L'RANGE) := L; RW(R'RANGE) := R; F := UFix(unsigned(LW) - unsigned(RW)); return F; end; -- A.4.2. UFix := UFix - unsigned function "-" (L: UFix; R: unsigned) return UFix is begin return L - to_UFix(R); end; -- A.4.3. UFix := unsigned - UFix function "-" (L: unsigned; R: UFix) return UFix is begin return to_UFix(L) - R; end; -- A.4.4. UFix := UFix - integer function "-" (L: UFix; R: natural) return UFix is variable R_fp: UFix(L'RANGE); begin Copy_V(R_fp, R); return L - R_fp; end; -- A.4.5. UFix := natural - UFix function "-" (L: natural; R: UFix) return UFix is variable L_fp: UFix(R'RANGE); begin Copy_V(L_fp, L); return L_fp - R; end; -- A.4.6. SFix := SFix - SFix function "-" (L: SFix; R: SFix) return SFix is begin return L + (-R); end; -- A.4.7. SFix := SFix - UFix function "-" (L: SFix; R: UFix) return SFix is begin return L + (-R); end; -- A.4.8. SFix := UFix - SFix function "-" (L: UFix; R: SFix) return SFix is begin return To_SFix(L) - R; end; -- A.4.9. SFix := SFix - signed function "-" (L: SFix; R: signed) return SFix is begin return L - to_SFix(R); end; -- A.4.10. SFix := signed - SFix function "-" (L: signed; R: SFix) return SFix is begin return to_SFix(L) - R; end; -- A.4.11. SFix := SFix - integer function "-" (L: SFix; R: integer) return SFix is variable R_fp: SFix(L'RANGE); begin Copy_V(R_fp, R); return L - R_fp; end; -- A.4.12. SFix := integer - SFix function "-" (L: integer; R: SFix) return SFix is variable L_fp: SFix(R'RANGE); begin Copy_V(L_fp, L); return L_fp - R; end; ------------------------------------------- -- A.5. Binary "*" multiplication operator ------------------------------------------- -- A.5.1. UFix := UFix * UFix function "*" (L: UFix; R: UFix) return UFix is variable F: UFix(L'LEFT+R'LEFT+1-FixP downto L'RIGHT+R'RIGHT-FixP); begin F := UFix(unsigned(L) * unsigned(R)); return F; end; -- A.5.2. UFix := UFix * unsigned function "*" (L: UFix; R: unsigned) return UFix is begin return L * to_UFix(R); end; -- A.5.3. UFix := unsigned * UFix function "*" (L: unsigned; R: UFix) return UFix is begin return to_UFix(L) * R; end; -- A.5.4. UFix := UFix * natural function "*" (L: UFix; R: natural) return UFix is variable R_fp: UFix(L'RANGE); begin Copy_V(R_fp, R); return L * R_fp; end; -- A.5.5. UFix := natural * UFix function "*" (L: natural; R: UFix) return UFix is begin return R * L; end; -- A.5.6. SFix := SFix * SFix function "*" (L: SFix; R: SFix) return SFix is variable F: SFix(L'LEFT+R'LEFT+1-FixP downto L'RIGHT+R'RIGHT-FixP); begin F := SFix(signed(L) * signed(R)); return F; end; -- A.5.7. SFix := SFix * UFix function "*" (L: SFix; R: UFix) return SFix is constant RS: SFix := SFix('0' & R); variable F: SFix(L'LEFT+R'LEFT+1-FixP downto L'RIGHT+R'RIGHT-FixP); variable FW: SFix(F'LEFT+1 downto F'RIGHT); begin FW := SFix(signed(L) * signed(RS)); Copy_V(F, FW); -- never overflows return F; end; -- A.5.8. SFix := UFix * SFix function "*" (L: UFix; R: SFix) return SFix is begin return R * L; end; -- A.5.9. SFix := SFix * signed function "*" (L: SFix; R: signed) return SFix is begin return L * to_SFix(R); end; -- A.5.10. SFix := signed * SFix function "*" (L: signed; R: SFix) return SFix is begin return to_SFix(L) * R; end; -- A.5.11. SFix := SFix * integer function "*" (L: SFix; R: integer) return SFix is variable R_fp: SFix(L'RANGE); begin Copy_V(R_fp, R); return L * R_fp; end; -- A.5.12. SFix := integer * SFix function "*" (L: integer; R: SFix) return SFix is begin return R * L; end; ------------------------------------------------------------------ -- R. Relational operators - arithmetic comparisons involving -- UFix, SFix and other numeric types. -- The operators are overloaded for most of the sensible -- combinations of SFix, UFix, UNSIGNED, SIGNED and INTEGER. -- Note that in all cases comparisons are exact; if one -- operand has more fraction bits than the other, the less -- precise operand will have its LSBs zero-extended, and -- these zero bits will take part in comparison with whatever -- LSBs exist in the more precise operand. -- -- Our implementation is based on only two operators, "=" and "<". -- All other operators are derived from these two, either by -- logical inversion of the result or by swapping operands. ------------------------------------------------------------------ ------------------------------------- -- R.1. Binary "=" equality operator ------------------------------------- -- R.1.1. UFix = UFix function "=" (L: UFix; R: UFix) return boolean is variable LW, RW: UFix(Max(L'LEFT, R'LEFT) downto Min(L'RIGHT, R'RIGHT)); begin LW := (others => '0'); RW := (others => '0'); LW(L'RANGE) := L; RW(R'RANGE) := R; return unsigned(LW) = unsigned(RW); end; -- R.1.2. UFix = unsigned function "=" (L: UFix; R: unsigned) return boolean is begin return L = to_UFix(R); end; -- R.1.3. unsigned = UFix function "=" (L: unsigned; R: UFix) return boolean is begin return to_UFix(L) = R; end; -- R.1.4. UFix = integer function "=" (L: UFix; R: integer) return boolean is variable RS: SFix(FixP+INT_WIDTH-1 downto FixP); begin Copy_V(RS, R, clip_MS, clip_LS); return To_SFix(L) = RS; end; -- R.1.5. integer = UFix function "=" (L: integer; R: UFix) return boolean is begin return R = L; end; -- R.1.6. SFix = SFix function "=" (L: SFix; R: SFix) return boolean is variable LW, RW: SFix(Max(L'LEFT, R'LEFT) downto Min(L'RIGHT, R'RIGHT)); begin -- clip modes are OK because we aren't losing any bits Copy_V(LW, L, clip_MS, clip_LS); Copy_V(RW, R, clip_MS, clip_LS); return signed(LW) = signed(RW); end; -- R.1.7. SFix = UFix function "=" (L: SFix; R: UFix) return boolean is begin return L = To_SFix(R); end; -- R.1.8. UFix = SFix function "=" (L: UFix; R: SFix) return boolean is begin return R = L; end; -- R.1.9. SFix = signed function "=" (L: SFix; R: signed) return boolean is begin return L = to_SFix(R); end; -- R.1.10. signed = SFix function "=" (L: signed; R: SFix) return boolean is begin return to_SFix(L) = R; end; -- R.1.11. SFix = integer function "=" (L: SFix; R: integer) return boolean is variable RS: SFix(FixP+INT_WIDTH-1 downto FixP); begin Copy_V(RS, R, clip_MS, clip_LS); return L = RS; end; -- R.1.12. integer = SFix function "=" (L: integer; R: SFix) return boolean is begin return R = L; end; -------------------------------------- -- R.2. Binary "<" less-than operator -------------------------------------- -- R.2.1. UFix < UFix function "<" (L: UFix; R: UFix) return boolean is variable LW, RW: unsigned(Max(L'LEFT, R'LEFT) downto Min(L'RIGHT, R'RIGHT)); begin LW := (others => '0'); RW := (others => '0'); LW(L'RANGE) := unsigned(L); RW(R'RANGE) := unsigned(R); return unsigned(LW) < unsigned(RW); end; -- R.2.2. UFix < unsigned function "<" (L: UFix; R: unsigned) return boolean is begin return L < To_UFix(R); end; -- R.2.3. unsigned < UFix function "<" (L: unsigned; R: UFix) return boolean is begin return To_UFix(L) < R; end; -- R.2.4. UFix < integer function "<" (L: UFix; R: integer) return boolean is variable S: SFix(FixP+INT_WIDTH-1 downto FixP); begin Copy_V(S, R, clip_MS, clip_LS); return L < S; end; -- R.2.5. integer < UFix function "<" (L: integer; R: UFix) return boolean is variable S: SFix(FixP+INT_WIDTH-1 downto FixP); begin Copy_V(S, L, clip_MS, clip_LS); return S < R; end; -- R.2.6. SFix < SFix function "<" (L: SFix; R: SFix) return boolean is variable LW, RW: SFix(Max(L'LEFT, R'LEFT) downto Min(L'RIGHT, R'RIGHT)); begin Copy_V(LW, L, clip_MS, clip_LS); Copy_V(RW, R, clip_MS, clip_LS); return signed(LW) < signed(RW); end; -- R.2.7. SFix < UFix function "<" (L: SFix; R: UFix) return boolean is begin return L < To_SFix(R); end; -- R.2.8. UFix < SFix function "<" (L: UFix; R: SFix) return boolean is begin return To_SFix(L) < R; end; -- R.2.9. SFix < signed function "<" (L: SFix; R: signed) return boolean is begin return L < To_SFix(R); end; -- R.2.10. signed < SFix function "<" (L: signed; R: SFix) return boolean is begin return To_SFix(L) < R; end; -- R.2.11. SFix < integer function "<" (L: SFix; R: integer) return boolean is variable S: SFix(FixP+INT_WIDTH-1 downto FixP); begin Copy_V(S, R, clip_MS, clip_LS); return L < S; end; -- R.2.12. integer < SFix function "<" (L: integer; R: SFix) return boolean is variable S: SFix(FixP+INT_WIDTH-1 downto FixP); begin Copy_V(S, L, clip_MS, clip_LS); return S < R; end; ---------------------------------------- -- R.3. Binary "/=" inequality operator ---------------------------------------- -- R.3.1. UFix /= UFix function "/=" (L: UFix; R: UFix) return boolean is begin return not (L = R); end; -- R.3.2. UFix /= unsigned function "/=" (L: UFix; R: unsigned) return boolean is begin return not (L = R); end; -- R.3.3. unsigned /= UFix function "/=" (L: unsigned; R: UFix) return boolean is begin return not (L = R); end; -- R.3.4. UFix /= integer function "/=" (L: UFix; R: integer) return boolean is begin return not (L = R); end; -- R.3.5. integer /= UFix function "/=" (L: integer; R: UFix) return boolean is begin return not (L = R); end; -- R.3.6. SFix /= SFix function "/=" (L: SFix; R: SFix) return boolean is begin return not (L = R); end; -- R.3.7. SFix /= UFix function "/=" (L: SFix; R: UFix) return boolean is begin return not (L = R); end; -- R.3.8. UFix /= SFix function "/=" (L: UFix; R: SFix) return boolean is begin return not (L = R); end; -- R.3.9. SFix /= signed function "/=" (L: SFix; R: signed) return boolean is begin return not (L = R); end; -- R.3.10. signed /= SFix function "/=" (L: signed; R: SFix) return boolean is begin return not (L = R); end; -- R.3.11. SFix /= integer function "/=" (L: SFix; R: integer) return boolean is begin return not (L = R); end; -- R.3.12. integer /= SFix function "/=" (L: integer; R: SFix) return boolean is begin return not (L = R); end; ----------------------------------------- -- R.4. Binary ">" greater-than operator ----------------------------------------- -- R.4.1. UFix > UFix function ">" (L: UFix; R: UFix) return boolean is begin return R < L; end; -- R.4.2. UFix > unsigned function ">" (L: UFix; R: unsigned) return boolean is begin return R < L; end; -- R.4.3. unsigned > UFix function ">" (L: unsigned; R: UFix) return boolean is begin return R < L; end; -- R.4.4. UFix > integer function ">" (L: UFix; R: integer) return boolean is begin return R < L; end; -- R.4.5. integer > UFix function ">" (L: integer; R: UFix) return boolean is begin return R < L; end; -- R.4.6. SFix > SFix function ">" (L: SFix; R: SFix) return boolean is begin return R < L; end; -- R.4.7. SFix > UFix function ">" (L: SFix; R: UFix) return boolean is begin return R < L; end; -- R.4.8. UFix > SFix function ">" (L: UFix; R: SFix) return boolean is begin return R < L; end; -- R.4.9. SFix > signed function ">" (L: SFix; R: signed) return boolean is begin return R < L; end; -- R.4.10. signed > SFix function ">" (L: signed; R: SFix) return boolean is begin return R < L; end; -- R.4.11. SFix > integer function ">" (L: SFix; R: integer) return boolean is begin return R < L; end; -- R.4.12. integer > SFix function ">" (L: integer; R: SFix) return boolean is begin return R < L; end; ---------------------------------------------- -- R.5. Binary ">=" greater-or-equal operator ---------------------------------------------- -- R.5.1. UFix >= UFix function ">=" (L: UFix; R: UFix) return boolean is begin return not (L < R); end; -- R.5.2. UFix >= unsigned function ">=" (L: UFix; R: unsigned) return boolean is begin return not (L < R); end; -- R.5.3. unsigned >= UFix function ">=" (L: unsigned; R: UFix) return boolean is begin return not (L < R); end; -- R.5.4. UFix >= integer function ">=" (L: UFix; R: integer) return boolean is begin return not (L < R); end; -- R.5.5. integer >= UFix function ">=" (L: integer; R: UFix) return boolean is begin return not (L < R); end; -- R.5.6. SFix >= SFix function ">=" (L: SFix; R: SFix) return boolean is begin return not (L < R); end; -- R.5.7. SFix >= UFix function ">=" (L: SFix; R: UFix) return boolean is begin return not (L < R); end; -- R.5.8. UFix >= SFix function ">=" (L: UFix; R: SFix) return boolean is begin return not (L < R); end; -- R.5.9. SFix >= signed function ">=" (L: SFix; R: signed) return boolean is begin return not (L < R); end; -- R.5.10. signed >= SFix function ">=" (L: signed; R: SFix) return boolean is begin return not (L < R); end; -- R.5.11. SFix >= integer function ">=" (L: SFix; R: integer) return boolean is begin return not (L < R); end; -- R.5.12. integer >= SFix function ">=" (L: integer; R: SFix) return boolean is begin return not (L < R); end; ------------------------------------------- -- R.6. Binary "<=" less-or-equal operator ------------------------------------------- -- R.6.1. UFix <= UFix function "<=" (L: UFix; R: UFix) return boolean is begin return not (R < L); end; -- R.6.2. UFix <= unsigned function "<=" (L: UFix; R: unsigned) return boolean is begin return not (R < L); end; -- R.6.3. unsigned <= UFix function "<=" (L: unsigned; R: UFix) return boolean is begin return not (R < L); end; -- R.6.4. UFix <= integer function "<=" (L: UFix; R: integer) return boolean is begin return not (R < L); end; -- R.6.5. integer <= UFix function "<=" (L: integer; R: UFix) return boolean is begin return not (R < L); end; -- R.6.6. SFix <= SFix function "<=" (L: SFix; R: SFix) return boolean is begin return not (R < L); end; -- R.6.7. SFix <= UFix function "<=" (L: SFix; R: UFix) return boolean is begin return not (R < L); end; -- R.6.8. UFix <= SFix function "<=" (L: UFix; R: SFix) return boolean is begin return not (R < L); end; -- R.6.9. SFix <= signed function "<=" (L: SFix; R: signed) return boolean is begin return not (R < L); end; -- R.6.10. signed <= SFix function "<=" (L: signed; R: SFix) return boolean is begin return not (R < L); end; -- R.6.11. SFix <= integer function "<=" (L: SFix; R: integer) return boolean is begin return not (R < L); end; -- R.6.12. integer <= SFix function "<=" (L: integer; R: SFix) return boolean is begin return not (R < L); end; ------------------------------------------------------------------ -- C. Concatenation operators between fixed-point operands, and -- between fixed-point operands and other reasonable types. -- Unlike the implicitly defined "&" operator, they preserve -- place value and return an appropriately aligned subtype. -- Preservation of place value means that some concatenation -- operations are illegal. In particular, operations -- [SFix & SFix] and [UFix & SFix] are illegal, and -- the place values of operands in [SFix & UFix] and -- [UFix & UFix] must match up - the rightmost subscript of -- the left operand must be one higher than the leftmost -- subscript of the right operand. -- Single bits of type std_ulogic may be concatenated with -- fixed-point types where there is no risk of losing -- sign-extension information. -- Because of the way VHDL defines implicit concatenation, -- it is impossible to detect all these errors at compile time. -- Instead they are detected by assertion statements at run time. -- Tool vendors may choose to implement compile-time checks -- so that the run-time checking overhead can be avoided. ------------------------------------------------------------------ -- C.1.1. UFix := UFix & UFix function "&" (L: UFix; R: UFix) return UFix is begin return UFix(concat(std_logic_vector(L), std_logic_vector(R))); end; -- C.1.2. UFix := UFix & std_ulogic function "&" (L: UFix; R: std_ulogic) return UFix is begin return UFix(concat(std_logic_vector(L), R)); end; -- C.1.3. UFix := std_ulogic & UFix function "&" (L: std_ulogic; R: UFix) return UFix is begin return UFix(concat(L, std_logic_vector(R))); end; -- C.2.1. SFix := SFix & UFix function "&" (L: SFix; R: UFix) return SFix is begin return SFix(concat(std_logic_vector(L), std_logic_vector(R))); end; -- C.2.2. SFix := SFix & SFix -- ILLEGAL function "&" (L: SFix; R: SFix) return SFix is begin report concat_signLS_msg severity concat_severity; return SFix(concat(std_logic_vector(L), std_logic_vector(R))); end; -- C.2.3. SFix := SFix & std_ulogic function "&" (L: SFix; R: std_ulogic) return SFix is begin return SFix(concat(std_logic_vector(L), R)); end; -- C.2.4. SFix := std_ulogic & SFix function "&" (L: std_ulogic; R: SFix) return SFix is begin assert std_match(L, R(R'LEFT)) report concat_sxt_msg severity concat_severity; return SFix(concat(L, std_logic_vector(R))); end; end; -- package body fix_std;