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.

353 lines
10 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_SPI_CPOL : natural range 0 to 1 := 0;
  24. G_SPI_CPHA : natural range 0 to 1 := 0;
  25. G_SCLK_DIVIDER : positive range 6 to positive'high := 10
  26. );
  27. port (
  28. --+ system if
  29. Reset_n_i : in std_logic;
  30. Clk_i : in std_logic;
  31. --+ SPI slave if
  32. SpiSclk_o : out std_logic;
  33. SpiSte_o : out std_logic;
  34. SpiMosi_o : out std_logic;
  35. SpiMiso_i : in std_logic;
  36. --+ local VAI if
  37. Data_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0);
  38. DataValid_i : in std_logic;
  39. DataAccept_o : out std_logic;
  40. Data_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0);
  41. DataValid_o : out std_logic;
  42. DataAccept_i : in std_logic
  43. );
  44. end component SpiMasterE;
  45. component SpiSlaveE is
  46. generic (
  47. G_DATA_WIDTH : positive := 8;
  48. G_SPI_CPOL : natural range 0 to 1 := 0;
  49. G_SPI_CPHA : natural range 0 to 1 := 0
  50. );
  51. port (
  52. --+ system if
  53. Reset_n_i : in std_logic;
  54. Clk_i : in std_logic;
  55. --+ SPI slave if
  56. SpiSclk_i : in std_logic;
  57. SpiSte_i : in std_logic;
  58. SpiMosi_i : in std_logic;
  59. SpiMiso_o : out std_logic;
  60. --+ local VAI if
  61. Data_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0);
  62. DataValid_i : in std_logic;
  63. DataAccept_o : out std_logic;
  64. Data_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0);
  65. DataValid_o : out std_logic;
  66. DataAccept_i : in std_logic
  67. );
  68. end component SpiSlaveE;
  69. --* testbench global clock period
  70. constant C_PERIOD : time := 5 ns;
  71. --* SPI data transfer data width
  72. constant C_DATA_WIDTH : natural := 8;
  73. --* testbench global clock
  74. signal s_clk : std_logic := '0';
  75. --* testbench global reset
  76. signal s_reset_n : std_logic := '0';
  77. --* SPI mode range subtype
  78. subtype t_spi_mode is natural range 0 to 3;
  79. --+ test done array with entry for each test
  80. signal s_test_done : boolean_vector(t_spi_mode'low to 2*t_spi_mode'high+1) := (others => false);
  81. begin
  82. --* testbench global clock
  83. s_clk <= not(s_clk) after C_PERIOD/2 when not(and_reduce(s_test_done)) else '0';
  84. --* testbench global reset
  85. s_reset_n <= '1' after 100 ns;
  86. --+ SpiMasterE tests for all 4 modes
  87. SpiMastersG : for mode in t_spi_mode'low to t_spi_mode'high generate
  88. signal s_sclk : std_logic;
  89. signal s_ste : std_logic;
  90. signal s_mosi : std_logic;
  91. signal s_miso : std_logic;
  92. signal s_din : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  93. signal s_din_valid : std_logic;
  94. signal s_din_accept : std_logic;
  95. signal s_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  96. signal s_dout_valid : std_logic;
  97. signal s_dout_accept : std_logic;
  98. shared variable sv_mosi_queue : t_list_queue;
  99. shared variable sv_miso_queue : t_list_queue;
  100. begin
  101. SpiMasterStimP : process is
  102. variable v_random : RandomPType;
  103. begin
  104. v_random.InitSeed(v_random'instance_name);
  105. s_din_valid <= '0';
  106. s_din <= (others => '0');
  107. wait until s_reset_n = '1';
  108. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  109. s_din <= v_random.RandSlv(C_DATA_WIDTH);
  110. s_din_valid <= '1';
  111. wait until rising_edge(s_clk) and s_din_accept = '1';
  112. s_din_valid <= '0';
  113. sv_mosi_queue.push(s_din);
  114. wait until rising_edge(s_clk);
  115. end loop;
  116. wait;
  117. end process SpiMasterStimP;
  118. i_SpiMasterE : SpiMasterE
  119. generic map (
  120. G_DATA_WIDTH => C_DATA_WIDTH,
  121. G_SPI_CPOL => mode / 2,
  122. G_SPI_CPHA => mode mod 2,
  123. G_SCLK_DIVIDER => 10
  124. )
  125. port map (
  126. --+ system if
  127. Reset_n_i => s_reset_n,
  128. Clk_i => s_clk,
  129. --+ SPI slave if
  130. SpiSclk_o => s_sclk,
  131. SpiSte_o => s_ste,
  132. SpiMosi_o => s_mosi,
  133. SpiMiso_i => s_miso,
  134. --+ local VAI if
  135. Data_i => s_din,
  136. DataValid_i => s_din_valid,
  137. DataAccept_o => s_din_accept,
  138. Data_o => s_dout,
  139. DataValid_o => s_dout_valid,
  140. DataAccept_i => s_dout_accept
  141. );
  142. SpiMasterCheckP : process is
  143. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  144. begin
  145. s_dout_accept <= '0';
  146. wait until s_reset_n = '1';
  147. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  148. wait until rising_edge(s_clk) and s_dout_valid = '1';
  149. s_dout_accept <= '1';
  150. sv_miso_queue.pop(v_queue_data);
  151. assert_equal(s_dout, v_queue_data);
  152. wait until rising_edge(s_clk);
  153. s_dout_accept <= '0';
  154. end loop;
  155. report "INFO: SpiMaster (mode=" & to_string(mode) & ") test successfully";
  156. s_test_done(mode) <= true;
  157. wait;
  158. end process SpiMasterCheckP;
  159. -- Unit test of spi slave procedure, checks all combinations
  160. -- of cpol & cpha against spi master procedure
  161. SpiSlaveP : process is
  162. variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  163. variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  164. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  165. variable v_random : RandomPType;
  166. begin
  167. v_random.InitSeed(v_random'instance_name);
  168. wait until s_reset_n = '1';
  169. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  170. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  171. sv_miso_queue.push(v_send_data);
  172. spi_slave (data_in => v_send_data,
  173. data_out => v_receive_data,
  174. sclk => s_sclk,
  175. ste => s_ste,
  176. mosi => s_mosi,
  177. miso => s_miso,
  178. cpol => mode / 2,
  179. cpha => mode mod 2
  180. );
  181. sv_mosi_queue.pop(v_queue_data);
  182. assert_equal(v_receive_data, v_queue_data);
  183. end loop;
  184. wait;
  185. end process SpiSlaveP;
  186. end generate SpiMastersG;
  187. --+ SpiSlaveE tests for all 4 modes
  188. SpiSlavesG : for mode in t_spi_mode'low to t_spi_mode'high generate
  189. signal s_sclk : std_logic;
  190. signal s_ste : std_logic;
  191. signal s_mosi : std_logic;
  192. signal s_miso : std_logic;
  193. signal s_din : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  194. signal s_din_valid : std_logic;
  195. signal s_din_accept : std_logic;
  196. signal s_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  197. signal s_dout_valid : std_logic;
  198. signal s_dout_accept : std_logic;
  199. shared variable sv_mosi_queue : t_list_queue;
  200. shared variable sv_miso_queue : t_list_queue;
  201. begin
  202. --* Unit test of spi master procedure, checks all combinations
  203. --* of cpol & cpha against spi slave procedure
  204. SpiMasterP : process is
  205. variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  206. variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  207. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  208. variable v_random : RandomPType;
  209. begin
  210. v_random.InitSeed(v_random'instance_name);
  211. s_sclk <= '1';
  212. s_ste <= '1';
  213. s_mosi <= '1';
  214. wait until s_reset_n = '1';
  215. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  216. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  217. sv_mosi_queue.push(v_send_data);
  218. spi_master (data_in => v_send_data,
  219. data_out => v_receive_data,
  220. sclk => s_sclk,
  221. ste => s_ste,
  222. mosi => s_mosi,
  223. miso => s_miso,
  224. cpol => mode / 2,
  225. cpha => mode mod 2,
  226. period => 100 ns
  227. );
  228. sv_miso_queue.pop(v_queue_data);
  229. assert_equal(v_receive_data, v_queue_data);
  230. end loop;
  231. report "INFO: SpiSlave (mode=" & to_string(mode) & ") test successfully";
  232. s_test_done(mode+4) <= true;
  233. wait;
  234. end process SpiMasterP;
  235. SpiSlaveStimP : process is
  236. variable v_random : RandomPType;
  237. begin
  238. v_random.InitSeed(v_random'instance_name);
  239. s_din_valid <= '0';
  240. s_din <= (others => '0');
  241. wait until s_reset_n = '1';
  242. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  243. s_din <= v_random.RandSlv(C_DATA_WIDTH);
  244. s_din_valid <= '1';
  245. wait until rising_edge(s_clk) and s_din_accept = '1';
  246. s_din_valid <= '0';
  247. sv_miso_queue.push(s_din);
  248. wait until rising_edge(s_clk) and s_dout_valid = '1';
  249. end loop;
  250. wait;
  251. end process SpiSlaveStimP;
  252. i_SpiSlaveE : SpiSlaveE
  253. generic map (
  254. G_DATA_WIDTH => C_DATA_WIDTH,
  255. G_SPI_CPOL => mode / 2,
  256. G_SPI_CPHA => mode mod 2
  257. )
  258. port map (
  259. --+ system if
  260. Reset_n_i => s_reset_n,
  261. Clk_i => s_clk,
  262. --+ SPI slave if
  263. SpiSclk_i => s_sclk,
  264. SpiSte_i => s_ste,
  265. SpiMosi_i => s_mosi,
  266. SpiMiso_o => s_miso,
  267. --+ local VAI if
  268. Data_i => s_din,
  269. DataValid_i => s_din_valid,
  270. DataAccept_o => s_din_accept,
  271. Data_o => s_dout,
  272. DataValid_o => s_dout_valid,
  273. DataAccept_i => s_dout_accept
  274. );
  275. SpiSlaveCheckP : process is
  276. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  277. begin
  278. s_dout_accept <= '0';
  279. wait until s_reset_n = '1';
  280. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  281. wait until rising_edge(s_clk) and s_dout_valid = '1';
  282. s_dout_accept <= '1';
  283. sv_mosi_queue.pop(v_queue_data);
  284. assert_equal(s_dout, v_queue_data);
  285. wait until rising_edge(s_clk);
  286. s_dout_accept <= '0';
  287. end loop;
  288. wait;
  289. end process SpiSlaveCheckP;
  290. end generate SpiSlavesG;
  291. end architecture sim;