Advertisement
Guest User

Untitled

a guest
Jul 17th, 2019
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VHDL 24.96 KB | None | 0 0
  1. --------------------------------------------------------------------------------
  2. -- (c) Copyright 2010 - 2013 Xilinx, Inc. All rights reserved.
  3. --
  4. -- This file contains confidential and proprietary information
  5. -- of Xilinx, Inc. and is protected under U.S. and
  6. -- international copyright and other intellectual property
  7. -- laws.
  8. --
  9. -- DISCLAIMER
  10. -- This disclaimer is not a license and does not grant any
  11. -- rights to the materials distributed herewith. Except as
  12. -- otherwise provided in a valid license issued to you by
  13. -- Xilinx, and to the maximum extent permitted by applicable
  14. -- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
  15. -- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
  16. -- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
  17. -- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
  18. -- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
  19. -- (2) Xilinx shall not be liable (whether in contract or tort,
  20. -- including negligence, or under any other theory of
  21. -- liability) for any loss or damage of any kind or nature
  22. -- related to, arising under or in connection with these
  23. -- materials, including for any direct, or any indirect,
  24. -- special, incidental, or consequential loss or damage
  25. -- (including loss of data, profits, goodwill, or any type of
  26. -- loss or damage suffered as a result of any action brought
  27. -- by a third party) even if such damage or loss was
  28. -- reasonably foreseeable or Xilinx had been advised of the
  29. -- possibility of the same.
  30. --
  31. -- CRITICAL APPLICATIONS
  32. -- Xilinx products are not designed or intended to be fail-
  33. -- safe, or for use in any application requiring fail-safe
  34. -- performance, such as life-support or safety devices or
  35. -- systems, Class III medical devices, nuclear facilities,
  36. -- applications related to the deployment of airbags, or any
  37. -- other applications that could lead to death, personal
  38. -- injury, or severe property or environmental damage
  39. -- (individually and collectively, "Critical
  40. -- Applications"). Customer assumes the sole risk and
  41. -- liability of any use of Xilinx products in Critical
  42. -- Applications, subject only to applicable laws and
  43. -- regulations governing limitations on product liability.
  44. --
  45. -- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
  46. -- PART OF THIS FILE AT ALL TIMES.
  47. --------------------------------------------------------------------------------
  48. -- Description:
  49. -- This is an example testbench for the Fast Fourier Transform IP core.
  50. -- The testbench has been generated by Vivado to accompany the IP core
  51. -- instance you have generated.
  52. --
  53. -- This testbench is for demonstration purposes only.  See note below for
  54. -- instructions on how to use it with your core.
  55. --
  56. -- See the Fast Fourier Transform product guide for further information
  57. -- about this core.
  58. --
  59. --------------------------------------------------------------------------------
  60. -- Using this testbench
  61. --
  62. -- This testbench instantiates your generated Fast Fourier Transform core
  63. -- instance named "xfft_0".
  64. --
  65. -- Use Vivado's Run Simulation flow to run this testbench.  See the Vivado
  66. -- documentation for details.
  67. --------------------------------------------------------------------------------
  68.  
  69. library ieee;
  70. use ieee.std_logic_1164.all;
  71. use ieee.numeric_std.all;
  72. use ieee.math_real.all;
  73.  
  74. entity tb_xfft_0 is
  75. end tb_xfft_0;
  76.  
  77. architecture tb of tb_xfft_0 is
  78.  
  79.   -----------------------------------------------------------------------
  80.   -- Timing constants
  81.   -----------------------------------------------------------------------
  82.   constant CLOCK_PERIOD : time := 100 ns;
  83.   constant T_HOLD       : time := 10 ns;
  84.   constant T_STROBE     : time := CLOCK_PERIOD - (1 ns);
  85.  
  86.   -----------------------------------------------------------------------
  87.   -- DUT signals
  88.   -----------------------------------------------------------------------
  89.  
  90.   -- General signals
  91.   signal aclk                        : std_logic := '0';  -- the master clock
  92.  
  93.   -- Config slave channel signals
  94.   signal s_axis_config_tvalid        : std_logic := '0';  -- payload is valid
  95.   signal s_axis_config_tready        : std_logic := '1';  -- slave is ready
  96.   signal s_axis_config_tdata         : std_logic_vector(15 downto 0) := (others => '0');  -- data payload
  97.  
  98.   -- Data slave channel signals
  99.   signal s_axis_data_tvalid          : std_logic := '0';  -- payload is valid
  100.   signal s_axis_data_tready          : std_logic := '1';  -- slave is ready
  101.   signal s_axis_data_tdata           : std_logic_vector(31 downto 0) := (others => '0');  -- data payload
  102.   signal s_axis_data_tlast           : std_logic := '0';  -- indicates end of packet
  103.  
  104.   -- Data master channel signals
  105.   signal m_axis_data_tvalid          : std_logic := '0';  -- payload is valid
  106.   signal m_axis_data_tready          : std_logic := '1';  -- slave is ready
  107.   signal m_axis_data_tdata           : std_logic_vector(31 downto 0) := (others => '0');  -- data payload
  108.   signal m_axis_data_tlast           : std_logic := '0';  -- indicates end of packet
  109.  
  110.   -- Event signals
  111.   signal event_frame_started         : std_logic := '0';
  112.   signal event_tlast_unexpected      : std_logic := '0';
  113.   signal event_tlast_missing         : std_logic := '0';
  114.   signal event_status_channel_halt   : std_logic := '0';
  115.   signal event_data_in_channel_halt  : std_logic := '0';
  116.   signal event_data_out_channel_halt : std_logic := '0';
  117.  
  118.   -----------------------------------------------------------------------
  119.   -- Aliases for AXI channel TDATA and TUSER fields
  120.   -- These are a convenience for viewing data in a simulator waveform viewer.
  121.   -- If using ModelSim or Questa, add "-voptargs=+acc=n" to the vsim command
  122.   -- to prevent the simulator optimizing away these signals.
  123.   -----------------------------------------------------------------------
  124.  
  125.   -- Config slave channel alias signals
  126.   signal s_axis_config_tdata_fwd_inv      : std_logic                    := '0';              -- forward or inverse
  127.   signal s_axis_config_tdata_scale_sch    : std_logic_vector(9 downto 0) := (others => '0');  -- scaling schedule
  128.  
  129.   -- Data slave channel alias signals
  130.   signal s_axis_data_tdata_re             : std_logic_vector(15 downto 0) := (others => '0');  -- real data
  131.   signal s_axis_data_tdata_im             : std_logic_vector(15 downto 0) := (others => '0');  -- imaginary data
  132.  
  133.   -- Data master channel alias signals
  134.   signal m_axis_data_tdata_re             : std_logic_vector(15 downto 0) := (others => '0');  -- real data
  135.   signal m_axis_data_tdata_im             : std_logic_vector(15 downto 0) := (others => '0');  -- imaginary data
  136.  
  137.   -----------------------------------------------------------------------
  138.   -- Constants, types and functions to create input data
  139.   -----------------------------------------------------------------------
  140.  
  141.   constant IP_WIDTH    : integer := 16;
  142.   constant MAX_SAMPLES : integer := 2**10;  -- maximum number of samples in a frame
  143.   type T_IP_SAMPLE is record
  144.     re : std_logic_vector(IP_WIDTH-1 downto 0);
  145.     im : std_logic_vector(IP_WIDTH-1 downto 0);
  146.   end record;
  147.   type T_IP_TABLE is array (0 to MAX_SAMPLES-1) of T_IP_SAMPLE;
  148.  
  149.   -- Zeroed input data table, for reset and initialization
  150.   constant IP_TABLE_CLEAR : T_IP_TABLE := (others => (re => (others => '0'),
  151.                                                       im => (others => '0')));
  152.  
  153.   -- Function to generate input data table
  154.   -- Data is a complex sinusoid exp(-jwt) with a frequency 2.6 times the frame size
  155.   -- added to another with a lower magnitude and a higher frequency
  156.   function create_ip_table return T_IP_TABLE is
  157.     variable result : T_IP_TABLE;
  158.     variable theta  : real;
  159.     variable theta2 : real;
  160.     variable re_real : real;
  161.     variable im_real : real;
  162.     variable re_int : integer;
  163.     variable im_int : integer;
  164.     constant DATA_WIDTH : integer := 14;
  165.   begin
  166.     for i in 0 to MAX_SAMPLES-1 loop
  167.       theta   := real(i) / real(MAX_SAMPLES) * 2.6 * 2.0 * MATH_PI;
  168.       re_real := cos(-theta);
  169.       im_real := sin(-theta);
  170.       theta2  := real(i) / real(MAX_SAMPLES) * 23.2 * 2.0 * MATH_PI;
  171.       re_real := re_real + (cos(-theta2) / 4.0);
  172.       im_real := im_real + (sin(-theta2) / 4.0);
  173.       re_int  := integer(round(re_real * real(2**(DATA_WIDTH))));
  174.       im_int  := integer(round(im_real * real(2**(DATA_WIDTH))));
  175.       result(i).re := std_logic_vector(to_signed(re_int, IP_WIDTH));
  176.       result(i).im := std_logic_vector(to_signed(im_int, IP_WIDTH));
  177.     end loop;
  178.     return result;
  179.   end function create_ip_table;
  180.  
  181.   -- Call the function to create the input data
  182.   constant IP_DATA : T_IP_TABLE := create_ip_table;
  183.  
  184.   -----------------------------------------------------------------------
  185.   -- Testbench signals
  186.   -----------------------------------------------------------------------
  187.  
  188.   -- Communication between processes regarding DUT configuration
  189.   type T_DO_CONFIG is (NONE, IMMEDIATE, AFTER_START, DONE);
  190.   shared variable do_config : T_DO_CONFIG := NONE;  -- instruction for driving config slave channel
  191.   type T_CFG_FWD_INV is (FWD, INV);
  192.   signal cfg_fwd_inv : T_CFG_FWD_INV := FWD;
  193.   type T_CFG_SCALE_SCH is (ZERO, DEFAULT);
  194.   signal cfg_scale_sch : T_CFG_SCALE_SCH := DEFAULT;
  195.  
  196.   -- Recording output data, for reuse as input data
  197.   signal op_sample       : integer    := 0;    -- output sample number
  198.   signal op_sample_first : std_logic  := '1';  -- indicates first output sample of a frame
  199.   signal ip_frame        : integer    := 0;    -- input / configuration frame number
  200.   signal op_data         : T_IP_TABLE := IP_TABLE_CLEAR;  -- recorded output data
  201.   signal op_frame        : integer    := 0;    -- output frame number (incremented at end of frame output)
  202.  
  203.  
  204. begin
  205.  
  206.   -----------------------------------------------------------------------
  207.   -- Instantiate the DUT
  208.   -----------------------------------------------------------------------
  209.  
  210.   dut : entity work.xfft_0
  211.     port map (
  212.       aclk                        => aclk,
  213.       s_axis_config_tvalid        => s_axis_config_tvalid,
  214.       s_axis_config_tready        => s_axis_config_tready,
  215.       s_axis_config_tdata         => s_axis_config_tdata,
  216.       s_axis_data_tvalid          => s_axis_data_tvalid,
  217.       s_axis_data_tready          => s_axis_data_tready,
  218.       s_axis_data_tdata           => s_axis_data_tdata,
  219.       s_axis_data_tlast           => s_axis_data_tlast,
  220.       m_axis_data_tvalid          => m_axis_data_tvalid,
  221.       m_axis_data_tready          => m_axis_data_tready,
  222.       m_axis_data_tdata           => m_axis_data_tdata,
  223.       m_axis_data_tlast           => m_axis_data_tlast,
  224.       event_frame_started         => event_frame_started,
  225.       event_tlast_unexpected      => event_tlast_unexpected,
  226.       event_tlast_missing         => event_tlast_missing,
  227.       event_status_channel_halt   => event_status_channel_halt,
  228.       event_data_in_channel_halt  => event_data_in_channel_halt,
  229.       event_data_out_channel_halt => event_data_out_channel_halt
  230.       );
  231.  
  232.   -----------------------------------------------------------------------
  233.   -- Generate clock
  234.   -----------------------------------------------------------------------
  235.  
  236.   clock_gen : process
  237.   begin
  238.     aclk <= '0';
  239.     wait for CLOCK_PERIOD;
  240.     loop
  241.       aclk <= '0';
  242.       wait for CLOCK_PERIOD/2;
  243.       aclk <= '1';
  244.       wait for CLOCK_PERIOD/2;
  245.     end loop;
  246.   end process clock_gen;
  247.  
  248.   -----------------------------------------------------------------------
  249.   -- Generate data slave channel inputs
  250.   -----------------------------------------------------------------------
  251.  
  252.   data_stimuli : process
  253.  
  254.     -- Variables for random number generation
  255.     variable seed1, seed2 : positive;
  256.     variable rand         : real;
  257.  
  258.     -- Procedure to drive an input sample with specific data
  259.     -- data is the data value to drive on the tdata signal
  260.     -- last is the bit value to drive on the tlast signal
  261.     -- valid_mode defines how to drive TVALID: 0 = TVALID always high, 1 = TVALID low occasionally
  262.     procedure drive_sample ( data       : std_logic_vector(31 downto 0);
  263.                              last       : std_logic;
  264.                              valid_mode : integer := 0 ) is
  265.     begin
  266.       s_axis_data_tdata  <= data;
  267.       s_axis_data_tlast  <= last;
  268.  
  269.       if valid_mode = 1 then
  270.         uniform(seed1, seed2, rand);  -- generate random number
  271.         if rand < 0.25 then
  272.           s_axis_data_tvalid <= '0';
  273.           uniform(seed1, seed2, rand);  -- generate another random number
  274.           wait for CLOCK_PERIOD * integer(round(rand * 4.0));  -- hold TVALID low for up to 4 cycles
  275.           s_axis_data_tvalid <= '1';  -- now assert TVALID
  276.         else
  277.           s_axis_data_tvalid <= '1';
  278.         end if;
  279.       else
  280.         s_axis_data_tvalid <= '1';
  281.       end if;
  282.       loop
  283.         wait until rising_edge(aclk);
  284.         exit when s_axis_data_tready = '1';
  285.       end loop;
  286.       wait for T_HOLD;
  287.       s_axis_data_tvalid <= '0';
  288.     end procedure drive_sample;
  289.  
  290.     -- Procedure to drive an input frame with a table of data
  291.     -- data is the data table containing input data
  292.     -- valid_mode defines how to drive TVALID: 0 = TVALID always high, 1 = TVALID low occasionally
  293.     procedure drive_frame ( data         : T_IP_TABLE;
  294.                             valid_mode   : integer := 0 ) is
  295.       variable samples : integer;
  296.       variable index   : integer;
  297.       variable sample_data : std_logic_vector(31 downto 0);
  298.       variable sample_last : std_logic;
  299.     begin
  300.       samples := data'length;
  301.       index  := 0;
  302.       while index < data'length loop
  303.         -- Look up sample data in data table, construct TDATA value
  304.         sample_data(15 downto 0)  := data(index).re;                  -- real data
  305.         sample_data(31 downto 16) := data(index).im;                  -- imaginary data
  306.         -- Construct TLAST's value
  307.         index := index + 1;
  308.         if index >= data'length then
  309.           sample_last := '1';
  310.         else
  311.           sample_last := '0';
  312.         end if;
  313.         -- Drive the sample
  314.         drive_sample(sample_data, sample_last, valid_mode);
  315.       end loop;
  316.     end procedure drive_frame;
  317.  
  318.     variable op_data_saved : T_IP_TABLE;  -- to save a copy of recorded output data
  319.  
  320.  
  321.   begin
  322.  
  323.     -- Drive inputs T_HOLD time after rising edge of clock
  324.     wait until rising_edge(aclk);
  325.     wait for T_HOLD;
  326.  
  327.     -- Drive a frame of input data
  328.     ip_frame <= 1;
  329.     drive_frame(IP_DATA);
  330.  
  331.     -- Allow the result to emerge
  332.     wait until m_axis_data_tlast = '1';
  333.     wait until rising_edge(aclk);
  334.     wait for T_HOLD;
  335.  
  336.     -- Take a copy of the result, to use later as input
  337.     op_data_saved := op_data;
  338.  
  339.     -- Now perform an inverse transform on the result to get back to the original input
  340.     -- Set up the configuration (config_stimuli process handles the config slave channel)
  341.     ip_frame <= 2;
  342.     cfg_fwd_inv <= INV;
  343.     do_config := IMMEDIATE;
  344.     while do_config /= DONE loop
  345.       wait until rising_edge(aclk);
  346.     end loop;
  347.     wait for T_HOLD;
  348.  
  349.     -- Configuration is done.  Set up another configuration to return to forward transforms,
  350.     -- and make the configuration occur as soon as the next frame has begun
  351.     ip_frame <= 3;
  352.     cfg_fwd_inv <= FWD;
  353.     do_config := AFTER_START;
  354.  
  355.     -- Now drive the input data, using the output data of the last frame
  356.     drive_frame(op_data);
  357.     wait until m_axis_data_tlast = '1';
  358.     wait until rising_edge(aclk);
  359.     wait for T_HOLD;
  360.  
  361.     -- The frame is complete, and the configuration to forward transforms has already been done,
  362.     -- so drive the input data, using the output data of the last frame,
  363.     -- which is the same as the original input (excepting scaling and finite precision effects).
  364.     -- This time, deassert the data slave channel TVALID occasionally to illustrate AXI handshaking effects:
  365.     -- as the core is configured to use Non Real Time throttle scheme, it will pause when TVALID is low.
  366.     drive_frame(op_data, 1);
  367.  
  368.     -- During the output of this frame, deassert the data master channel TREADY occasionally:
  369.     -- as the core is configured to use Non Real Time throttle scheme, it will pause when TREADY is low.
  370.     wait until m_axis_data_tvalid = '1';
  371.     wait until rising_edge(aclk);
  372.     while m_axis_data_tlast /= '1' loop
  373.       wait for T_HOLD;
  374.       uniform(seed1, seed2, rand);  -- generate random number
  375.       if rand < 0.25 then
  376.         m_axis_data_tready <= '0';
  377.       else
  378.         m_axis_data_tready <= '1';
  379.       end if;
  380.       wait until rising_edge(aclk);
  381.     end loop;
  382.     wait for T_HOLD;
  383.     m_axis_data_tready <= '1';
  384.     wait for CLOCK_PERIOD;
  385.  
  386.     -- Now run 4 back-to-back transforms, as quickly as possible.
  387.     -- First queue up 2 configurations: these will be applied successively over the next 2 transforms.
  388.     -- 1st configuration
  389.     ip_frame <= 4;
  390.     cfg_fwd_inv <= FWD;  -- forward transform
  391.     cfg_scale_sch <= DEFAULT;  -- default scaling schedule
  392.     do_config := IMMEDIATE;
  393.     while do_config /= DONE loop
  394.       wait until rising_edge(aclk);
  395.     end loop;
  396.     wait for T_HOLD;
  397.  
  398.     -- 2nd configuration: same as 1st, except:
  399.     ip_frame <= 5;
  400.     cfg_fwd_inv <= INV;  -- inverse transform
  401.     cfg_scale_sch <= ZERO;  -- no scaling
  402.     do_config := IMMEDIATE;
  403.     while do_config /= DONE loop
  404.       wait until rising_edge(aclk);
  405.     end loop;
  406.     wait for T_HOLD;
  407.  
  408.     -- Drive the 1st data frame
  409.     drive_frame(IP_DATA);
  410.  
  411.     -- Request a 3rd configuration, to be sent after 2nd data frame starts
  412.     ip_frame <= 6;
  413.     cfg_fwd_inv <= FWD;  -- forward transform
  414.     cfg_scale_sch <= ZERO;  -- no scaling
  415.     do_config := AFTER_START;
  416.  
  417.     -- Drive the 2nd data frame
  418.     drive_frame(op_data_saved);
  419.  
  420.     -- Request a 4th configuration, to be sent after 3rd data frame starts: same as 3rd, except:
  421.     ip_frame <= 7;
  422.     cfg_fwd_inv <= INV;  -- inverse transform
  423.     cfg_scale_sch <= DEFAULT;  -- default scaling schedule
  424.     do_config := AFTER_START;
  425.  
  426.     -- Drive the 3rd data frame
  427.     drive_frame(IP_DATA);
  428.  
  429.     -- Drive the 4th data frame
  430.     drive_frame(op_data_saved);
  431.  
  432.     -- Wait until all the output data from all frames has been produced
  433.     wait until op_frame = 7;
  434.     wait for CLOCK_PERIOD * 10;
  435.  
  436.     -- End of test
  437.     report "Not a real failure. Simulation finished successfully. Test completed successfully" severity failure;
  438.     wait;
  439.  
  440.   end process data_stimuli;
  441.  
  442.   -----------------------------------------------------------------------
  443.   -- Generate config slave channel inputs
  444.   -----------------------------------------------------------------------
  445.  
  446.   config_stimuli : process
  447.     variable scale_sch : std_logic_vector(9 downto 0);
  448.   begin
  449.  
  450.     -- Drive a configuration when requested by data_stimuli process
  451.     wait until rising_edge(aclk);
  452.     while do_config = NONE or do_config = DONE loop
  453.       wait until rising_edge(aclk);
  454.     end loop;
  455.  
  456.     -- If the configuration is requested to occur after the next frame starts, wait for that event
  457.     if do_config = AFTER_START then
  458.       wait until event_frame_started = '1';
  459.       wait until rising_edge(aclk);
  460.     end if;
  461.  
  462.     -- Drive inputs T_HOLD time after rising edge of clock
  463.     wait for T_HOLD;
  464.  
  465.     -- Construct the config slave channel TDATA signal
  466.     s_axis_config_tdata <= (others => '0');  -- clear unused bits
  467.     -- Format the transform direction
  468.     if cfg_fwd_inv = FWD then
  469.       s_axis_config_tdata(0) <= '1';  -- forward
  470.     elsif cfg_fwd_inv = INV then
  471.       s_axis_config_tdata(0) <= '0';  -- inverse
  472.     end if;
  473.     -- Format the scaling schedule
  474.     if cfg_scale_sch = ZERO then  -- no scaling
  475.       scale_sch := (others => '0');
  476.     elsif cfg_scale_sch = DEFAULT then  -- default scaling, for largest magnitude output with no overflow guaranteed
  477.       scale_sch(1 downto 0) := "11";  -- largest scaling at first stage
  478.       for s in 2 to 5 loop
  479.         scale_sch(s*2-1 downto s*2-2) := "10";  -- less scaling at later stages
  480.       end loop;
  481.     end if;
  482.     s_axis_config_tdata(10 downto 1) <= scale_sch;
  483.  
  484.     -- Drive the transaction on the config slave channel
  485.     s_axis_config_tvalid <= '1';
  486.     loop
  487.       wait until rising_edge(aclk);
  488.       exit when s_axis_config_tready = '1';
  489.     end loop;
  490.     wait for T_HOLD;
  491.     s_axis_config_tvalid <= '0';
  492.  
  493.     -- Tell the data_stimuli process that the configuration has been done
  494.     do_config := DONE;
  495.  
  496.   end process config_stimuli;
  497.  
  498.   -----------------------------------------------------------------------
  499.   -- Record outputs, to use later as inputs for another frame
  500.   -----------------------------------------------------------------------
  501.  
  502.   record_outputs : process (aclk)
  503.     -- Function to digit-reverse an integer, to convert output to input ordering
  504.     function digit_reverse_int ( fwd, width : integer ) return integer is
  505.       variable rev     : integer;
  506.       variable fwd_slv : std_logic_vector(width-1 downto 0);
  507.       variable rev_slv : std_logic_vector(width-1 downto 0);
  508.     begin
  509.       fwd_slv := std_logic_vector(to_unsigned(fwd, width));
  510.       for i in 0 to width/2-1 loop  -- reverse in digit groups (2 bits at a time)
  511.         rev_slv(i*2+1 downto i*2) := fwd_slv(width-i*2-1 downto width-i*2-2);
  512.       end loop;
  513.       if width mod 2 = 1 then  -- width is odd: LSB moves to MSB
  514.         rev_slv(width-1) := fwd_slv(0);
  515.       end if;
  516.       rev := to_integer(unsigned(rev_slv));
  517.       return rev;
  518.     end function digit_reverse_int;
  519.  
  520.     variable index : integer := 0;
  521.  
  522.   begin
  523.     if rising_edge(aclk) then
  524.       if m_axis_data_tvalid = '1' and m_axis_data_tready = '1' then
  525.         -- Record output data such that it can be used as input data
  526.         index := op_sample;
  527.         -- Digit-reverse output sample number, to get actual sample index as outputs are in digit-reversed order
  528.         index := digit_reverse_int(index, 10);
  529.         op_data(index).re <= m_axis_data_tdata(15 downto 0);
  530.         op_data(index).im <= m_axis_data_tdata(31 downto 16);
  531.         -- Increment output sample counter
  532.         if m_axis_data_tlast = '1' then  -- end of output frame: reset sample counter and increment frame counter
  533.           op_sample <= 0;
  534.           op_frame <= op_frame + 1;
  535.           op_sample_first <= '1';  -- for next output frame
  536.         else
  537.           op_sample_first <= '0';
  538.           op_sample <= op_sample + 1;
  539.         end if;
  540.       end if;
  541.     end if;
  542.   end process record_outputs;
  543.  
  544.   -----------------------------------------------------------------------
  545.   -- Check outputs
  546.   -----------------------------------------------------------------------
  547.  
  548.   check_outputs : process
  549.     variable check_ok : boolean := true;
  550.     -- Previous values of data master channel signals
  551.     variable m_data_tvalid_prev : std_logic := '0';
  552.     variable m_data_tready_prev : std_logic := '0';
  553.     variable m_data_tdata_prev  : std_logic_vector(31 downto 0) := (others => '0');
  554.   begin
  555.  
  556.     -- Check outputs T_STROBE time after rising edge of clock
  557.     wait until rising_edge(aclk);
  558.     wait for T_STROBE;
  559.  
  560.     -- Do not check the output payload values, as this requires a numerical model
  561.     -- which would make this demonstration testbench unwieldy.
  562.     -- Instead, check the protocol of the data master channel:
  563.     -- check that the payload is valid (not X) when TVALID is high
  564.     -- and check that the payload does not change while TVALID is high until TREADY goes high
  565.  
  566.     if m_axis_data_tvalid = '1' then
  567.       if is_x(m_axis_data_tdata) then
  568.         report "ERROR: m_axis_data_tdata is invalid when m_axis_data_tvalid is high" severity error;
  569.         check_ok := false;
  570.       end if;
  571.  
  572.       if m_data_tvalid_prev = '1' and m_data_tready_prev = '0' then  -- payload must be the same as last cycle
  573.         if m_axis_data_tdata /= m_data_tdata_prev then
  574.           report "ERROR: m_axis_data_tdata changed while m_axis_data_tvalid was high and m_axis_data_tready was low" severity error;
  575.           check_ok := false;
  576.         end if;
  577.       end if;
  578.  
  579.     end if;
  580.  
  581.     assert check_ok
  582.       report "ERROR: terminating test with failures." severity failure;
  583.  
  584.     -- Record payload values for checking next clock cycle
  585.     if check_ok then
  586.       m_data_tvalid_prev  := m_axis_data_tvalid;
  587.       m_data_tready_prev  := m_axis_data_tready;
  588.       m_data_tdata_prev   := m_axis_data_tdata;
  589.     end if;
  590.  
  591.   end process check_outputs;
  592.  
  593.   -----------------------------------------------------------------------
  594.   -- Assign TDATA / TUSER fields to aliases, for easy simulator waveform viewing
  595.   -----------------------------------------------------------------------
  596.  
  597.   -- Config slave channel alias signals
  598.   s_axis_config_tdata_fwd_inv    <= s_axis_config_tdata(0);
  599.   s_axis_config_tdata_scale_sch  <= s_axis_config_tdata(10 downto 1);
  600.  
  601.   -- Data slave channel alias signals
  602.   s_axis_data_tdata_re           <= s_axis_data_tdata(15 downto 0);
  603.   s_axis_data_tdata_im           <= s_axis_data_tdata(31 downto 16);
  604.  
  605.   -- Data master channel alias signals
  606.   m_axis_data_tdata_re           <= m_axis_data_tdata(15 downto 0);
  607.   m_axis_data_tdata_im           <= m_axis_data_tdata(31 downto 16);
  608.  
  609. end tb;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement