Skip to content
Snippets Groups Projects
Select Git revision
  • 28ef1a8284f83de446b59fede804f934894773fe
  • master default protected
  • L2SDP-LIFT
  • L2SDP-1113
  • HPR-158
5 results

tb_resize.vhd

Blame
  • 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;