Skip to content

Instantly share code, notes, and snippets.

@imuguruza
Created May 18, 2022 06:25
Show Gist options
  • Save imuguruza/9d347bcb641aa9bab0856d5de4ba7e0f to your computer and use it in GitHub Desktop.
Save imuguruza/9d347bcb641aa9bab0856d5de4ba7e0f to your computer and use it in GitHub Desktop.
SPI Salve TB
--------------------------------------------------------------------------------
-- PROJECT: SPI MASTER AND SLAVE FOR FPGA
--------------------------------------------------------------------------------
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
-- LICENSE: The MIT License, please read LICENSE file
-- WEBSITE: https://github.com/jakubcabal/spi-fpga
--------------------------------------------------------------------------------
-- modified by imuguruza
-----------------------------------------
--/ HEADER 16x bits /-- SPI 16x bits chunk 1
-----------------------------------------
--/ MSB..MSB-16 DATA 16xbits /-- SPI 16x bits chunk 2
-----------------------------------------
--/ 7..0 DATA 8xbits | CRC | EMPTY 7x bits /-- SPI 16x bits chunk 3
-----------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
entity TOP_TB is
Generic (
CLK_FREQ : natural := 50e6; -- system clock frequency in Hz
SPI_FREQ : natural := 1e6; -- spi clock frequency in Hz
TRANS_COUNT : natural := 1e4; -- number of test transaction
DATA_SIZE : integer := 24; --number of data bits in message
SPI_DATA_SIZE : integer := 16 --number of data bits in message
);
end entity;
architecture SIM of TOP_TB is
constant CLK_PERIOD : time := 1 ns * integer(real(1e9)/real(CLK_FREQ));
constant SPI_PERIOD : time := 1 ns * integer(real(1e9)/real(SPI_FREQ));
constant FRAME_HEADER_WIDTH : INTEGER := 16; -- HEADER SIZE, 16 bits
constant FRAME_HEADER_AND_DATA_WIDTH : INTEGER := DATA_SIZE + FRAME_HEADER_WIDTH;
constant MESSAGE_HEADER : std_logic_vector (FRAME_HEADER_WIDTH - 1 DOWNTO 0) := x"CAFE";
signal CLK : std_logic;
signal RST : std_logic;
signal sclk : std_logic := '0';
signal cs_n : std_logic := '1';
signal mosi : std_logic;
signal miso : std_logic := '0';
signal dummy_miso : std_logic := '0';
signal spi_mdi : std_logic_vector(SPI_DATA_SIZE-1 downto 0);
signal spi_mdo : std_logic_vector(SPI_DATA_SIZE-1 downto 0);
signal data : std_logic_vector(DATA_SIZE-1 downto 0);
signal sim_done : std_logic := '0';
signal FRAME_HEADER_AND_DATA : std_logic_vector(FRAME_HEADER_AND_DATA_WIDTH-1 downto 0);
signal DATA_M_2_S : std_logic_vector (DATA_SIZE-1 DOWNTO 0);
signal CRC : std_logic;
procedure CALCULATE_CRC (
signal MESSAGE : in std_logic_vector ((FRAME_HEADER_WIDTH + DATA_SIZE) - 1 DOWNTO 0);
signal CRC_VAL : out std_logic
) is
begin
for i in 0 to FRAME_HEADER_WIDTH + DATA_SIZE - 2 loop
CRC_VAL <= MESSAGE ( (FRAME_HEADER_WIDTH + DATA_SIZE) - 1 - i)
xor MESSAGE ( (FRAME_HEADER_WIDTH + DATA_SIZE) - 2 - i);
end loop;
end procedure;
procedure SPI_MASTER (
constant SPI_PER : time;
signal SMM_MDI : out std_logic_vector(SPI_DATA_SIZE-1 downto 0);
signal SMM_MDO : in std_logic_vector(SPI_DATA_SIZE-1 downto 0);
signal SMM_SCLK : out std_logic;
signal SMM_CS_N : out std_logic;
signal SMM_MOSI : out std_logic;
signal SMM_MISO : in std_logic
) is
begin
SMM_CS_N <= '0';
for i in 0 to (SPI_DATA_SIZE-1) loop
SMM_SCLK <= '0';
SMM_MOSI <= SMM_MDO(SPI_DATA_SIZE-1-i);
wait for SPI_PER/2;
SMM_SCLK <= '1';
SMM_MDI(SPI_DATA_SIZE-1-i) <= SMM_MISO;
wait for SPI_PER/2;
end loop;
SMM_SCLK <= '0';
wait for SPI_PER/2;
SMM_CS_N <= '1';
end procedure;
begin
dut : entity work.TOP
generic map (
DATA_SIZE => DATA_SIZE
)
port map (
i_clk => CLK,
i_reset => RST,
-- SPI MASTER INTERFACE
i_sclk => sclk,
i_cs_n => cs_n,
i_mosi => mosi,
o_miso => miso,
-----------
o_data => data
);
clk_gen_p : process
begin
CLK <= '0';
wait for CLK_PERIOD/2;
CLK <= '1';
wait for CLK_PERIOD/2;
if (sim_done = '1') then
wait;
end if;
end process;
rst_gen_p : process
begin
report "======== SIMULATION START! ========";
RST <= '1';
wait for CLK_PERIOD*3;
RST <= '0';
wait;
end process;
-- -------------------------------------------------------------------------
-- DUT TEST
-- -------------------------------------------------------------------------
test : process
begin
wait until RST = '0';
spi_mdo <= x"0000";
spi_mdi <= x"0000";
wait for CLK_PERIOD*10;
-- compose frame header and data and crc
DATA_M_2_S <= x"A0A0A0";
wait for CLK_PERIOD*10;
FRAME_HEADER_AND_DATA <= JEMA_MESSAGE_HEADER & DATA_M_2_S;
wait for CLK_PERIOD*10;
CALCULATE_CRC(FRAME_HEADER_AND_DATA, CRC);
wait for CLK_PERIOD*10;
report "======== Sending frame with data x'A0A0A0'... ========";
-- send chunk 1
spi_mdo <= MESSAGE_HEADER;
wait for CLK_PERIOD*10;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*10;
-- send chunk 2
spi_mdo <= DATA_M_2_S(23 DOWNTO 8);
wait for CLK_PERIOD*10;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*10;
-- send chunk 3, with 0 empty fields
spi_mdo <= DATA_M_2_S(7 DOWNTO 0) & CRC & "0000000";
wait for CLK_PERIOD*10;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*10;
-- Check data out of DUT
if (data /= DATA_M_2_S ) then
report "======== Data out not expected, error! ========";
else
report "======== Data out expected, ok! ========";
end if;
-- compose frame header and data and crc
DATA_M_2_S <= x"0F0F0F";
wait for CLK_PERIOD;
FRAME_HEADER_AND_DATA <= MESSAGE_HEADER & DATA_M_2_S;
wait for CLK_PERIOD;
CALCULATE_CRC(FRAME_HEADER_AND_DATA, CRC);
wait for CLK_PERIOD;
report "======== Sending frame with data x'0F0F0F'... ========";
-- send chunk 1
spi_mdo <= MESSAGE_HEADER;
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- send chunk 2
spi_mdo <= DATA_M_2_S(23 DOWNTO 8);
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- send chunk 3, with 0 empty fields
spi_mdo <= DATA_M_2_S(7 DOWNTO 0) & CRC & "0000000";
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- Check data out of DUT
if (data /= DATA_M_2_S ) then
report "======== Data out not expected, error! ========";
else
report "======== Data out expected, ok! ========";
end if;
-------------------------------------------------------------------------------
DATA_M_2_S <= x"0B0B0B";
wait for CLK_PERIOD;
FRAME_HEADER_AND_DATA <= MESSAGE_HEADER & DATA_M_2_S;
wait for CLK_PERIOD;
CALCULATE_CRC(FRAME_HEADER_AND_DATA, CRC);
wait for CLK_PERIOD;
report "======== Sending frame with data x'0B0B0B' with wrong CRC... ========";
-- send chunk 1
spi_mdo <= MESSAGE_HEADER;
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- send chunk 2
spi_mdo <= DATA_M_2_S(23 DOWNTO 8);
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- send chunk 3, with 0 empty fields
spi_mdo <= DATA_M_2_S(7 DOWNTO 0) & not CRC & "0000000";
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- Check data out of DUT
if (data /= x"0F0F0F" ) then
report "======== Data out not expected, error! ========";
else
report "======== Data out expected, ok! ========";
end if;
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
DATA_M_2_S <= x"0B0B0B";
wait for CLK_PERIOD;
FRAME_HEADER_AND_DATA <= MESSAGE_HEADER & DATA_M_2_S;
wait for CLK_PERIOD;
CALCULATE_CRC(FRAME_HEADER_AND_DATA, CRC);
wait for CLK_PERIOD;
report "======== Sending frame with data x'0C0C0C' with wrong Header... ========";
-- send chunk 1
spi_mdo <= x"EFAC";
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- send chunk 2
spi_mdo <= DATA_M_2_S(23 DOWNTO 8);
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- send chunk 3, with 0 empty fields
spi_mdo <= DATA_M_2_S(7 DOWNTO 0) & CRC & "0000000";
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- Check data out of DUT
if (data /= x"0F0F0F" ) then
report "======== Data out not expected, error! ========";
else
report "======== Data out expected, ok! ========";
end if;
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
DATA_M_2_S <= x"0B0B0B";
wait for CLK_PERIOD;
FRAME_HEADER_AND_DATA <= MESSAGE_HEADER & DATA_M_2_S;
wait for CLK_PERIOD;
CALCULATE_CRC(FRAME_HEADER_AND_DATA, CRC);
wait for CLK_PERIOD;
report "======== Sending frame with data x'0B0B0B' with different message tail... ========";
-- send chunk 1
spi_mdo <= MESSAGE_HEADER;
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- send chunk 2
spi_mdo <= DATA_M_2_S(23 DOWNTO 8);
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- send chunk 3, with 0 empty fields
spi_mdo <= DATA_M_2_S(7 DOWNTO 0) & CRC & "1010101";
wait for CLK_PERIOD;
SPI_MASTER(SPI_PERIOD, spi_mdi, spi_mdo, sclk, cs_n, mosi, dummy_miso);
wait for CLK_PERIOD*5;
-- Check data out of DUT
if (data /= DATA_M_2_S ) then
report "======== Data out not expected, error! ========";
else
report "======== Data out expected, ok! ========";
end if;
-------------------------------------------------------------------------------
report "======== SIMULATION SUCCESSFULLY COMPLETED! ========";
sim_done <= '1';
wait for CLK_PERIOD*10;
end process;
end architecture;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment