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.

395 lines
13 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 4*t_spi_mode'high+3) := (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. --* Generate tests for both direction
  89. DataDirectionG : for direction in 0 to 1 generate
  90. --* Generate SpiMasterE tests for all 4 modes
  91. SpiMastersG : for mode in t_spi_mode'low to t_spi_mode'high generate
  92. signal s_sclk : std_logic;
  93. signal s_ste : std_logic;
  94. signal s_mosi : std_logic;
  95. signal s_miso : std_logic;
  96. signal s_din : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  97. signal s_din_valid : std_logic;
  98. signal s_din_accept : std_logic;
  99. signal s_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  100. signal s_dout_valid : std_logic;
  101. signal s_dout_accept : std_logic;
  102. shared variable sv_mosi_queue : t_list_queue;
  103. shared variable sv_miso_queue : t_list_queue;
  104. begin
  105. --* Stimuli generator and BFM for the valid-accept interface
  106. --* on the local data input of the DUT
  107. --*
  108. --* Generates random stimuli and serves it to the
  109. --* valid-accept interface at the input of the DUT
  110. --*
  111. --* The stimuli data is also pushed into the mosi queue
  112. --* which serves as simple abstract reference model
  113. --* of the SPI transmit (master -> slave) channel
  114. SpiMasterStimP : process is
  115. variable v_random : RandomPType;
  116. begin
  117. v_random.InitSeed(v_random'instance_name);
  118. s_din_valid <= '0';
  119. s_din <= (others => '0');
  120. wait until s_reset_n = '1';
  121. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  122. s_din <= v_random.RandSlv(C_DATA_WIDTH);
  123. s_din_valid <= '1';
  124. wait until rising_edge(s_clk) and s_din_accept = '1';
  125. s_din_valid <= '0';
  126. sv_mosi_queue.push(s_din);
  127. wait until rising_edge(s_clk);
  128. end loop;
  129. wait;
  130. end process SpiMasterStimP;
  131. --* DUT: SpiMasterE component
  132. i_SpiMasterE : SpiMasterE
  133. generic map (
  134. G_DATA_WIDTH => C_DATA_WIDTH,
  135. G_DATA_DIR => direction,
  136. G_SPI_CPOL => mode / 2,
  137. G_SPI_CPHA => mode mod 2,
  138. G_SCLK_DIVIDER => 10
  139. )
  140. port map (
  141. --+ system if
  142. Reset_n_i => s_reset_n,
  143. Clk_i => s_clk,
  144. --+ SPI slave if
  145. SpiSclk_o => s_sclk,
  146. SpiSte_o => s_ste,
  147. SpiMosi_o => s_mosi,
  148. SpiMiso_i => s_miso,
  149. --+ local VAI if
  150. Data_i => s_din,
  151. DataValid_i => s_din_valid,
  152. DataAccept_o => s_din_accept,
  153. Data_o => s_dout,
  154. DataValid_o => s_dout_valid,
  155. DataAccept_i => s_dout_accept
  156. );
  157. --* Checker and BFM for the valid-accept interface
  158. --* on the local data output of the DUT
  159. --*
  160. --* Reads the output of the DUT and compares it to
  161. --* data popped from the miso queue which serves as
  162. --* simple abstract reference model of the SPI receive
  163. --* (slave -> master) channel
  164. SpiMasterCheckP : process is
  165. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  166. begin
  167. s_dout_accept <= '0';
  168. wait until s_reset_n = '1';
  169. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  170. wait until rising_edge(s_clk) and s_dout_valid = '1';
  171. s_dout_accept <= '1';
  172. sv_miso_queue.pop(v_queue_data);
  173. assert_equal(s_dout, v_queue_data);
  174. wait until rising_edge(s_clk);
  175. s_dout_accept <= '0';
  176. end loop;
  177. report "INFO: SpiMaster (direction=" & to_string(direction) & ", mode=" & to_string(mode) & ") test successfully";
  178. s_test_done(mode+direction*4) <= true;
  179. wait;
  180. end process SpiMasterCheckP;
  181. --* Stimuli generator and BFM for the SPI slave
  182. --* interface on the SPI miso input of the DUT
  183. --*
  184. --* Generates random stimuli and serves it to the
  185. --* SPI interface at the input of the DUT
  186. --*
  187. --* The stimuli data is also pushed into the miso queue
  188. --* which serves as simple abstract reference model
  189. --* of the SPI receive (slave -> master) channel
  190. --*
  191. --* Furthermore the data received by the SPI slave BFM
  192. --* is checked against data popped from the mosi queue
  193. --* which serves as simple abstract reference model of
  194. --* the SPI receive (master -> slave) channel
  195. SpiSlaveP : process is
  196. variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  197. variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  198. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  199. variable v_random : RandomPType;
  200. begin
  201. v_random.InitSeed(v_random'instance_name);
  202. s_miso <= 'Z';
  203. wait until s_reset_n = '1';
  204. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  205. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  206. sv_miso_queue.push(v_send_data);
  207. spi_slave (data_in => v_send_data,
  208. data_out => v_receive_data,
  209. sclk => s_sclk,
  210. ste => s_ste,
  211. mosi => s_mosi,
  212. miso => s_miso,
  213. dir => direction,
  214. cpol => mode / 2,
  215. cpha => mode mod 2
  216. );
  217. sv_mosi_queue.pop(v_queue_data);
  218. assert_equal(v_receive_data, v_queue_data);
  219. end loop;
  220. wait;
  221. end process SpiSlaveP;
  222. end generate SpiMastersG;
  223. --* Generate SpiMasterE tests for all 4 modes
  224. SpiSlavesG : for mode in t_spi_mode'low to t_spi_mode'high generate
  225. signal s_sclk : std_logic;
  226. signal s_ste : std_logic;
  227. signal s_mosi : std_logic;
  228. signal s_miso : std_logic;
  229. signal s_din : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  230. signal s_din_valid : std_logic;
  231. signal s_din_accept : std_logic;
  232. signal s_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  233. signal s_dout_valid : std_logic;
  234. signal s_dout_accept : std_logic;
  235. shared variable sv_mosi_queue : t_list_queue;
  236. shared variable sv_miso_queue : t_list_queue;
  237. begin
  238. --* Unit test of spi master procedure, checks all combinations
  239. --* of cpol & cpha against spi slave procedure
  240. SpiMasterP : process is
  241. variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  242. variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  243. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  244. variable v_random : RandomPType;
  245. begin
  246. v_random.InitSeed(v_random'instance_name);
  247. s_sclk <= '1';
  248. s_ste <= '1';
  249. s_mosi <= '1';
  250. wait until s_reset_n = '1';
  251. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  252. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  253. sv_mosi_queue.push(v_send_data);
  254. spi_master (data_in => v_send_data,
  255. data_out => v_receive_data,
  256. sclk => s_sclk,
  257. ste => s_ste,
  258. mosi => s_mosi,
  259. miso => s_miso,
  260. dir => direction,
  261. cpol => mode / 2,
  262. cpha => mode mod 2,
  263. period => C_PERIOD * 10
  264. );
  265. sv_miso_queue.pop(v_queue_data);
  266. assert_equal(v_receive_data, v_queue_data);
  267. end loop;
  268. report "INFO: SpiSlave (direction=" & to_string(direction) & ", mode=" & to_string(mode) & ") test successfully";
  269. s_test_done(mode+8+direction*4) <= true;
  270. wait;
  271. end process SpiMasterP;
  272. SpiSlaveStimP : process is
  273. variable v_random : RandomPType;
  274. begin
  275. v_random.InitSeed(v_random'instance_name);
  276. s_din_valid <= '0';
  277. s_din <= (others => '0');
  278. wait until s_reset_n = '1';
  279. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  280. s_din <= v_random.RandSlv(C_DATA_WIDTH);
  281. s_din_valid <= '1';
  282. wait until rising_edge(s_clk) and s_din_accept = '1';
  283. s_din_valid <= '0';
  284. sv_miso_queue.push(s_din);
  285. wait until rising_edge(s_clk) and s_dout_valid = '1';
  286. end loop;
  287. wait;
  288. end process SpiSlaveStimP;
  289. i_SpiSlaveE : SpiSlaveE
  290. generic map (
  291. G_DATA_WIDTH => C_DATA_WIDTH,
  292. G_DATA_DIR => direction,
  293. G_SPI_CPOL => mode / 2,
  294. G_SPI_CPHA => mode mod 2
  295. )
  296. port map (
  297. --+ system if
  298. Reset_n_i => s_reset_n,
  299. Clk_i => s_clk,
  300. --+ SPI slave if
  301. SpiSclk_i => s_sclk,
  302. SpiSte_i => s_ste,
  303. SpiMosi_i => s_mosi,
  304. SpiMiso_o => s_miso,
  305. --+ local VAI if
  306. Data_i => s_din,
  307. DataValid_i => s_din_valid,
  308. DataAccept_o => s_din_accept,
  309. Data_o => s_dout,
  310. DataValid_o => s_dout_valid,
  311. DataAccept_i => s_dout_accept
  312. );
  313. SpiSlaveCheckP : process is
  314. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  315. begin
  316. s_dout_accept <= '0';
  317. wait until s_reset_n = '1';
  318. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  319. wait until rising_edge(s_clk) and s_dout_valid = '1';
  320. s_dout_accept <= '1';
  321. sv_mosi_queue.pop(v_queue_data);
  322. assert_equal(s_dout, v_queue_data);
  323. wait until rising_edge(s_clk);
  324. s_dout_accept <= '0';
  325. end loop;
  326. wait;
  327. end process SpiSlaveCheckP;
  328. end generate SpiSlavesG;
  329. end generate DataDirectionG;
  330. end architecture sim;