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.

394 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. wait until s_reset_n = '1';
  203. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  204. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  205. sv_miso_queue.push(v_send_data);
  206. spi_slave (data_in => v_send_data,
  207. data_out => v_receive_data,
  208. sclk => s_sclk,
  209. ste => s_ste,
  210. mosi => s_mosi,
  211. miso => s_miso,
  212. dir => direction,
  213. cpol => mode / 2,
  214. cpha => mode mod 2
  215. );
  216. sv_mosi_queue.pop(v_queue_data);
  217. assert_equal(v_receive_data, v_queue_data);
  218. end loop;
  219. wait;
  220. end process SpiSlaveP;
  221. end generate SpiMastersG;
  222. --* Generate SpiMasterE tests for all 4 modes
  223. SpiSlavesG : for mode in t_spi_mode'low to t_spi_mode'high generate
  224. signal s_sclk : std_logic;
  225. signal s_ste : std_logic;
  226. signal s_mosi : std_logic;
  227. signal s_miso : std_logic;
  228. signal s_din : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  229. signal s_din_valid : std_logic;
  230. signal s_din_accept : std_logic;
  231. signal s_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  232. signal s_dout_valid : std_logic;
  233. signal s_dout_accept : std_logic;
  234. shared variable sv_mosi_queue : t_list_queue;
  235. shared variable sv_miso_queue : t_list_queue;
  236. begin
  237. --* Unit test of spi master procedure, checks all combinations
  238. --* of cpol & cpha against spi slave procedure
  239. SpiMasterP : process is
  240. variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  241. variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  242. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  243. variable v_random : RandomPType;
  244. begin
  245. v_random.InitSeed(v_random'instance_name);
  246. s_sclk <= '1';
  247. s_ste <= '1';
  248. s_mosi <= '1';
  249. wait until s_reset_n = '1';
  250. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  251. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  252. sv_mosi_queue.push(v_send_data);
  253. spi_master (data_in => v_send_data,
  254. data_out => v_receive_data,
  255. sclk => s_sclk,
  256. ste => s_ste,
  257. mosi => s_mosi,
  258. miso => s_miso,
  259. dir => direction,
  260. cpol => mode / 2,
  261. cpha => mode mod 2,
  262. period => C_PERIOD * 10
  263. );
  264. sv_miso_queue.pop(v_queue_data);
  265. assert_equal(v_receive_data, v_queue_data);
  266. end loop;
  267. report "INFO: SpiSlave (direction=" & to_string(direction) & ", mode=" & to_string(mode) & ") test successfully";
  268. s_test_done(mode+8+direction*4) <= true;
  269. wait;
  270. end process SpiMasterP;
  271. SpiSlaveStimP : process is
  272. variable v_random : RandomPType;
  273. begin
  274. v_random.InitSeed(v_random'instance_name);
  275. s_din_valid <= '0';
  276. s_din <= (others => '0');
  277. wait until s_reset_n = '1';
  278. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  279. s_din <= v_random.RandSlv(C_DATA_WIDTH);
  280. s_din_valid <= '1';
  281. wait until rising_edge(s_clk) and s_din_accept = '1';
  282. s_din_valid <= '0';
  283. sv_miso_queue.push(s_din);
  284. wait until rising_edge(s_clk) and s_dout_valid = '1';
  285. end loop;
  286. wait;
  287. end process SpiSlaveStimP;
  288. i_SpiSlaveE : SpiSlaveE
  289. generic map (
  290. G_DATA_WIDTH => C_DATA_WIDTH,
  291. G_DATA_DIR => direction,
  292. G_SPI_CPOL => mode / 2,
  293. G_SPI_CPHA => mode mod 2
  294. )
  295. port map (
  296. --+ system if
  297. Reset_n_i => s_reset_n,
  298. Clk_i => s_clk,
  299. --+ SPI slave if
  300. SpiSclk_i => s_sclk,
  301. SpiSte_i => s_ste,
  302. SpiMosi_i => s_mosi,
  303. SpiMiso_o => s_miso,
  304. --+ local VAI if
  305. Data_i => s_din,
  306. DataValid_i => s_din_valid,
  307. DataAccept_o => s_din_accept,
  308. Data_o => s_dout,
  309. DataValid_o => s_dout_valid,
  310. DataAccept_i => s_dout_accept
  311. );
  312. SpiSlaveCheckP : process is
  313. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  314. begin
  315. s_dout_accept <= '0';
  316. wait until s_reset_n = '1';
  317. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  318. wait until rising_edge(s_clk) and s_dout_valid = '1';
  319. s_dout_accept <= '1';
  320. sv_mosi_queue.pop(v_queue_data);
  321. assert_equal(s_dout, v_queue_data);
  322. wait until rising_edge(s_clk);
  323. s_dout_accept <= '0';
  324. end loop;
  325. wait;
  326. end process SpiSlaveCheckP;
  327. end generate SpiSlavesG;
  328. end generate DataDirectionG;
  329. end architecture sim;