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

Subversion Repositories viirf

[/] [viirf/] [trunk/] [src/] [sos_cascaded_top_tb.vhd] - Rev 2

Compare with Previous | Blame | View Log

--------------------------------------------------------------------------------------------------------------
-- MIT License
--  
-- Copyright (c) 2017 Mario Mauerer
--  
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
-- 
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
-- 
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
-----------------------------------------------------------------------------
--
-- VIIRF - Versatile IIR Filter
--
-- Testbench for sos_cascaded_top.vhd
--
-- This testbench tests the top-level filter unit.
--
-- Note: The text-files used to configure, feed and compare the filter might
-- require an absolute path or a proper relative path to the simulator in their
-- declaration below.
--
-- First, it configures the filter via the coefficient data interface.
-- To achieve this, 7 text-files have to be provided:
--      CoeffStimuli_b0.txt"; ==> One new line for each section's b0-coeff.
--      CoeffStimuli_b1.txt"; ==> One new line for each section's b1-coeff.
--      CoeffStimuli_b2.txt"; ==> One new line for each section's b2-coeff.
--      CoeffStimuli_a1.txt"; ==> One new line for each section's a1-coeff.
--      CoeffStimuli_a2.txt"; ==> One new line for each section's a2-coeff.
--      CoeffStimuli_g.txt"; ==> One new line for each section's g-coeff.
--      CoeffStimuli_finalgain.txt"; ==> Contains only one number, the final gain.
--
-- NOTE: These files have also be provided and filled with data even if the SOS
-- or final filter gains are disabled! The testbench reads them nonetheless.
-- The python-configuration scripts takes this into account and fills the files
-- with zeros, if the coefficients are not required.
--
-- After configuring the filter, the testbench reads input data from the file
-- InputDat_Stimuli.txt". Each new line is a new input value.
--
-- The testbench compares the filter output to values store in the file
-- OutputDat_GoldenReference.txt". Upon mismatch, an error is raised.
 
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
library unisim;
use unisim.vcomponents.all;
use std.textio.all;
-------------------------------------------------------------------------------
 
entity sos_cascaded_top_tb is
end entity sos_cascaded_top_tb;
 
-------------------------------------------------------------------------------
 
architecture arch_tb of sos_cascaded_top_tb is
 
  -- This is the period with which new filter data gets strobed into the
  -- filter. 
  constant T_FILT_UPDATE : time := 200 ns;
 
  -- Component generics
  constant NUM_SEC           : integer := 27;
  constant W_DAT_INPUT       : integer := 16;
  constant GAIN_INPUT        : integer := 4;
  constant W_SECT_DAT        : integer := 23;
  constant W_COEF            : integer := 18;
  constant W_FRAC            : integer := 16;
  constant SOSGAIN_EN        : boolean := false;
  constant FINALGAIN_EN      : boolean := true;
  constant W_DAT_OUTPUT      : integer := 32;
  constant W_DAT_INTF        : integer := 32;
  constant USE_PIPELINE_CORE : boolean := true;
 
  -- Component ports
  signal ClkxCI        : std_logic := '0';
  signal RstxRI        : std_logic;
  signal DatxDI        : signed(W_DAT_INPUT-1 downto 0);
  signal StrbxSI       : std_logic;
  signal DatxDO        : signed(W_DAT_OUTPUT-1 downto 0);
  signal StrbxSO       : std_logic;
  signal SectAddrxDI   : std_logic_vector(W_DAT_INTF-1 downto 0);
  signal CoeffAddrxDI  : std_logic_vector(W_DAT_INTF-1 downto 0);
  signal CoeffDatxDI   : std_logic_vector(W_DAT_INTF-1 downto 0);
  signal CoeffValidxSI : std_logic;
 
  -- Testbench-Internal: This signals when the filter has been configured and
  -- is ready for input data.
  signal CoeffWriteDone : std_logic := '0';
 
begin  -- architecture arch_tb
 
  -- Component instantiation
  DUT : entity work.sos_cascaded_top
    generic map (
      NUM_SEC           => NUM_SEC,
      W_DAT_INPUT       => W_DAT_INPUT,
      GAIN_INPUT        => GAIN_INPUT,
      W_SECT_DAT        => W_SECT_DAT,
      W_COEF            => W_COEF,
      W_FRAC            => W_FRAC,
      SOSGAIN_EN        => SOSGAIN_EN,
      FINALGAIN_EN      => FINALGAIN_EN,
      W_DAT_OUTPUT      => W_DAT_OUTPUT,
      W_DAT_INTF        => W_DAT_INTF,
      USE_PIPELINE_CORE => USE_PIPELINE_CORE)
    port map (
      ClkxCI        => ClkxCI,
      RstxRI        => RstxRI,
      DatxDI        => DatxDI,
      StrbxSI       => StrbxSI,
      DatxDO        => DatxDO,
      StrbxSO       => StrbxSO,
      SectAddrxDI   => SectAddrxDI,
      CoeffAddrxDI  => CoeffAddrxDI,
      CoeffDatxDI   => CoeffDatxDI,
      CoeffValidxSI => CoeffValidxSI);
 
  -- Clock generation
  ClkxCI <= not ClkxCI after 5 ns;
 
  --------------------------------------------------------------
  -- Reset process: This simply releases the reset after 100 ns.
  --------------------------------------------------------------
  RstProc : process
  begin
    RstxRI <= '1';
    wait for 100 ns;
    wait until rising_edge(ClkxCI);
    RstxRI <= '0';
    wait;
  end process RstProc;
 
  --------------------------------------------------------------------------------------------------
  -- Before data can be applied, this writes the coefficients from files into the RAM of the filter:
  --------------------------------------------------------------------------------------------------
  CoeffWriteProc : process
    -- These files serve the filter coefficients. Each coefficients has a
    -- separate file and each section's coefficient is on a new line (except
    -- finalgain, there is only one number required as there is only one final
    -- filter gain)
    -- THESE PATHS MIGHT REQUIRED TO BE ABSOLUTE OR PROPERLY RELATIVE TO THE
    -- SIMULATOR'S PATH.
    file COEFFILE_B0        : text is in "/testbench_stimuli/CoeffStimuli_b0.txt";
    file COEFFILE_B1        : text is in "/testbench_stimuli/CoeffStimuli_b1.txt";
    file COEFFILE_B2        : text is in "/testbench_stimuli/CoeffStimuli_b2.txt";
    file COEFFILE_A1        : text is in "/testbench_stimuli/CoeffStimuli_a1.txt";
    file COEFFILE_A2        : text is in "/testbench_stimuli/CoeffStimuli_a2.txt";
    file COEFFILE_G         : text is in "/testbench_stimuli/CoeffStimuli_g.txt";
    file COEFFILE_FINALGAIN : text is in "/testbench_stimuli/CoeffStimuli_finalgain.txt";
 
    variable fileline    : line;
    variable filedata    : real;
    variable SectAddrxS  : integer range 0 to NUM_SEC;
    variable CoeffAddrxS : integer range 0 to 6;
  begin
    wait until rising_edge(ClkxCI);
    if RstxRI = '1' then
      SectAddrxDI    <= (others => '0');
      CoeffAddrxDI   <= (others => '0');
      CoeffDatxDI    <= (others => '0');
      CoeffValidxSI  <= '0';
      CoeffWriteDone <= '0';
    else
      wait for 100 ns;
      wait until rising_edge(ClkxCI);
 
      -- Write the coefficients for each section using the coefficient interface:
      -- Go through all sections:
      for I in 0 to NUM_SEC-1 loop
        SectAddrxS := I;
 
        -- For each section, go through all 6 SOS-coefficients:
        for K in 0 to 5 loop
          CoeffAddrxS := K;
 
          if CoeffAddrxS = 0 then
            if (not endfile(COEFFILE_B0)) then
              readline(COEFFILE_B0, fileline);
              read(fileline, filedata);
            else
              assert false report "Reached end of coefficient-file without having provided all sections with data. Enough lines in coefficient-file?" severity failure;
            end if;
          elsif CoeffAddrxS = 1 then
            if (not endfile(COEFFILE_B1)) then
              readline(COEFFILE_B1, fileline);
              read(fileline, filedata);
            else
              assert false report "Reached end of coefficient-file without having provided all sections with data. Enough lines in coefficient-file?" severity failure;
            end if;
          elsif CoeffAddrxS = 2 then
            if (not endfile(COEFFILE_B2)) then
              readline(COEFFILE_B2, fileline);
              read(fileline, filedata);
            else
              assert false report "Reached end of coefficient-file without having provided all sections with data. Enough lines in coefficient-file?" severity failure;
            end if;
          elsif CoeffAddrxS = 3 then
            if (not endfile(COEFFILE_A1)) then
              readline(COEFFILE_A1, fileline);
              read(fileline, filedata);
            else
              assert false report "Reached end of coefficient-file without having provided all sections with data. Enough lines in coefficient-file?" severity failure;
            end if;
          elsif CoeffAddrxS = 4 then
            if (not endfile(COEFFILE_A2)) then
              readline(COEFFILE_A2, fileline);
              read(fileline, filedata);
            else
              assert false report "Reached end of coefficient-file without having provided all sections with data. Enough lines in coefficient-file?" severity failure;
            end if;
          elsif CoeffAddrxS = 5 then
            if (not endfile(COEFFILE_G)) then
              readline(COEFFILE_G, fileline);
              read(fileline, filedata);
            else
              assert false report "Reached end of coefficient-file without having provided all sections with data. Enough lines in coefficient-file?" severity failure;
            end if;
          end if;
          wait until rising_edge(ClkxCI);
          SectAddrxDI   <= std_logic_vector(to_unsigned(SectAddrxS, W_DAT_INTF));
          CoeffAddrxDI  <= std_logic_vector(to_unsigned(CoeffAddrxS, W_DAT_INTF));
          CoeffDatxDI   <= std_logic_vector(to_signed(natural(filedata), W_DAT_INTF));
          CoeffValidxSI <= '1';
 
        end loop;
      end loop;
 
      -- The final output-gain is transmitted by selecting NUM_SECT as SectAddr
      -- and 6 as CoeffAddr:
      CoeffValidxSI <= '1';
      wait until rising_edge(ClkxCI);
      if (not endfile(COEFFILE_FINALGAIN)) then
        readline(COEFFILE_FINALGAIN, fileline);
        read(fileline, filedata);
      else
        assert false report "Reached end of coefficient-file without having provided all sections with data. Enough lines in coefficient-file?" severity failure;
      end if;
      SectAddrxDI   <= std_logic_vector(to_unsigned(NUM_SEC, W_DAT_INTF));
      CoeffAddrxDI  <= std_logic_vector(to_unsigned(6, W_DAT_INTF));
      CoeffDatxDI   <= std_logic_vector(to_signed(natural(filedata), W_DAT_INTF));
      CoeffValidxSI <= '1';
      wait until rising_edge(ClkxCI);
      CoeffValidxSI <= '0';
 
      --We are done writing the coefficients, hence we simply do nothing more
      --in this process. We signal this to other processes using the flag.
      CoeffWriteDone <= '1';
      wait;
    end if;
 
  end process CoeffWriteProc;
 
  -----------------------------------------------------------------------------
  -- This reads filter input data from a file and feeds it to the filter input:
  -----------------------------------------------------------------------------
  InputDataWrite : process
    -- This file stores the filter input:
    -- THIS PATH MIGHT REQUIRED TO BE ABSOLUTE OR PROPERLY RELATIVE TO THE
    -- SIMULATOR'S PATH.
    file INPUTSTIMULI_FILE : text is in "/testbench_stimuli/InputDat_Stimuli.txt";
    variable stimuliline   : line;
    variable stimulidata   : real;
  begin
    wait until rising_edge(ClkxCI);
    if RstxRI = '1' then
      DatxDI  <= (others => '0');
      StrbxSI <= '0';
    else
      -- If the filter coefficients have been written to the filter's RAM, we
      -- can start applying data:
      if CoeffWriteDone = '1' then
        while (not endfile(INPUTSTIMULI_FILE)) loop
          readline(INPUTSTIMULI_FILE, stimuliline);
          read(stimuliline, stimulidata);
          -- We apply data periodically:
          wait for T_FILT_UPDATE;
          wait until rising_edge(ClkxCI);
          StrbxSI <= '1';
          DatxDI  <= to_signed(natural(stimulidata), W_DAT_INPUT);
          wait until rising_edge(ClkxCI);
          StrbxSI <= '0';
        end loop;
        -- If we run out of filter input data, we halt the simulation:
        assert false report "Reached end of input-stimuli file." severity failure;
      end if;
    end if;
  end process InputDataWrite;
 
-------------------------------------------------------------------------------
  -- This reads the output of the filter and compares it to the golden reference
  -----------------------------------------------------------------------------
  OutputDataCompare : process
    -- This file stores the filter input:
    -- THIS PATH MIGHT REQUIRED TO BE ABSOLUTE OR PROPERLY RELATIVE TO THE
    -- SIMULATOR'S PATH.
    file REF_FILE    : text is in "/testbench_stimuli/OutputDat_GoldenReference.txt";
    variable refline : line;
    variable refdata : real;
  begin
    wait until rising_edge(ClkxCI);
 
    if W_DAT_OUTPUT > 32 then
      assert false report "Test-bench only supports output comparisons with bit-widths less than 33 bits!" severity failure;
    end if;
 
    -- The filter outputs new data:
    if StrbxSO = '1' then
      if endfile(REF_FILE) then
        assert false report "Reached end of golden-reference file." severity failure;
      else
        readline(REF_FILE, refline);
        read(refline, refdata);
        -- Check if the output is correct:
        if DatxDO /= to_signed(natural(refdata), W_DAT_OUTPUT) then
          assert false report "Filter did not produce the expected output." severity failure;
        end if;
      end if;
    end if;
  end process OutputDataCompare;
 
 
 
end architecture arch_tb;
 
-------------------------------------------------------------------------------
 
configuration sos_cascaded_top_tb_arch_tb_cfg of sos_cascaded_top_tb is
  for arch_tb
  end for;
end sos_cascaded_top_tb_arch_tb_cfg;
 
-------------------------------------------------------------------------------
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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