------------------------------------------------------------------------------- -- -- tb_spi_master_slave.vhdl -- -- Testbench for: -- -- spi_fsm_example -- SPI MASTER -- spi_slave_example -- SPI SLAVE -- ------------------------------------------------------------------------------- -- -- TEST DESCRIPTION -- -- The testbench connects the SPI master directly to the SPI slave. -- -- Master transmits: -- -- X"A5" -- -- Slave transmits: -- -- X"3C" -- -- Because SPI is full duplex: -- -- Master RX should = X"3C" -- Slave RX should = X"A5" -- ------------------------------------------------------------------------------- -- -- SPI CONNECTION -- -- MASTER SLAVE -- -- spi_cs_n_out -----------------> spi_cs_n_in -- -- spi_sclk_out -----------------> spi_sclk_in -- -- spi_mosi_out -----------------> spi_mosi_in -- -- spi_miso_in <------------------ spi_miso_out -- ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; -- fix for to_hstring use ieee.std_logic_textio.all; -- Required for the hwrite function use std.textio.all; -- use ieee.numeric_std.all; entity spi_master_slave_example_tb is generic( CLK_DIVIDER: positive := 4; DATA_WIDTH: positive := 8; NUM_TRANSFERS: positive := 16 ); end entity; architecture behavioral of spi_master_slave_example_tb is ------------------------------------------------------- -- fix for to_hstring - not included in the Quartus Lite ...1164 library for some reason -- converts a SLV to a hex string for use in a "report" string ------------------------------------------------------- function to_hstring(slv : std_logic_vector) return string is variable L : line; -- a LINE is a buffer for I/O variable result : string(1 to (slv'length + 3) / 4); -- ceil for a nibble begin hwrite(L, slv); -- write the SLV to a LINE as hex text result := L.all; -- get the whole text line and assign it to a string deallocate(L); return result; end function; --------------------------------------------------------- signal CLK_IN: std_logic; signal RESET_IN: std_logic; signal START_IN: std_logic; signal MASTER_TX_DATA: std_logic_vector((DATA_WIDTH-1) downto 0); signal MASTER_RX_DATA: std_logic_vector((DATA_WIDTH-1) downto 0); signal SLAVE_TX_DATA: std_logic_vector((DATA_WIDTH-1) downto 0); signal SLAVE_RX_DATA: std_logic_vector((DATA_WIDTH-1) downto 0); signal MASTER_BUSY: std_logic; signal SLAVE_BUSY: std_logic; constant PER: time := 20 ns; component spi_master_slave_example is generic( CLK_DIVIDER: positive := 4; DATA_WIDTH: positive := 8 ); port( i_clk_in: in std_logic; i_reset_in: in std_logic; i_start_in: in std_logic; i_master_tx_data: in std_logic_vector(DATA_WIDTH-1 downto 0); o_master_rx_data: out std_logic_vector(DATA_WIDTH-1 downto 0); i_slave_tx_data: in std_logic_vector(DATA_WIDTH-1 downto 0); o_slave_rx_data: out std_logic_vector(DATA_WIDTH-1 downto 0); o_master_busy_out: out std_logic; o_slave_busy_out: out std_logic ); end component; begin -- DUT master_inst: spi_master_slave_example generic map( CLK_DIVIDER => CLK_DIVIDER, DATA_WIDTH => DATA_WIDTH ) port map( i_clk_in => CLK_IN, i_reset_in => RESET_IN, i_start_in => START_IN, i_master_tx_data => MASTER_TX_DATA, o_master_rx_data => MASTER_RX_DATA, i_slave_tx_data => SLAVE_TX_DATA, o_slave_rx_data => SLAVE_RX_DATA, o_master_busy_out => MASTER_BUSY, o_slave_busy_out => SLAVE_BUSY ); -- Clock process clock: process -- note - no sensitivity list allowed begin CLK_IN <= '0'; wait for PER/2; infinite: loop CLK_IN <= not CLK_IN; wait for PER/2; end loop; end process clock; -- RESET process reset: process -- note - no sensitivity list allowed begin RESET_IN <= '1'; wait for 2*PER; RESET_IN <= '0'; wait; end process reset; test_process: process begin wait for 2 * PER; -- wait for reset for i in 1 to NUM_TRANSFERS loop MASTER_TX_DATA <= std_logic_vector(to_unsigned((4 * i), MASTER_TX_DATA'length)); SLAVE_TX_DATA <= std_logic_vector(to_unsigned((3 * i), MASTER_TX_DATA'length)); START_IN <= '0'; -- start transfer wait for 8 * PER; START_IN <= '1'; wait for PER; START_IN <= '0'; wait for PER * CLK_DIVIDER; assert master_busy = '1' report "ERROR: Master did not indicate busy." severity error; assert slave_busy = '1' report "ERROR: Slave did not indicate busy." severity error; -- complete ? wait until (master_busy = '0'); wait for 2 * PER; -- check master assert MASTER_RX_DATA = std_logic_vector(to_unsigned((3 * i), MASTER_TX_DATA'length)) report "ERROR: Master received incorrect data." & " Expected " & to_hstring(std_logic_vector(to_unsigned((3 * i), MASTER_TX_DATA'length))) & " Received " & to_hstring(master_rx_data) severity error; assert master_busy = '0' report "ERROR: Master did not indicate idle." severity error; -- check slave assert SLAVE_RX_DATA = std_logic_vector(to_unsigned((4 * i), SLAVE_TX_DATA'length)) report "ERROR: Slave received incorrect data." & " Expected " & to_hstring(std_logic_vector(to_unsigned((4 * i), SLAVE_TX_DATA'length))) & " Received " & to_hstring(slave_rx_data) severity error; assert slave_busy = '0' report "ERROR: Slave did not indicate idle." severity error; end loop; report "========================================"; report "ALL SPI TESTS COMPLETED"; report "========================================"; -- Wait a a few clocks and terminate the sim (independent of tool settings) wait for PER * 4; assert false report "SPI TESTBENCH COMPLETE." severity failure; end process; end architecture;