1911 lines
53 KiB
VHDL
1911 lines
53 KiB
VHDL
---------------------------------------------------------------------
|
|
--
|
|
-- 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<R then
|
|
return L;
|
|
else
|
|
return R;
|
|
end if;
|
|
end;
|
|
|
|
-- concat:
|
|
--
|
|
-- This helper function automates the calculation of return
|
|
-- subtype range in concatenation operators "&".
|
|
--
|
|
function concat(L, R: std_logic_vector) return std_logic_vector is
|
|
variable F: std_logic_vector(L'LEFT downto R'RIGHT);
|
|
begin
|
|
if L'LENGTH = 0 then
|
|
return R;
|
|
elsif R'LENGTH = 0 then
|
|
return L;
|
|
else
|
|
assert L'RIGHT = R'LEFT+1
|
|
report concat_range_msg
|
|
severity concat_severity;
|
|
F := L & R;
|
|
return F;
|
|
end if;
|
|
end;
|
|
--
|
|
function concat(L: std_logic; R: std_logic_vector)
|
|
return std_logic_vector is
|
|
variable F: std_logic_vector(R'LEFT+1 downto R'RIGHT);
|
|
begin
|
|
F := L & R;
|
|
return F;
|
|
end;
|
|
--
|
|
function concat(L: std_logic_vector; R: std_ulogic)
|
|
return std_logic_vector is
|
|
variable F: std_logic_vector(L'LEFT downto L'RIGHT-1);
|
|
begin
|
|
F := L & R;
|
|
return F;
|
|
end;
|
|
|
|
--------------------------------------------------------------------
|
|
-- IMPLEMENTATIONS OF PUBLIC SUBPROGRAMS
|
|
--------------------------------------------------------------------
|
|
|
|
---------------------------
|
|
-- E. Extraction functions
|
|
---------------------------
|
|
|
|
-- E.1. Return the integral part of a UFix value
|
|
function Int(U: UFix) return UFix is
|
|
begin
|
|
if U'LEFT < FixP then
|
|
return Izero_UFix;
|
|
elsif U'RIGHT > 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;
|