Select Git revision
tb_resize.vhd
-
Eric Kooistra authoredEric Kooistra authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
tb_resize.vhd 10.55 KiB
-------------------------------------------------------------------------------
--
-- Copyright (C) 2009
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
-- Author: E. Kooistra 2009, updated in 2021
-- Purpose: Test bench for common_resize.vhd and for RESIZE_NUM() from
-- common_pkg.vhd
-- Usage:
-- > do wave_resize.do
-- or use:
-- > as 5
-- and manually set the signed data output signals to radix decimal
-- > run -a
-- . Verify clipping using g_clip=TRUE and g_clip_symmetric=TRUE or FALSE
-- . Verify wrapping using g_clip=FALSE
-- . Observe reg_dat with respect to out_sdat, out_sovr for signed
-- . Observe reg_dat with respect to out_udat, out_uovr for unsigned
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE work.common_pkg.ALL;
ENTITY tb_resize IS
GENERIC (
-- Supported for RESIZE_NUM() and common_resize.vhd
g_in_dat_w : NATURAL := 5;
g_out_dat_w : NATURAL := 3;
-- Only supported for common_resize.vhd
g_clip : BOOLEAN := TRUE;
g_clip_symmetric : BOOLEAN := TRUE
);
END tb_resize;
ARCHITECTURE tb OF tb_resize IS
CONSTANT clk_period : TIME := 10 ns;
CONSTANT c_pipeline_input : NATURAL := 0;
CONSTANT c_pipeline_output : NATURAL := 1;
CONSTANT c_pipeline : NATURAL := c_pipeline_input + c_pipeline_output;
-- Test data
SIGNAL in_val : STD_LOGIC;
SIGNAL in_dat : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
SIGNAL reg_val : STD_LOGIC;
SIGNAL reg_dat : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
-- Signed output data, view as radix decimal in Wave window
SIGNAL reg_sdat : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
SIGNAL lowrange_sdat : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); -- keep LSbits or sign extend
SIGNAL resize_num_sdat : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); -- using RESIZE_NUM() from common_pkg.vhd
SIGNAL resize_sdat : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); -- using RESIZE() from IEEE.NUMERIC_STD
SIGNAL out_sdat : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); -- using common_resize.vhd
SIGNAL out_sovr : STD_LOGIC; -- overflow for out_sdat
-- Unsigned output data, view as radix unsigned in Wave window
SIGNAL reg_udat : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
SIGNAL lowrange_udat : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); -- keep LSbits
SIGNAL resize_num_udat : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); -- using RESIZE_NUM() from common_pkg.vhd
SIGNAL resize_udat : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); -- using RESIZE() from IEEE.NUMERIC_STD
SIGNAL out_udat : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); -- using common_resize.vhd
SIGNAL out_uovr : STD_LOGIC; -- overflow for out_udat
SIGNAL tb_end : STD_LOGIC := '0';
SIGNAL clk : STD_LOGIC := '1';
SIGNAL rst : STD_LOGIC;
CONSTANT c_init : STD_LOGIC_VECTOR(in_dat'RANGE) := (OTHERS=>'0');
CONSTANT g_clip_umax : NATURAL := 2**g_out_dat_w - 1;
CONSTANT g_clip_smax : NATURAL := 2**(g_out_dat_w - 1) - 1;
CONSTANT g_clip_smin : INTEGER := -2**(g_out_dat_w - 1);
BEGIN
-- Stimuli
clk <= NOT clk OR tb_end AFTER clk_period/2;
rst <= '1', '0' AFTER 3*clk_period;
-- Testbench end
p_tb_end : PROCESS
VARIABLE v_dat : STD_LOGIC_VECTOR(in_dat'RANGE);
BEGIN
tb_end <= '0';
WAIT UNTIL in_val='1';
WAIT UNTIL rising_edge(clk);
v_dat := in_dat; -- keep first in_dat
WAIT UNTIL rising_edge(clk);
WAIT UNTIL v_dat=in_dat; -- wait until all incrementing in_dat values have been applied at least once
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
WAIT UNTIL rising_edge(clk);
tb_end <= '1';
WAIT;
END PROCESS;
p_clk : PROCESS (rst, clk)
BEGIN
IF rst='1' THEN
in_val <= '0';
in_dat <= c_init;
ELSIF rising_edge(clk) THEN
in_val <= '1';
in_dat <= STD_LOGIC_VECTOR(SIGNED(in_dat)+1);
END IF;
END PROCESS;
-- Delay input as much as DUT output, assume c_pipeline = 1
reg_val <= in_val WHEN rising_edge(clk);
reg_dat <= in_dat WHEN rising_edge(clk);
reg_sdat <= reg_dat;
reg_udat <= reg_dat;
gen_extend_lowrange : IF g_out_dat_w >= g_in_dat_w GENERATE
p_extend_lowrange : PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
-- Extend MSbits for "SIGNED" and "UNSIGNED"
lowrange_sdat <= (OTHERS => in_dat(g_in_dat_w-1)); -- Extend MSbit for "SIGNED"
lowrange_udat <= (OTHERS => '0'); -- Extend '0' for "UNSIGNED"
lowrange_sdat(g_in_dat_w-1 DOWNTO 0) <= in_dat;
lowrange_udat(g_in_dat_w-1 DOWNTO 0) <= in_dat;
END IF;
END PROCESS;
END GENERATE;
gen_reduce_lowrange : IF g_out_dat_w < g_in_dat_w GENERATE
p_reduce_lowrange : PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
-- Remove MSbits for "SIGNED" and "UNSIGNED"
lowrange_sdat <= in_dat(g_out_dat_w-1 DOWNTO 0);
lowrange_udat <= in_dat(g_out_dat_w-1 DOWNTO 0);
END IF;
END PROCESS;
END GENERATE;
-- IEEE RESIZE() for "SIGNED" and "UNSIGNED"
resize_sdat <= STD_LOGIC_VECTOR(RESIZE( SIGNED(in_dat), g_out_dat_w)) WHEN rising_edge(clk);
resize_udat <= STD_LOGIC_VECTOR(RESIZE(UNSIGNED(in_dat), g_out_dat_w)) WHEN rising_edge(clk);
-- RESIZE_NUM() from common_pkg.vhd for "SIGNED" and "UNSIGNED"
resize_num_sdat <= STD_LOGIC_VECTOR(RESIZE_NUM( SIGNED(in_dat), g_out_dat_w)) WHEN rising_edge(clk);
resize_num_udat <= STD_LOGIC_VECTOR(RESIZE_NUM(UNSIGNED(in_dat), g_out_dat_w)) WHEN rising_edge(clk);
-- DUT for "SIGNED"
u_s_resize : ENTITY work.common_resize
GENERIC MAP (
g_representation => "SIGNED",
g_clip => g_clip,
g_clip_symmetric => g_clip_symmetric,
g_pipeline_input => c_pipeline_input,
g_pipeline_output => c_pipeline_output,
g_in_dat_w => g_in_dat_w,
g_out_dat_w => g_out_dat_w
)
PORT MAP (
clk => clk,
in_dat => in_dat,
out_dat => out_sdat,
out_ovr => out_sovr
);
-- DUT for "UNSIGNED"
u_u_resize : ENTITY work.common_resize
GENERIC MAP (
g_representation => "UNSIGNED",
g_clip => g_clip,
g_clip_symmetric => g_clip_symmetric,
g_pipeline_input => c_pipeline_input,
g_pipeline_output => c_pipeline_output,
g_in_dat_w => g_in_dat_w,
g_out_dat_w => g_out_dat_w
)
PORT MAP (
clk => clk,
in_dat => in_dat,
out_dat => out_udat,
out_ovr => out_uovr
);
-- Verification
p_verify : PROCESS
BEGIN
WAIT UNTIL rising_edge(clk);
IF reg_val = '1' THEN
IF g_in_dat_w<=g_out_dat_w THEN
-- For extended width expected value is same as input value
ASSERT SIGNED( lowrange_sdat) = SIGNED(reg_dat) REPORT "Wrong extended lowrange_sdat" SEVERITY ERROR;
ASSERT UNSIGNED( lowrange_udat) = UNSIGNED(reg_dat) REPORT "Wrong extended lowrange_udat" SEVERITY ERROR;
ASSERT SIGNED( resize_sdat) = SIGNED(reg_dat) REPORT "Wrong extended resize_sdat" SEVERITY ERROR;
ASSERT UNSIGNED( resize_udat) = UNSIGNED(reg_dat) REPORT "Wrong extended resize_udat" SEVERITY ERROR;
ASSERT SIGNED(resize_num_sdat) = SIGNED(reg_dat) REPORT "Wrong extended resize_num_sdat" SEVERITY ERROR;
ASSERT UNSIGNED(resize_num_udat) = UNSIGNED(reg_dat) REPORT "Wrong extended resize_num_udat" SEVERITY ERROR;
ASSERT SIGNED( out_sdat) = SIGNED(reg_dat) REPORT "Wrong extended out_sdat" SEVERITY ERROR;
ASSERT UNSIGNED( out_udat) = UNSIGNED(reg_dat) REPORT "Wrong extended out_udat" SEVERITY ERROR;
ELSE
-- For reduced width compare unsigned with lowrange
ASSERT UNSIGNED( resize_udat) = UNSIGNED(lowrange_udat) REPORT "Wrong wrapped resize_udat" SEVERITY ERROR;
ASSERT UNSIGNED(resize_num_udat) = UNSIGNED(lowrange_udat) REPORT "Wrong wrapped resize_num_udat" SEVERITY ERROR;
ASSERT UNSIGNED( out_udat) = UNSIGNED(lowrange_udat) OR
UNSIGNED( out_udat) = g_clip_umax REPORT "Wrong clipped out_udat" SEVERITY ERROR;
-- For reduced width compare signed with lowrange
-- . no need to verify RESIZE(), because it is part of IEEE.NUMERIC_STD
-- . verify RESIZE_NUM() below for all g_out_dat_w
-- . verify common_resize here
IF g_clip THEN
IF g_clip_symmetric THEN
ASSERT (SIGNED(out_sdat) = SIGNED(lowrange_sdat) OR SIGNED(out_sdat) = -g_clip_smax OR SIGNED(out_sdat) = g_clip_smax) AND
SIGNED(out_sdat) /= g_clip_smin AND
SIGNED(out_sdat) /= -g_clip_smin REPORT "Wrong clipped symmetrical out_sdat" SEVERITY ERROR;
ELSE
ASSERT (SIGNED(out_sdat) = SIGNED(lowrange_sdat) OR SIGNED(out_sdat) = g_clip_smin OR SIGNED(out_sdat) = g_clip_smax)
REPORT "Wrong clipped out_sdat" SEVERITY ERROR;
END IF;
ELSE
ASSERT SIGNED(out_sdat) = SIGNED(lowrange_sdat) REPORT "Wrong wrapped out_sdat" SEVERITY ERROR;
END IF;
END IF;
-- RESIZE_NUM() in common_pkg.vhd is always equivalent to lowrange
ASSERT SIGNED(resize_num_sdat) = SIGNED(lowrange_sdat) REPORT "Wrong resize_num_sdat /= lowrange_sdat" SEVERITY ERROR;
ASSERT UNSIGNED(resize_num_udat) = UNSIGNED(lowrange_udat) REPORT "Wrong resize_num_udat /= lowrange_udat" SEVERITY ERROR;
END IF;
END PROCESS;
END tb;