OpenCores
URL https://opencores.org/ocsvn/astron_multiplier/astron_multiplier/trunk

Subversion Repositories astron_multiplier

[/] [astron_multiplier/] [trunk/] [tb_common_mult.vhd] - Rev 5

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
--
-- 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/>.
--
-------------------------------------------------------------------------------
 
-- Purpose: Tb for common_mult architectures
-- Description:
--   The tb is self verifying.
-- Usage:
--   > as 10
--   > run -all
 
LIBRARY IEEE, common_pkg_lib, common_components_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
--USE technology_lib.technology_select_pkg.ALL;
USE common_pkg_lib.common_pkg.ALL;
USE common_pkg_lib.tb_common_pkg.ALL;
 
 
ENTITY tb_common_mult IS
  GENERIC (
    g_in_dat_w         : NATURAL := 7;
    g_out_dat_w        : NATURAL := 11;  -- = 2*g_in_dat_w, or smaller to truncate MSbits, or larger to extend MSbits
    g_nof_mult         : NATURAL := 2;
    g_pipeline_input   : NATURAL := 1;
    g_pipeline_product : NATURAL := 1;
    g_pipeline_output  : NATURAL := 1
  );
END tb_common_mult;
 
ARCHITECTURE tb OF tb_common_mult IS
 
  CONSTANT clk_period    : TIME := 10 ns;
  CONSTANT c_pipeline    : NATURAL := g_pipeline_input + g_pipeline_product + g_pipeline_output;
  CONSTANT c_nof_mult    : NATURAL := 2;  -- fixed
 
  CONSTANT c_max_p       : INTEGER :=  2**(g_in_dat_w-1)-1;
  CONSTANT c_min         : INTEGER := -c_max_p;
  CONSTANT c_max_n       : INTEGER := -2**(g_in_dat_w-1);
 
  CONSTANT c_technology  : NATURAL := 0;
 
  FUNCTION func_sresult(in_a, in_b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
    CONSTANT c_res_w  : NATURAL := 2*g_in_dat_w;  -- use sufficiently large result width
    VARIABLE v_a      : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
    VARIABLE v_b      : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
    VARIABLE v_result : SIGNED(c_res_w-1 DOWNTO 0);
  BEGIN
    -- Calculate expected result
    v_a      := RESIZE_SVEC(in_a, g_in_dat_w);
    v_b      := RESIZE_SVEC(in_b, g_in_dat_w);
    v_result := RESIZE_NUM(SIGNED(v_a)*SIGNED(v_b), c_res_w);
    RETURN RESIZE_SVEC(STD_LOGIC_VECTOR(v_result), g_out_dat_w);  -- Truncate MSbits or sign extend MSBits
  END;
 
  FUNCTION func_uresult(in_a, in_b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
    CONSTANT c_res_w  : NATURAL := 2*g_in_dat_w;  -- use sufficiently large result width
    VARIABLE v_a      : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
    VARIABLE v_b      : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
    VARIABLE v_result : UNSIGNED(c_res_w-1 DOWNTO 0);
  BEGIN
    -- Calculate expected result
    v_a      := RESIZE_UVEC(in_a, g_in_dat_w);
    v_b      := RESIZE_UVEC(in_b, g_in_dat_w);
    v_result := RESIZE_NUM(UNSIGNED(v_a)*UNSIGNED(v_b), c_res_w);
    RETURN RESIZE_UVEC(STD_LOGIC_VECTOR(v_result), g_out_dat_w);  -- Truncate MSbits or zero extend MSBits
  END;
 
  SIGNAL rst                  : STD_LOGIC;
  SIGNAL clk                  : STD_LOGIC := '0';
  SIGNAL tb_end               : STD_LOGIC := '0';
 
  -- Input signals
  SIGNAL in_a                 : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
  SIGNAL in_b                 : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
  SIGNAL in_a_p               : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
  SIGNAL in_b_p               : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
 
  -- Product signals
  SIGNAL sresult_expected     : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);  -- pipelined expected result
  SIGNAL sresult_rtl          : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
  SIGNAL sresult_ip           : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
  SIGNAL uresult_expected     : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);  -- pipelined expected result
  SIGNAL uresult_rtl          : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
  SIGNAL uresult_ip           : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
 
  -- auxiliary signals
  SIGNAL in_a_arr             : STD_LOGIC_VECTOR(g_nof_mult*g_in_dat_w-1 DOWNTO 0);
  SIGNAL in_b_arr             : STD_LOGIC_VECTOR(g_nof_mult*g_in_dat_w-1 DOWNTO 0);
  SIGNAL out_sresult          : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);  -- combinatorial expected result
  SIGNAL out_uresult          : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);  -- combinatorial expected result
  SIGNAL sresult_arr_expected : STD_LOGIC_VECTOR(g_nof_mult*g_out_dat_w-1 DOWNTO 0);
  SIGNAL uresult_arr_expected : STD_LOGIC_VECTOR(g_nof_mult*g_out_dat_w-1 DOWNTO 0);
  SIGNAL sresult_arr_rtl      : STD_LOGIC_VECTOR(g_nof_mult*g_out_dat_w-1 DOWNTO 0);
  SIGNAL uresult_arr_rtl      : STD_LOGIC_VECTOR(g_nof_mult*g_out_dat_w-1 DOWNTO 0);
  SIGNAL sresult_arr_ip       : STD_LOGIC_VECTOR(g_nof_mult*g_out_dat_w-1 DOWNTO 0);
  SIGNAL uresult_arr_ip       : STD_LOGIC_VECTOR(g_nof_mult*g_out_dat_w-1 DOWNTO 0);
 
BEGIN
 
  clk  <= NOT clk OR tb_end AFTER clk_period/2;
 
  -- run 1 us
  p_in_stimuli : PROCESS
  BEGIN
    rst <= '1';
    in_a <= TO_SVEC(0, g_in_dat_w);
    in_b <= TO_SVEC(0, g_in_dat_w);
    proc_common_wait_some_cycles(clk, 10);
    rst <= '0';
    proc_common_wait_some_cycles(clk, 10);
 
    -- Some special combinations
    in_a <= TO_SVEC(2, g_in_dat_w);
    in_b <= TO_SVEC(3, g_in_dat_w);
    WAIT UNTIL rising_edge(clk);
    in_a <= TO_SVEC(c_max_p, g_in_dat_w);  -- p*p = pp
    in_b <= TO_SVEC(c_max_p, g_in_dat_w);
    WAIT UNTIL rising_edge(clk);
    in_a <= TO_SVEC(c_max_n, g_in_dat_w);  -- -p*-p = pp
    in_b <= TO_SVEC(c_max_n, g_in_dat_w);
    WAIT UNTIL rising_edge(clk);
    in_a <= TO_SVEC(c_max_p, g_in_dat_w);  -- p*-p =  = -pp
    in_b <= TO_SVEC(c_max_n, g_in_dat_w);
    WAIT UNTIL rising_edge(clk);
    in_a <= TO_SVEC(c_max_p, g_in_dat_w);  -- p*(-p-1) = -pp - p
    in_b <= TO_SVEC(c_min, g_in_dat_w);
    WAIT UNTIL rising_edge(clk);
    in_a <= TO_SVEC(c_max_n, g_in_dat_w);  -- -p*(-p-1) = pp + p
    in_b <= TO_SVEC(c_min, g_in_dat_w);
    WAIT UNTIL rising_edge(clk);
 
    proc_common_wait_some_cycles(clk, 50);
 
    -- All combinations
    FOR I IN -2**(g_in_dat_w-1) TO 2**(g_in_dat_w-1)-1 LOOP
      FOR J IN -2**(g_in_dat_w-1) TO 2**(g_in_dat_w-1)-1 LOOP
        in_a <= TO_SVEC(I, g_in_dat_w);
        in_b <= TO_SVEC(J, g_in_dat_w);
        WAIT UNTIL rising_edge(clk);
      END LOOP;
    END LOOP;
 
    proc_common_wait_some_cycles(clk, 50);
    tb_end <= '1';
    WAIT;
  END PROCESS;
 
  -- pipeline inputs to ease comparison in the Wave window
  u_in_a_pipeline : ENTITY common_components_lib.common_pipeline
  GENERIC MAP (
    g_representation => "SIGNED",
    g_pipeline       => c_pipeline,
    g_reset_value    => 0,
    g_in_dat_w       => g_in_dat_w,
    g_out_dat_w      => g_in_dat_w
  )
  PORT MAP (
    rst     => rst,
    clk     => clk,
    clken   => '1',
    in_dat  => in_a,
    out_dat => in_a_p
  );
 
  u_in_b_pipeline : ENTITY common_components_lib.common_pipeline
  GENERIC MAP (
    g_representation => "SIGNED",
    g_pipeline       => c_pipeline,
    g_reset_value    => 0,
    g_in_dat_w       => g_in_dat_w,
    g_out_dat_w      => g_in_dat_w
  )
  PORT MAP (
    rst     => rst,
    clk     => clk,
    clken   => '1',
    in_dat  => in_b,
    out_dat => in_b_p
  );
 
  gen_wires : FOR I IN 0 TO g_nof_mult-1 GENERATE
    -- use same input for all multipliers
    in_a_arr((I+1)*g_in_dat_w-1 DOWNTO I*g_in_dat_w) <= in_a;
    in_b_arr((I+1)*g_in_dat_w-1 DOWNTO I*g_in_dat_w) <= in_b;
    -- calculate expected output only for one multiplier
    out_sresult <= func_sresult(in_a, in_b);
    out_uresult <= func_uresult(in_a, in_b);
    -- copy the expected result for all multipliers
    sresult_arr_expected((I+1)*g_out_dat_w-1 DOWNTO I*g_out_dat_w) <= sresult_expected;
    uresult_arr_expected((I+1)*g_out_dat_w-1 DOWNTO I*g_out_dat_w) <= uresult_expected;
  END GENERATE;
 
  -- use mult(0) to observe result in Wave window
  sresult_rtl <= sresult_arr_rtl(g_out_dat_w-1 DOWNTO 0);
  uresult_rtl <= uresult_arr_rtl(g_out_dat_w-1 DOWNTO 0);
  sresult_ip  <= sresult_arr_ip(g_out_dat_w-1 DOWNTO 0);
  uresult_ip  <= uresult_arr_ip(g_out_dat_w-1 DOWNTO 0);
 
  u_sresult : ENTITY common_components_lib.common_pipeline
  GENERIC MAP (
    g_representation => "SIGNED",
    g_pipeline       => c_pipeline,
    g_reset_value    => 0,
    g_in_dat_w       => g_out_dat_w,
    g_out_dat_w      => g_out_dat_w
  )
  PORT MAP (
    rst     => rst,
    clk     => clk,
    clken   => '1',
    in_dat  => out_sresult,
    out_dat => sresult_expected
  );
 
  u_uresult : ENTITY common_components_lib.common_pipeline
  GENERIC MAP (
    g_representation => "UNSIGNED",
    g_pipeline       => c_pipeline,
    g_reset_value    => 0,
    g_in_dat_w       => g_out_dat_w,
    g_out_dat_w      => g_out_dat_w
  )
  PORT MAP (
    rst     => rst,
    clk     => clk,
    clken   => '1',
    in_dat  => out_uresult,
    out_dat => uresult_expected
  );
 
  u_sdut_rtl : ENTITY work.common_mult
  GENERIC MAP (
    g_technology       => c_technology,
    g_variant          => "RTL",
    g_in_a_w           => g_in_dat_w,
    g_in_b_w           => g_in_dat_w,
    g_out_p_w          => g_out_dat_w,
    g_nof_mult         => g_nof_mult,
    g_pipeline_input   => g_pipeline_input,
    g_pipeline_product => g_pipeline_product,
    g_pipeline_output  => g_pipeline_output,
    g_representation   => "SIGNED"
  )
  PORT MAP (
    rst     => '0',
    clk     => clk,
    clken   => '1',
    in_a    => in_a_arr,
    in_b    => in_b_arr,
    out_p   => sresult_arr_rtl
  );
 
  u_udut_rtl : ENTITY work.common_mult
  GENERIC MAP (
    g_technology       => c_technology,
    g_variant          => "RTL",
    g_in_a_w           => g_in_dat_w,
    g_in_b_w           => g_in_dat_w,
    g_out_p_w          => g_out_dat_w,
    g_nof_mult         => g_nof_mult,
    g_pipeline_input   => g_pipeline_input,
    g_pipeline_product => g_pipeline_product,
    g_pipeline_output  => g_pipeline_output,
    g_representation   => "UNSIGNED"
  )
  PORT MAP (
    rst     => '0',
    clk     => clk,
    clken   => '1',
    in_a    => in_a_arr,
    in_b    => in_b_arr,
    out_p   => uresult_arr_rtl
  );
 
  u_sdut_ip : ENTITY work.common_mult
  GENERIC MAP (
    g_technology       => c_technology,
    g_variant          => "IP",
    g_in_a_w           => g_in_dat_w,
    g_in_b_w           => g_in_dat_w,
    g_out_p_w          => g_out_dat_w,
    g_nof_mult         => g_nof_mult,
    g_pipeline_input   => g_pipeline_input,
    g_pipeline_product => g_pipeline_product,
    g_pipeline_output  => g_pipeline_output,
    g_representation   => "SIGNED"
  )
  PORT MAP (
    rst     => '0',
    clk     => clk,
    clken   => '1',
    in_a    => in_a_arr,
    in_b    => in_b_arr,
    out_p   => sresult_arr_ip
  );
 
  u_udut_ip : ENTITY work.common_mult
  GENERIC MAP (
    g_technology       => c_technology,
    g_variant          => "IP",
    g_in_a_w           => g_in_dat_w,
    g_in_b_w           => g_in_dat_w,
    g_out_p_w          => g_out_dat_w,
    g_nof_mult         => g_nof_mult,
    g_pipeline_input   => g_pipeline_input,
    g_pipeline_product => g_pipeline_product,
    g_pipeline_output  => g_pipeline_output,
    g_representation   => "UNSIGNED"
  )
  PORT MAP (
    rst     => '0',
    clk     => clk,
    clken   => '1',
    in_a    => in_a_arr,
    in_b    => in_b_arr,
    out_p   => uresult_arr_ip
  );
 
  p_verify : PROCESS(rst, clk)
  BEGIN
    IF rst='0' THEN
      IF rising_edge(clk) THEN
        -- verify all multipliers in parallel
        ASSERT sresult_arr_rtl = sresult_arr_expected REPORT "Error: wrong Signed RTL result" SEVERITY ERROR;
        ASSERT uresult_arr_rtl = uresult_arr_expected REPORT "Error: wrong Unsigned RTL result" SEVERITY ERROR;
        ASSERT sresult_arr_ip  = sresult_arr_expected REPORT "Error: wrong Signed IP result" SEVERITY ERROR;
        ASSERT uresult_arr_ip  = uresult_arr_expected REPORT "Error: wrong Unsigned IP result" SEVERITY ERROR;
      END IF;
    END IF;
  END PROCESS;
 
END tb;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.