Library of reusable VHDL components
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
12 KiB

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. use ieee.numeric_std.all;
  4. --+ including vhdl 2008 libraries
  5. --+ These lines can be commented out when using
  6. --+ a simulator with built-in VHDL 2008 support
  7. library ieee_proposed;
  8. use ieee_proposed.standard_additions.all;
  9. use ieee_proposed.std_logic_1164_additions.all;
  10. use ieee_proposed.numeric_std_additions.all;
  11. library osvvm;
  12. use osvvm.RandomPkg.all;
  13. library libvhdl;
  14. use libvhdl.AssertP.all;
  15. use libvhdl.SimP.all;
  16. use libvhdl.QueueP.all;
  17. entity SpiT is
  18. end entity SpiT;
  19. architecture sim of SpiT is
  20. component SpiMasterE is
  21. generic (
  22. G_DATA_WIDTH : positive := 8;
  23. G_DATA_DIR : natural range 0 to 1 := 0;
  24. G_SPI_CPOL : natural range 0 to 1 := 0;
  25. G_SPI_CPHA : natural range 0 to 1 := 0;
  26. G_SCLK_DIVIDER : positive range 6 to positive'high := 10
  27. );
  28. port (
  29. --+ system if
  30. Reset_n_i : in std_logic;
  31. Clk_i : in std_logic;
  32. --+ SPI slave if
  33. SpiSclk_o : out std_logic;
  34. SpiSte_o : out std_logic;
  35. SpiMosi_o : out std_logic;
  36. SpiMiso_i : in std_logic;
  37. --+ local VAI if
  38. Data_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0);
  39. DataValid_i : in std_logic;
  40. DataAccept_o : out std_logic;
  41. Data_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0);
  42. DataValid_o : out std_logic;
  43. DataAccept_i : in std_logic
  44. );
  45. end component SpiMasterE;
  46. component SpiSlaveE is
  47. generic (
  48. G_DATA_WIDTH : positive := 8;
  49. G_DATA_DIR : natural range 0 to 1 := 0;
  50. G_SPI_CPOL : natural range 0 to 1 := 0;
  51. G_SPI_CPHA : natural range 0 to 1 := 0
  52. );
  53. port (
  54. --+ system if
  55. Reset_n_i : in std_logic;
  56. Clk_i : in std_logic;
  57. --+ SPI slave if
  58. SpiSclk_i : in std_logic;
  59. SpiSte_i : in std_logic;
  60. SpiMosi_i : in std_logic;
  61. SpiMiso_o : out std_logic;
  62. --+ local VAI if
  63. Data_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0);
  64. DataValid_i : in std_logic;
  65. DataAccept_o : out std_logic;
  66. Data_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0);
  67. DataValid_o : out std_logic;
  68. DataAccept_i : in std_logic
  69. );
  70. end component SpiSlaveE;
  71. --* testbench global clock period
  72. constant C_PERIOD : time := 5 ns;
  73. --* SPI data transfer data width
  74. constant C_DATA_WIDTH : natural := 8;
  75. --* testbench global clock
  76. signal s_clk : std_logic := '0';
  77. --* testbench global reset
  78. signal s_reset_n : std_logic := '0';
  79. --* SPI mode range subtype
  80. subtype t_spi_mode is natural range 0 to 3;
  81. --+ test done array with entry for each test
  82. signal s_test_done : boolean_vector(t_spi_mode'low to 2*t_spi_mode'high+1) := (others => false);
  83. begin
  84. --* testbench global clock
  85. s_clk <= not(s_clk) after C_PERIOD/2 when not(and_reduce(s_test_done)) else '0';
  86. --* testbench global reset
  87. s_reset_n <= '1' after 100 ns;
  88. --+ SpiMasterE tests for all 4 modes
  89. SpiMastersG : for mode in t_spi_mode'low to t_spi_mode'high generate
  90. signal s_sclk : std_logic;
  91. signal s_ste : std_logic;
  92. signal s_mosi : std_logic;
  93. signal s_miso : std_logic;
  94. signal s_din : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  95. signal s_din_valid : std_logic;
  96. signal s_din_accept : std_logic;
  97. signal s_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  98. signal s_dout_valid : std_logic;
  99. signal s_dout_accept : std_logic;
  100. shared variable sv_mosi_queue : t_list_queue;
  101. shared variable sv_miso_queue : t_list_queue;
  102. begin
  103. --* Stimuli generator and BFM for the valid-accept interface
  104. --* on the local data input of the DUT
  105. --*
  106. --* Generates random stimuli and serves it to the
  107. --* valid-accept interface at the input of the DUT
  108. --*
  109. --* The stimuli data is also pushed into the mosi queue
  110. --* which serves as simple abstract reference model
  111. --* of the SPI transmit (master -> slave) channel
  112. SpiMasterStimP : process is
  113. variable v_random : RandomPType;
  114. begin
  115. v_random.InitSeed(v_random'instance_name);
  116. s_din_valid <= '0';
  117. s_din <= (others => '0');
  118. wait until s_reset_n = '1';
  119. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  120. s_din <= v_random.RandSlv(C_DATA_WIDTH);
  121. s_din_valid <= '1';
  122. wait until rising_edge(s_clk) and s_din_accept = '1';
  123. s_din_valid <= '0';
  124. sv_mosi_queue.push(s_din);
  125. wait until rising_edge(s_clk);
  126. end loop;
  127. wait;
  128. end process SpiMasterStimP;
  129. --* DUT: SpiMasterE component
  130. i_SpiMasterE : SpiMasterE
  131. generic map (
  132. G_DATA_WIDTH => C_DATA_WIDTH,
  133. G_DATA_DIR => 1,
  134. G_SPI_CPOL => mode / 2,
  135. G_SPI_CPHA => mode mod 2,
  136. G_SCLK_DIVIDER => 10
  137. )
  138. port map (
  139. --+ system if
  140. Reset_n_i => s_reset_n,
  141. Clk_i => s_clk,
  142. --+ SPI slave if
  143. SpiSclk_o => s_sclk,
  144. SpiSte_o => s_ste,
  145. SpiMosi_o => s_mosi,
  146. SpiMiso_i => s_miso,
  147. --+ local VAI if
  148. Data_i => s_din,
  149. DataValid_i => s_din_valid,
  150. DataAccept_o => s_din_accept,
  151. Data_o => s_dout,
  152. DataValid_o => s_dout_valid,
  153. DataAccept_i => s_dout_accept
  154. );
  155. --* Checker and BFM for the valid-accept interface
  156. --* on the local data output of the DUT
  157. --*
  158. --* Reads the output of the DUT and compares it to
  159. --* data popped from the miso queue which serves as
  160. --* simple abstract reference model of the SPI receive
  161. --* (slave -> master) channel
  162. SpiMasterCheckP : process is
  163. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  164. begin
  165. s_dout_accept <= '0';
  166. wait until s_reset_n = '1';
  167. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  168. wait until rising_edge(s_clk) and s_dout_valid = '1';
  169. s_dout_accept <= '1';
  170. sv_miso_queue.pop(v_queue_data);
  171. assert_equal(s_dout, v_queue_data);
  172. wait until rising_edge(s_clk);
  173. s_dout_accept <= '0';
  174. end loop;
  175. report "INFO: SpiMaster (mode=" & to_string(mode) & ") test successfully";
  176. s_test_done(mode) <= true;
  177. wait;
  178. end process SpiMasterCheckP;
  179. --* Stimuli generator and BFM for the SPI slave
  180. --* interface on the SPI miso input of the DUT
  181. --*
  182. --* Generates random stimuli and serves it to the
  183. --* SPI interface at the input of the DUT
  184. --*
  185. --* The stimuli data is also pushed into the miso queue
  186. --* which serves as simple abstract reference model
  187. --* of the SPI receive (slave -> master) channel
  188. --*
  189. --* Furthermore the data received by the SPI slave BFM
  190. --* is checked against data popped from the mosi queue
  191. --* which serves as simple abstract reference model of
  192. --* the SPI receive (master -> slave) channel
  193. SpiSlaveP : process is
  194. variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  195. variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  196. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  197. variable v_random : RandomPType;
  198. begin
  199. v_random.InitSeed(v_random'instance_name);
  200. wait until s_reset_n = '1';
  201. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  202. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  203. sv_miso_queue.push(v_send_data);
  204. spi_slave (data_in => v_send_data,
  205. data_out => v_receive_data,
  206. sclk => s_sclk,
  207. ste => s_ste,
  208. mosi => s_mosi,
  209. miso => s_miso,
  210. cpol => mode / 2,
  211. cpha => mode mod 2
  212. );
  213. sv_mosi_queue.pop(v_queue_data);
  214. assert_equal(v_receive_data, v_queue_data);
  215. end loop;
  216. wait;
  217. end process SpiSlaveP;
  218. end generate SpiMastersG;
  219. --+ SpiSlaveE tests for all 4 modes
  220. SpiSlavesG : for mode in t_spi_mode'low to t_spi_mode'high generate
  221. signal s_sclk : std_logic;
  222. signal s_ste : std_logic;
  223. signal s_mosi : std_logic;
  224. signal s_miso : std_logic;
  225. signal s_din : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  226. signal s_din_valid : std_logic;
  227. signal s_din_accept : std_logic;
  228. signal s_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  229. signal s_dout_valid : std_logic;
  230. signal s_dout_accept : std_logic;
  231. shared variable sv_mosi_queue : t_list_queue;
  232. shared variable sv_miso_queue : t_list_queue;
  233. begin
  234. --* Unit test of spi master procedure, checks all combinations
  235. --* of cpol & cpha against spi slave procedure
  236. SpiMasterP : process is
  237. variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  238. variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  239. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  240. variable v_random : RandomPType;
  241. begin
  242. v_random.InitSeed(v_random'instance_name);
  243. s_sclk <= '1';
  244. s_ste <= '1';
  245. s_mosi <= '1';
  246. wait until s_reset_n = '1';
  247. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  248. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  249. sv_mosi_queue.push(v_send_data);
  250. spi_master (data_in => v_send_data,
  251. data_out => v_receive_data,
  252. sclk => s_sclk,
  253. ste => s_ste,
  254. mosi => s_mosi,
  255. miso => s_miso,
  256. cpol => mode / 2,
  257. cpha => mode mod 2,
  258. period => 100 ns
  259. );
  260. sv_miso_queue.pop(v_queue_data);
  261. assert_equal(v_receive_data, v_queue_data);
  262. end loop;
  263. report "INFO: SpiSlave (mode=" & to_string(mode) & ") test successfully";
  264. s_test_done(mode+4) <= true;
  265. wait;
  266. end process SpiMasterP;
  267. SpiSlaveStimP : process is
  268. variable v_random : RandomPType;
  269. begin
  270. v_random.InitSeed(v_random'instance_name);
  271. s_din_valid <= '0';
  272. s_din <= (others => '0');
  273. wait until s_reset_n = '1';
  274. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  275. s_din <= v_random.RandSlv(C_DATA_WIDTH);
  276. s_din_valid <= '1';
  277. wait until rising_edge(s_clk) and s_din_accept = '1';
  278. s_din_valid <= '0';
  279. sv_miso_queue.push(s_din);
  280. wait until rising_edge(s_clk) and s_dout_valid = '1';
  281. end loop;
  282. wait;
  283. end process SpiSlaveStimP;
  284. i_SpiSlaveE : SpiSlaveE
  285. generic map (
  286. G_DATA_WIDTH => C_DATA_WIDTH,
  287. G_DATA_DIR => 1,
  288. G_SPI_CPOL => mode / 2,
  289. G_SPI_CPHA => mode mod 2
  290. )
  291. port map (
  292. --+ system if
  293. Reset_n_i => s_reset_n,
  294. Clk_i => s_clk,
  295. --+ SPI slave if
  296. SpiSclk_i => s_sclk,
  297. SpiSte_i => s_ste,
  298. SpiMosi_i => s_mosi,
  299. SpiMiso_o => s_miso,
  300. --+ local VAI if
  301. Data_i => s_din,
  302. DataValid_i => s_din_valid,
  303. DataAccept_o => s_din_accept,
  304. Data_o => s_dout,
  305. DataValid_o => s_dout_valid,
  306. DataAccept_i => s_dout_accept
  307. );
  308. SpiSlaveCheckP : process is
  309. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  310. begin
  311. s_dout_accept <= '0';
  312. wait until s_reset_n = '1';
  313. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  314. wait until rising_edge(s_clk) and s_dout_valid = '1';
  315. s_dout_accept <= '1';
  316. sv_mosi_queue.pop(v_queue_data);
  317. assert_equal(s_dout, v_queue_data);
  318. wait until rising_edge(s_clk);
  319. s_dout_accept <= '0';
  320. end loop;
  321. wait;
  322. end process SpiSlaveCheckP;
  323. end generate SpiSlavesG;
  324. end architecture sim;