Skip to content

Commit 87ef439

Browse files
committed
SPI MASTER [FEATURE]: Add better simulation
1 parent c57179c commit 87ef439

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-0
lines changed

sim/spi_master_tb.vhd

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
--------------------------------------------------------------------------------
2+
-- PROJECT: SPI MASTER AND SLAVE FOR FPGA
3+
--------------------------------------------------------------------------------
4+
-- NAME: SPI_MASTER
5+
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
6+
-- LICENSE: LGPL-3.0, please read LICENSE file
7+
-- WEBSITE: https://github.com/jakubcabal/spi-fpga
8+
--------------------------------------------------------------------------------
9+
10+
library IEEE;
11+
use IEEE.STD_LOGIC_1164.ALL;
12+
use IEEE.NUMERIC_STD.ALL;
13+
use IEEE.MATH_REAL.ALL;
14+
15+
entity SPI_MASTER_TB is
16+
Generic (
17+
CLK_FREQ : natural := 50e6; -- system clock frequency in Hz
18+
SPI_FREQ : natural := 1e6; -- spi clock frequency in Hz
19+
WORD_SIZE : natural := 8; -- size of transfer word in bits, must be power of two
20+
TRANS_COUNT : natural := 1e4 -- number of test transaction
21+
);
22+
end entity;
23+
24+
architecture SIM of SPI_MASTER_TB is
25+
26+
constant CLK_PERIOD : time := 1 ns * integer(real(1e9)/real(CLK_FREQ));
27+
constant SPI_PERIOD : time := 1 ns * integer(real(1e9)/real(SPI_FREQ));
28+
constant RX_OFFSET : natural := 42;
29+
constant TX_OFFSET : natural := 11;
30+
31+
signal CLK : std_logic;
32+
signal RST : std_logic;
33+
34+
signal sclk : std_logic;
35+
signal cs_n : std_logic;
36+
signal mosi : std_logic;
37+
signal miso : std_logic;
38+
39+
signal udi : std_logic_vector(WORD_SIZE-1 downto 0);
40+
signal udi_vld : std_logic;
41+
signal udi_rdy : std_logic;
42+
signal udo : std_logic_vector(WORD_SIZE-1 downto 0);
43+
signal udo_exp : std_logic_vector(WORD_SIZE-1 downto 0);
44+
signal udo_vld : std_logic;
45+
46+
signal spi_sdi : std_logic_vector(WORD_SIZE-1 downto 0);
47+
signal spi_sdo : std_logic_vector(WORD_SIZE-1 downto 0);
48+
signal spi_sdo_exp : std_logic_vector(WORD_SIZE-1 downto 0);
49+
50+
signal spi_model_done : std_logic := '0';
51+
signal udi_done : std_logic := '0';
52+
signal udo_done : std_logic := '0';
53+
signal sim_done : std_logic := '0';
54+
signal rand_int : integer := 0;
55+
signal count_rx : integer;
56+
signal count_tx : integer;
57+
58+
procedure SPI_SLAVE (
59+
signal SSM_SDI : in std_logic_vector(WORD_SIZE-1 downto 0);
60+
signal SSM_SDO : out std_logic_vector(WORD_SIZE-1 downto 0);
61+
signal SSM_SCLK : in std_logic;
62+
signal SSM_CS_N : in std_logic;
63+
signal SSM_MOSI : in std_logic;
64+
signal SSM_MISO : out std_logic
65+
) is
66+
begin
67+
wait until SSM_CS_N = '0';
68+
for i in 0 to (WORD_SIZE-1) loop
69+
SSM_MISO <= SSM_SDI(WORD_SIZE-1-i);
70+
wait until rising_edge(SSM_SCLK);
71+
SSM_SDO(WORD_SIZE-1-i) <= SSM_MOSI;
72+
wait until falling_edge(SSM_SCLK);
73+
end loop;
74+
end procedure;
75+
76+
begin
77+
78+
rand_int_p : process
79+
variable seed1, seed2: positive;
80+
variable rand : real;
81+
begin
82+
uniform(seed1, seed2, rand);
83+
rand_int <= integer(rand*real(20));
84+
--report "Random number X: " & integer'image(rand_int);
85+
wait for CLK_PERIOD;
86+
if (sim_done = '1') then
87+
wait;
88+
end if;
89+
end process;
90+
91+
dut : entity work.SPI_MASTER
92+
generic map (
93+
CLK_FREQ => CLK_FREQ,
94+
SCLK_FREQ => SPI_FREQ,
95+
WORD_SIZE => WORD_SIZE
96+
)
97+
port map (
98+
CLK => CLK,
99+
RST => RST,
100+
-- SPI SLAVE INTERFACE
101+
SCLK => sclk,
102+
CS_N(0) => cs_n,
103+
MOSI => mosi,
104+
MISO => miso,
105+
-- USER INTERFACE
106+
DIN => udi,
107+
DIN_ADDR => (others => '0'),
108+
DIN_LAST => '1',
109+
DIN_VLD => udi_vld,
110+
DIN_RDY => udi_rdy,
111+
DOUT => udo,
112+
DOUT_VLD => udo_vld
113+
);
114+
115+
clk_gen_p : process
116+
begin
117+
CLK <= '0';
118+
wait for CLK_PERIOD/2;
119+
CLK <= '1';
120+
wait for CLK_PERIOD/2;
121+
if (sim_done = '1') then
122+
wait;
123+
end if;
124+
end process;
125+
126+
rst_gen_p : process
127+
begin
128+
report "======== SIMULATION START! ========";
129+
report "Total transactions for master to slave direction: " & integer'image(TRANS_COUNT);
130+
report "Total transactions for slave to master direction: " & integer'image(TRANS_COUNT);
131+
RST <= '1';
132+
wait for CLK_PERIOD*3;
133+
RST <= '0';
134+
wait;
135+
end process;
136+
137+
-- -------------------------------------------------------------------------
138+
-- DUT TEST
139+
-- -------------------------------------------------------------------------
140+
141+
spi_slave_model_p : process
142+
begin
143+
count_tx <= 1;
144+
wait until RST = '0';
145+
for i in 0 to TRANS_COUNT-1 loop
146+
spi_sdi <= std_logic_vector(to_unsigned(((i+RX_OFFSET) mod 2**WORD_SIZE),WORD_SIZE));
147+
spi_sdo_exp <= std_logic_vector(to_unsigned(((i+TX_OFFSET) mod 2**WORD_SIZE),WORD_SIZE));
148+
SPI_SLAVE(spi_sdi, spi_sdo, sclk, cs_n, mosi, miso);
149+
if (spi_sdo = spi_sdo_exp) then
150+
if ((count_tx mod (TRANS_COUNT/10)) = 0) then
151+
report "Transactions received from master: " & integer'image(count_tx);
152+
end if;
153+
else
154+
report "======== UNEXPECTED TRANSACTION ON MOSI SIGNAL (master to slave)! ========" severity failure;
155+
end if;
156+
count_tx <= count_tx + 1;
157+
end loop;
158+
spi_model_done <= '1';
159+
wait;
160+
end process;
161+
162+
spi_master_udi_p : process
163+
begin
164+
wait until RST = '0';
165+
wait until rising_edge(CLK);
166+
wait for CLK_PERIOD/2;
167+
for i in 0 to TRANS_COUNT-1 loop
168+
udi <= std_logic_vector(to_unsigned(((i+TX_OFFSET) mod 2**WORD_SIZE),WORD_SIZE));
169+
udi_vld <= '1';
170+
if (udi_rdy = '0') then
171+
wait until udi_rdy = '1';
172+
wait for CLK_PERIOD/2;
173+
end if;
174+
wait for CLK_PERIOD;
175+
udi_vld <= '0';
176+
wait for rand_int*CLK_PERIOD;
177+
end loop;
178+
udi_done <= '1';
179+
wait;
180+
end process;
181+
182+
spi_master_udo_p : process
183+
begin
184+
count_rx <= 1;
185+
for i in 0 to TRANS_COUNT-1 loop
186+
udo_exp <= std_logic_vector(to_unsigned(((i+RX_OFFSET) mod 2**WORD_SIZE),WORD_SIZE));
187+
wait until udo_vld = '1';
188+
if (udo = udo_exp) then
189+
if ((count_rx mod (TRANS_COUNT/10)) = 0) then
190+
report "Transactions received from slave: " & integer'image(count_rx);
191+
end if;
192+
else
193+
report "======== UNEXPECTED TRANSACTION ON DOUT SIGNAL (slave to master)! ========" severity failure;
194+
end if;
195+
count_rx <= count_rx + 1;
196+
wait for CLK_PERIOD;
197+
end loop;
198+
udo_done <= '1';
199+
wait;
200+
end process;
201+
202+
-- -------------------------------------------------------------------------
203+
-- TEST DONE CHECK
204+
-- -------------------------------------------------------------------------
205+
206+
test_done_p : process
207+
variable v_test_done : std_logic;
208+
begin
209+
v_test_done := spi_model_done and udi_done and udo_done;
210+
if (v_test_done = '1') then
211+
wait for 100*CLK_PERIOD;
212+
sim_done <= '1';
213+
report "======== SIMULATION SUCCESSFULLY COMPLETED! ========";
214+
wait;
215+
end if;
216+
wait for CLK_PERIOD;
217+
end process;
218+
219+
end architecture;

sim/spi_master_tb_msim_run.tcl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#-------------------------------------------------------------------------------
2+
# PROJECT: SPI MASTER AND SLAVE FOR FPGA
3+
#-------------------------------------------------------------------------------
4+
# AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
5+
# LICENSE: LGPL-3.0, please read LICENSE file
6+
# WEBSITE: https://github.com/jakubcabal/spi-fpga
7+
#-------------------------------------------------------------------------------
8+
9+
# Create work library
10+
vlib work
11+
12+
# Compile VHDL files
13+
vcom -93 ../rtl/spi_master.vhd
14+
vcom -93 ./spi_master_tb.vhd
15+
16+
# Load testbench
17+
vsim work.spi_master_tb
18+
19+
# Setup and start simulation
20+
add wave sim:/spi_master_tb/*
21+
add wave sim:/spi_master_tb/dut/*
22+
run -All

0 commit comments

Comments
 (0)