diff --git a/libraries/base/common/hdllib.cfg b/libraries/base/common/hdllib.cfg index 573c1a56f9f3c6b1f054c8b8d5af998d8b1ca4cc..6e815027bcfc900a809dc93fecf5bf33026710ee 100644 --- a/libraries/base/common/hdllib.cfg +++ b/libraries/base/common/hdllib.cfg @@ -192,6 +192,7 @@ test_bench_files = tb/vhdl/tb_requantize.vhd tb/vhdl/tb_resize.vhd tb/vhdl/tb_round.vhd + tb/vhdl/tb_common_to_sreal.vhd tb/vhdl/tb_delta_cycle_demo.vhd tb/vhdl/tb_mms_common_variable_delay.vhd @@ -220,6 +221,7 @@ regression_test_vhdl = tb/vhdl/tb_resize.vhd #tb/vhdl/tb_round.vhd -- has no self verification yet tb/vhdl/tb_requantize.vhd + tb/vhdl/tb_common_to_sreal.vhd tb/vhdl/tb_common_pulse_delay.vhd tb/vhdl/tb_tb_common_adder_tree.vhd diff --git a/libraries/base/common/src/vhdl/common_pkg.vhd b/libraries/base/common/src/vhdl/common_pkg.vhd index e5093bd08e56674e7712ca98d0794a8636bfff1c..55a7a6a8446deaa3f36105b592d966a147a37d67 100644 --- a/libraries/base/common/src/vhdl/common_pkg.vhd +++ b/libraries/base/common/src/vhdl/common_pkg.vhd @@ -370,11 +370,16 @@ PACKAGE common_pkg IS FUNCTION TO_UVEC(dec, w : NATURAL) RETURN STD_LOGIC_VECTOR; FUNCTION TO_SVEC(dec, w : INTEGER) RETURN STD_LOGIC_VECTOR; - + FUNCTION TO_SVEC_32(dec : INTEGER) RETURN STD_LOGIC_VECTOR; -- = TO_SVEC() with w=32 for t_slv_32_arr slv elements - - FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR) RETURN REAL; -- convert unsigned slv of any length to REAL - FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR) RETURN REAL; -- convert signed slv of any length to REAL + + FUNCTION TO_UINT(udec : REAL; w, resolution_w : INTEGER) RETURN NATURAL; -- REAL >= 0 to NATURAL fixed point number + FUNCTION TO_SINT(sdec : REAL; w, resolution_w : INTEGER) RETURN INTEGER; -- REAL to INTEGER fixed point number + FUNCTION TO_UVEC(udec : REAL; w, resolution_w : INTEGER) RETURN STD_LOGIC_VECTOR; -- REAL >= 0 to unsigned SLV fixed point number + FUNCTION TO_SVEC(sdec : REAL; w, resolution_w : INTEGER) RETURN STD_LOGIC_VECTOR; -- REAL to signed SLV fixed point number + + FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR) RETURN REAL; -- convert unsigned slv of any length to REAL, fixed point number with resolution = 1 + FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR) RETURN REAL; -- convert signed slv of any length to REAL, fixed point number with resolution = 1 FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL; -- convert unsigned fixed point slv of any length, and with resolution of 2**resolution_w, to REAL FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL; -- convert signed fixed point slv of any length, and with resolution of 2**resolution_w, to REAL @@ -1807,67 +1812,164 @@ PACKAGE BODY common_pkg IS BEGIN RETURN STD_LOGIC_VECTOR(TO_SIGNED(dec, w)); END; - + FUNCTION TO_SVEC_32(dec : INTEGER) RETURN STD_LOGIC_VECTOR IS BEGIN RETURN TO_SVEC(dec, 32); END; + FUNCTION TO_UINT(udec : REAL; w, resolution_w : INTEGER) RETURN NATURAL IS + CONSTANT c_resolution : REAL := 1.0 / 2.0**REAL(resolution_w); + CONSTANT c_ureal : REAL := ROUND(udec / c_resolution); -- rounds away from zero + BEGIN + IF udec >= 0.0 THEN + RETURN TO_SINT(udec, w + 1, resolution_w); -- w + 1, because unsigned has no sign bit + ELSE + REPORT "Negative REAL clipped to INTEGER 0 : " & REAL'IMAGE(c_ureal) & " --> 0" SEVERITY WARNING; + RETURN 0; + END IF; + END; + + FUNCTION TO_SINT(sdec : REAL; w, resolution_w : INTEGER) RETURN INTEGER IS + CONSTANT c_max : REAL := 2.0**REAL(w - 1) - 1.0; + CONSTANT c_min : REAL := -2.0**REAL(w - 1); + CONSTANT c_resolution : REAL := 1.0 / 2.0**REAL(resolution_w); + CONSTANT c_sreal : REAL := ROUND(sdec / c_resolution); -- rounds away from zero + CONSTANT c_sint : INTEGER := INTEGER(c_sreal); + BEGIN + IF c_sreal >= c_min THEN + IF c_sreal <= c_max THEN + RETURN c_sint; + ELSE + REPORT "REAL clipped to INTEGER max : " & REAL'IMAGE(c_sreal) & " --> " & INTEGER'IMAGE(INTEGER(c_max)) SEVERITY WARNING; + RETURN INTEGER(c_max); -- clip to max + END IF; + ELSE + REPORT "REAL clipped to INTEGER min : " & REAL'IMAGE(c_sreal) & " --> " & INTEGER'IMAGE(INTEGER(c_min)) SEVERITY WARNING; + RETURN INTEGER(c_min); -- clip to min + END IF; + END; + + FUNCTION TO_UVEC(udec : REAL; w, resolution_w : INTEGER) RETURN STD_LOGIC_VECTOR IS + -- Determine range that fits w bits + CONSTANT c_uvec_max : STD_LOGIC_VECTOR(w-1 DOWNTO 0) := (OTHERS => '1'); + CONSTANT c_max : REAL := 2.0**REAL(w) - 1.0; + CONSTANT c_resolution : REAL := 1.0 / 2.0**REAL(resolution_w); + VARIABLE v_ureal : REAL := ROUND(udec / c_resolution); -- rounds away from zero + -- Convert to uvec + VARIABLE v_floor : REAL := 0.0; + VARIABLE v_uvec : STD_LOGIC_VECTOR(w-1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + IF udec >= 0.0 THEN + IF v_ureal <= c_max THEN + -- Avoid using INTEGER, which is limited to 32 bit, by determining per + -- bit whether the REAL value contributes to it. + -- If the REAL, after fixed point scaling by c_resolution, fits in w + -- bits, then the remainer v_floor after w times dividing by 2.0 will + -- be 0.0, because 2**w * 0.5 = 2**(w-1). For example u(4,0) = 7.0 + -- yields: + -- 7.0 / 2 = 3.5 --> [0] = '1' + -- floor(3.5) = 3.0 / 2 = 1.5 --> [1] = '1' + -- floor(1.5) = 1.0 / 2 = 0.5 --> [2] = '1' + -- floor(0.5) = 0.0 / 2 = 0.0 --> [3] = '0' + -- so u(4,0) = 7.0 yields remainder 0.0 and SLV[3:0] = "0111" + -- similar u(4,0) = 8.0 yields remainder 0.5 and SLV[3:0] = "1000" + -- and u(4,0) > 8.0 yields remainder >= 0.5 + FOR I IN 0 TO w-1 LOOP + v_ureal := v_ureal / 2.0; + v_floor := floor(v_ureal); + IF v_ureal > v_floor THEN + v_uvec(I) := '1'; + END IF; + v_ureal := v_floor; + END LOOP; + ASSERT v_floor = 0.0 REPORT "Unexpected TO_UVEC REAL remainder : " & REAL'IMAGE(v_floor) & " /= 0.0" SEVERITY FAILURE; + RETURN v_uvec; + ELSE + REPORT "Positive REAL clipped to UVEC max : " & REAL'IMAGE(v_ureal) & " --> " & REAL'IMAGE(c_max) SEVERITY WARNING; + RETURN c_uvec_max; + END IF; + ELSE + REPORT "Negative REAL clipped to UVEC 0 : " & REAL'IMAGE(v_ureal) & " --> 0" SEVERITY WARNING; + RETURN TO_UVEC(0, w); + END IF; + END; + + FUNCTION TO_SVEC(sdec : REAL; w, resolution_w : INTEGER) RETURN STD_LOGIC_VECTOR IS + -- Determine range that fits w bits + CONSTANT c_svec_max : STD_LOGIC_VECTOR(w-1 DOWNTO 0) := '0' & (w-2 DOWNTO 0 => '1'); + CONSTANT c_svec_min : STD_LOGIC_VECTOR(w-1 DOWNTO 0) := '1' & (w-2 DOWNTO 0 => '0'); + CONSTANT c_max : REAL := 2.0**REAL(w - 1) - 1.0; + CONSTANT c_min : REAL := -2.0**REAL(w - 1); + CONSTANT c_resolution : REAL := 1.0 / 2.0**REAL(resolution_w); + CONSTANT c_sreal : REAL := ROUND(sdec / c_resolution); -- rounds away from zero + -- Convert to positive using TO_UVEC, so if sdec is negative, then + -- negate sdec to have positive c_udec. + CONSTANT c_pos : BOOLEAN := sdec >= 0.0; + CONSTANT c_udec : REAL := sel_a_b(c_pos, sdec, -sdec); + -- Determine SLV value for positive REAL, use w+1 to fit negate of most negative value + CONSTANT c_uvec : STD_LOGIC_VECTOR(w DOWNTO 0) := TO_UVEC(c_udec, w + 1, resolution_w); + -- Back to signed, so if sdec is negative, then negate c_uvec to have positive c_svec + CONSTANT c_svec : STD_LOGIC_VECTOR(w DOWNTO 0) := sel_a_b(c_pos, c_uvec, NEGATE_SVEC(c_uvec)); + BEGIN + IF c_sreal >= c_min THEN + IF c_sreal <= c_max THEN + RETURN c_svec(w-1 DOWNTO 0); + ELSE + REPORT "REAL clipped to SVEC max : " & REAL'IMAGE(c_sreal) & " --> " & REAL'IMAGE(c_max) SEVERITY WARNING; + RETURN c_svec_max; -- clip to max + END IF; + ELSE + REPORT "REAL clipped to SVEC min : " & REAL'IMAGE(c_sreal) & " --> " & REAL'IMAGE(c_min) SEVERITY WARNING; + RETURN c_svec_min; -- clip to min + END IF; + END; + FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR) RETURN REAL IS CONSTANT c_len : NATURAL := uvec'LENGTH; - VARIABLE v_uvec : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0) := uvec; + CONSTANT c_uvec : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0) := uvec; VARIABLE v_real : REAL := 0.0; BEGIN -- Avoid using INTEGER, which is limited to 32 bit, by determining per bit whether it contributes to the REAL value FOR I IN 0 TO c_len-1 LOOP - IF v_uvec(I)='1' THEN - v_real := v_real + 2**REAL(I); + IF c_uvec(I)='1' THEN + v_real := v_real + 2.0**REAL(I); END IF; END LOOP; RETURN v_real; END; FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR) RETURN REAL IS - CONSTANT c_len : NATURAL := svec'LENGTH + 1; -- use +1 so the v_uvec can also fit abs() of most negative is -1 * -2**(c_len-1) - VARIABLE v_pos : BOOLEAN := TRUE; - VARIABLE v_uvec : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0) := RESIZE_SVEC(svec, c_len); - VARIABLE v_real : REAL := 0.0; - BEGIN - -- Negate svec to have positive v_uvec. - IF SIGNED(svec) < 0 THEN - v_pos := FALSE; - v_uvec := INCR_UVEC(NOT svec, 1); -- negate the svec to make it positive - END IF; + -- Increase vector length by +1 so the c_uvec can also fit abs() of most negative is -1 * -2**(c_len-1) + CONSTANT c_len : NATURAL := svec'LENGTH + 1; + CONSTANT c_svec : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0) := RESIZE_SVEC(svec, c_len); + -- If c_svec is negative, then negate c_svec to have positive c_uvec. + CONSTANT c_pos : BOOLEAN := SIGNED(svec) >= 0; + CONSTANT c_uvec : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0) := sel_a_b(c_pos, c_svec, NEGATE_SVEC(c_svec)); -- Determine REAL value for positive - v_real := TO_UREAL(v_uvec); + CONSTANT c_real : REAL := TO_UREAL(c_uvec); + BEGIN -- Update the sign - IF v_pos THEN - RETURN v_real; - ELSE - RETURN -v_real; - END IF; + RETURN sel_a_b(c_pos, c_real, -c_real); END; FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL IS - -- First convert as unsigned integer: - VARIABLE v_real : REAL := TO_UREAL(uvec); BEGIN - -- Then scale to real (see TO_SREAL) - RETURN v_real * 2.0**REAL(resolution_w); + -- First convert as unsigned integer, then scale to real. See TO_SREAL() + -- for interpretation of resolution_w + RETURN TO_UREAL(uvec) / 2.0**REAL(resolution_w); END; FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL IS - -- First convert as signed integer: - VARIABLE v_real : REAL := TO_SREAL(svec); BEGIN - -- Then scale to real: + -- First convert as unsigned integer, then scale to real -- . The resolution_w is the number of bits that LSbit 0 in svec(HIGH-1 DOWNTO 0) is after -- (when resolution_w > 0), or before (when resolution_w < 0) the fixed point. - -- . The real value is then scaled by scaling the integer value by 2**(-1 * resolution_w): + -- . The real value is then scaled by scaling the integer value by 1.0 / 2**(resolution_w): -- . resolution_w = 0 : scale by 2**0 = 1, so no scaling and the value is treated as an integer -- . resolution_w < 0 : scale up -- . resolution_w > 0 : scale down - RETURN v_real * 2.0**REAL(-1 * resolution_w); + RETURN TO_SREAL(svec) / 2.0**REAL(resolution_w); END; @@ -1931,7 +2033,10 @@ PACKAGE BODY common_pkg IS FUNCTION NEGATE_SVEC(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS BEGIN -- use NUMERIC_STD to avoid range limitation of 32b INTEGER + -- default approach RETURN STD_LOGIC_VECTOR(-SIGNED(vec)); -- negate by multiplying by -1 + -- alternative equivalent approach + -- RETURN INCR_UVEC(NOT vec, 1); -- negate by using two complement negate END; -- Negate vec, but avoid overflow by forcing -min to +max. Use w <= vec'LENGTH. diff --git a/libraries/base/common/tb/vhdl/tb_common_to_sreal.vhd b/libraries/base/common/tb/vhdl/tb_common_to_sreal.vhd new file mode 100644 index 0000000000000000000000000000000000000000..8cd012da5fd31e5886a77e4d6079e9de9ae1391c --- /dev/null +++ b/libraries/base/common/tb/vhdl/tb_common_to_sreal.vhd @@ -0,0 +1,159 @@ +-- -------------------------------------------------------------------------- +-- Copyright 2021 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- -------------------------------------------------------------------------- +-- +-- Author: E. Kooistra, 13 okt 2021 +-- Purpose: Verify to_sreal() and to_svec() from common_pkg.vhd +-- Description: +-- The tb shows how a REAL value is represented by a fixed point SLV. The +-- signed REAL value is denoted as s(w, p) as defined and explained in []: +-- +-- s = sign bit, value +1 or -1 +-- w = width in number of bits of the SLV +-- p = position of the fixed point in the SLV, p = 0 for integers, p > 0 +-- for p bit fraction, p < 0 for scale factor 2**p +-- +-- The resolution of the REAL value is r = 1/2**p. +-- +-- . to_svec() converts a fixed point INTEGER or SLV into a REAL value +-- . to_sreal() converts a REAL value into a fixed point SLV or INTEGER +-- +-- The tb verifies that a_slv(w-1:0) = to_svec(to_sreal(a_slv(w-1:0))). +-- +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L3+SDP+Decision%3A+Definition+of+fixed+point+numbers +-- +-- Usage: +-- > as 5, observe signals with radix decimal +-- > run -all +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.MATH_REAL.ALL; +USE work.common_pkg.ALL; + + +ENTITY tb_common_to_sreal IS +END tb_common_to_sreal; + +ARCHITECTURE tb OF tb_common_to_sreal IS + + CONSTANT clk_period : TIME := 10 ns; + + CONSTANT c_resolution_w : NATURAL := 5; + CONSTANT c_width : NATURAL := 4; + CONSTANT c_min : INTEGER := -2**(c_width-1); + CONSTANT c_max : INTEGER := 2**(c_width-1)-1; + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL rst : STD_LOGIC := '1'; + + SIGNAL a_real : REAL := 0.0; + SIGNAL a_sint : INTEGER; + SIGNAL a_slv : STD_LOGIC_VECTOR(c_width-1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL dbg_resolution_w : INTEGER := 0; + SIGNAL dbg_resolution : REAL := 0.0; + + PROCEDURE proc_wait_some_cycles(SIGNAL clk : IN STD_LOGIC; + c_nof_cycles : IN NATURAL) IS + BEGIN + FOR I IN 0 TO c_nof_cycles-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP; + END proc_wait_some_cycles; + +BEGIN + + -- Stimuli + clk <= NOT clk OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER 3*clk_period; + + -- Testbench end + p_tb : PROCESS + VARIABLE v_slv : STD_LOGIC_VECTOR(c_width-1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE v_real : REAL; + BEGIN + -- Simulator evaluates process until first WAIT at startup 0 ps, but + -- simulator does not recognise WAIT in proc_wait_some_cycles() then. + -- Therefore add WAIT here to avoid ASSERT messages that occur later. + WAIT UNTIL rising_edge(clk); + proc_wait_some_cycles(clk, 10); + + -- Try all v_slv for c_width and resolutions beyond c_width + FOR R IN -c_resolution_w TO c_resolution_w LOOP + dbg_resolution_w <= R; + dbg_resolution <= 1.0 / 2.0**REAL(R); + FOR I IN c_min TO c_max LOOP + v_slv := TO_SVEC(I, c_width); + -- Convert fixed point v_slv with binary point at resolution width R, to real and back to slv + v_real := TO_SREAL(v_slv, R); + -- Show as signals in Wave window + a_real <= v_real; + a_sint <= TO_SINT(v_real, c_width, R); + a_slv <= TO_SVEC(v_real, c_width, R); + WAIT UNTIL rising_edge(clk); + -- Verify + ASSERT a_sint = I REPORT "Wrong REAL to INTEGER conversion for I = " & INTEGER'IMAGE(I) SEVERITY ERROR; + ASSERT a_slv = v_slv REPORT "Wrong REAL to SLV conversion for I = " & INTEGER'IMAGE(I) SEVERITY ERROR; + END LOOP; + proc_wait_some_cycles(clk, 10); + END LOOP; + + proc_wait_some_cycles(clk, 10); + + -- Try overflow + -- . No overflow with 4 bit integers for -16.49 : +15.49 + v_real := -9.51; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -9.49; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -8.51; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -8.49; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -7.51; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -7.49; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -6.51; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -6.49; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 6.49; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 6.51; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 7.49; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 7.51; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + proc_wait_some_cycles(clk, 5); + + -- . Just overflow with 4 bit integers for -16.5 : +15.5 + v_real := -15.5; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 15.5; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + proc_wait_some_cycles(clk, 5); + + -- . Large overflow with 4 bit integers for << -16.5 : >> +15.5 + v_real := -18.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 18.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -28.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 28.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -38.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 38.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -48.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 48.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -58.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 58.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := -68.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + v_real := 68.0; a_real <= v_real; a_sint <= TO_SINT(v_real, 4, 0); a_slv <= TO_SVEC(v_real, 4, 0); WAIT UNTIL rising_edge(clk); + + proc_wait_some_cycles(clk, 10); + tb_end <= '1'; + WAIT; + END PROCESS; + + -- TO_SINT() and TO_SVEC() must always yield same result + ASSERT a_sint = TO_SINT(a_slv) REPORT "Unexpected difference between TO_SINT() and TO_SVEC() :" & INTEGER'IMAGE(a_sint) & " /= " & INTEGER'IMAGE(TO_SINT(a_slv)); + +END tb;