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.

306 lines
8.9 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 := 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. --+ spi ste demultiplexing
  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. wait until s_reset_n = '1';
  106. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  107. s_din <= v_random.RandSlv(C_DATA_WIDTH);
  108. s_din_valid <= '1';
  109. wait until rising_edge(s_clk) and s_din_accept = '1';
  110. s_din_valid <= '0';
  111. sv_mosi_queue.push(s_din);
  112. wait until rising_edge(s_clk);
  113. end loop;
  114. wait;
  115. end process SpiMasterStimP;
  116. i_SpiMasterE : SpiMasterE
  117. generic map (
  118. G_DATA_WIDTH => 8,
  119. G_SPI_CPOL => mode / 2,
  120. G_SPI_CPHA => mode mod 2,
  121. G_SCLK_DIVIDER => 10
  122. )
  123. port map (
  124. --+ system if
  125. Reset_n_i => s_reset_n,
  126. Clk_i => s_clk,
  127. --+ SPI slave if
  128. SpiSclk_o => s_sclk,
  129. SpiSte_o => s_ste,
  130. SpiMosi_o => s_mosi,
  131. SpiMiso_i => s_miso,
  132. --+ local VAI if
  133. Data_i => s_din,
  134. DataValid_i => s_din_valid,
  135. DataAccept_o => s_din_accept,
  136. Data_o => s_dout,
  137. DataValid_o => s_dout_valid,
  138. DataAccept_i => s_dout_accept
  139. );
  140. SpiMasterCheckP : process is
  141. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  142. begin
  143. wait until s_reset_n = '1';
  144. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  145. wait until rising_edge(s_clk) and s_dout_valid = '1';
  146. s_dout_accept <= '1';
  147. sv_miso_queue.pop(v_queue_data);
  148. assert_equal(s_dout, v_queue_data);
  149. wait until rising_edge(s_clk);
  150. s_dout_accept <= '0';
  151. end loop;
  152. report "INFO: SpiMaster (mode=" & to_string(mode) & ") test successfully";
  153. s_test_done(mode) <= true;
  154. wait;
  155. end process SpiMasterCheckP;
  156. -- Unit test of spi slave procedure, checks all combinations
  157. -- of cpol & cpha against spi master procedure
  158. SpiSlaveP : process is
  159. variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  160. variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  161. variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  162. variable v_random : RandomPType;
  163. begin
  164. v_random.InitSeed(v_random'instance_name);
  165. wait until s_reset_n = '1';
  166. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  167. v_send_data := v_random.RandSlv(C_DATA_WIDTH);
  168. sv_miso_queue.push(v_send_data);
  169. spi_slave (data_in => v_send_data,
  170. data_out => v_receive_data,
  171. sclk => s_sclk,
  172. ste => s_ste,
  173. mosi => s_mosi,
  174. miso => s_miso,
  175. cpol => mode / 2,
  176. cpha => mode mod 2
  177. );
  178. sv_mosi_queue.pop(v_queue_data);
  179. assert_equal(v_receive_data, v_queue_data);
  180. end loop;
  181. wait;
  182. end process SpiSlaveP;
  183. end generate SpiMastersG;
  184. --+ spi ste demultiplexing
  185. SpiSlavesG : for mode in t_spi_mode'low to t_spi_mode'high generate
  186. signal s_sclk : std_logic;
  187. signal s_ste : std_logic;
  188. signal s_mosi : std_logic;
  189. signal s_miso : std_logic;
  190. signal s_din : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  191. signal s_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0);
  192. signal s_dout_valid : std_logic;
  193. signal s_dout_accept : std_logic;
  194. begin
  195. -- Unit test of spi master procedure, checks all combinations
  196. -- of cpol & cpha against spi slave procedure
  197. SpiMasterP : process is
  198. variable v_slave_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0');
  199. begin
  200. s_sclk <= '1';
  201. s_ste <= '1';
  202. s_mosi <= '1';
  203. wait until s_reset_n = '1';
  204. for i in 0 to integer'(2**C_DATA_WIDTH-1) loop
  205. spi_master (data_in => std_logic_vector(to_unsigned(i, C_DATA_WIDTH)),
  206. data_out => v_slave_data,
  207. sclk => s_sclk,
  208. ste => s_ste,
  209. mosi => s_mosi,
  210. miso => s_miso,
  211. cpol => mode / 2,
  212. cpha => mode mod 2,
  213. period => 100 ns
  214. );
  215. assert_equal(v_slave_data, std_logic_vector(to_unsigned(i, C_DATA_WIDTH)));
  216. end loop;
  217. report "INFO: SpiSlave (mode=" & to_string(mode) & ") test successfully";
  218. s_test_done(mode+4) <= true;
  219. wait;
  220. end process SpiMasterP;
  221. s_din <= std_logic_vector(unsigned(s_dout) + 1);
  222. i_SpiSlaveE : SpiSlaveE
  223. generic map (
  224. G_DATA_WIDTH => 8,
  225. G_SPI_CPOL => mode / 2,
  226. G_SPI_CPHA => mode mod 2
  227. )
  228. port map (
  229. --+ system if
  230. Reset_n_i => s_reset_n,
  231. Clk_i => s_clk,
  232. --+ SPI slave if
  233. SpiSclk_i => s_sclk,
  234. SpiSte_i => s_ste,
  235. SpiMosi_i => s_mosi,
  236. SpiMiso_o => s_miso,
  237. --+ local VAI if
  238. Data_i => s_din,
  239. DataValid_i => s_dout_valid,
  240. DataAccept_o => s_dout_accept,
  241. Data_o => s_dout,
  242. DataValid_o => s_dout_valid,
  243. DataAccept_i => s_dout_accept
  244. );
  245. end generate SpiSlavesG;
  246. end architecture sim;