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.

222 lines
6.7 KiB

  1. -- Copyright (c) 2014 - 2022 by Torsten Meissner
  2. --
  3. -- Licensed under the Apache License, Version 2.0 (the "License");
  4. -- you may not use this file except in compliance with the License.
  5. -- You may obtain a copy of the License at
  6. --
  7. -- https://www.apache.org/licenses/LICENSE-2.0
  8. --
  9. -- Unless required by applicable law or agreed to in writing, software
  10. -- distributed under the License is distributed on an "AS IS" BASIS,
  11. -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. -- See the License for the specific language governing permissions and
  13. -- limitations under the License.
  14. library ieee;
  15. use ieee.std_logic_1164.all;
  16. use ieee.numeric_std.all;
  17. entity SpiSlaveE is
  18. generic (
  19. G_DATA_WIDTH : positive := 8; --* data bus width
  20. G_DATA_DIR : natural range 0 to 1 := 0; --* start from lsb/msb 0/1
  21. G_SPI_CPOL : natural range 0 to 1 := 0; --* SPI clock polarity
  22. G_SPI_CPHA : natural range 0 to 1 := 0 --* SPI clock phase
  23. );
  24. port (
  25. --+ system if
  26. Reset_n_i : in std_logic;
  27. Clk_i : in std_logic;
  28. --+ SPI slave if
  29. SpiSclk_i : in std_logic;
  30. SpiSte_i : in std_logic;
  31. SpiMosi_i : in std_logic;
  32. SpiMiso_o : out std_logic;
  33. --+ local VAI if
  34. Data_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0);
  35. DataValid_i : in std_logic;
  36. DataAccept_o : out std_logic;
  37. Data_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0);
  38. DataValid_o : out std_logic;
  39. DataAccept_i : in std_logic
  40. );
  41. end entity SpiSlaveE;
  42. architecture rtl of SpiSlaveE is
  43. type t_spi_state is (IDLE, TRANSFER, STORE);
  44. signal s_spi_state : t_spi_state;
  45. signal s_send_register : std_logic_vector(G_DATA_WIDTH-1 downto 0);
  46. signal s_recv_register : std_logic_vector(G_DATA_WIDTH-1 downto 0);
  47. signal s_sclk_d : std_logic_vector(2 downto 0);
  48. signal s_ste_d : std_logic_vector(2 downto 0);
  49. signal s_mosi_d : std_logic_vector(2 downto 0);
  50. signal s_miso : std_logic;
  51. signal s_data_valid : std_logic;
  52. signal s_transfer_valid : boolean;
  53. signal s_sclk_rising : boolean;
  54. signal s_sclk_falling : boolean;
  55. signal s_read_edge : boolean;
  56. signal s_write_edge : boolean;
  57. alias a_ste : std_logic is s_ste_d(s_ste_d'left);
  58. alias a_mosi : std_logic is s_mosi_d(s_mosi_d'left);
  59. constant C_BIT_COUNTER_START : natural := (G_DATA_WIDTH-1) * G_DATA_DIR;
  60. constant C_BIT_COUNTER_END : natural := (G_DATA_WIDTH-1) * to_integer(not(to_unsigned(G_DATA_DIR, 1)));
  61. begin
  62. --* help signals for edge detection on sclk
  63. s_sclk_rising <= true when s_sclk_d(2 downto 1) = "01" else false;
  64. s_sclk_falling <= true when s_sclk_d(2 downto 1) = "10" else false;
  65. s_read_edge <= s_sclk_rising when G_SPI_CPOL = G_SPI_CPHA else s_sclk_falling;
  66. s_write_edge <= s_sclk_falling when G_SPI_CPOL = G_SPI_CPHA else s_sclk_rising;
  67. --* Sync asynchronous SPI inputs with 3 stage FF line
  68. --* We use 3 FF because of edge detection on sclk line
  69. --* Mosi & ste are also registered with 3 FF to stay in
  70. --* sync with registered sclk
  71. SpiSyncP : process (Reset_n_i, Clk_i) is
  72. begin
  73. if (Reset_n_i = '0') then
  74. if (G_SPI_CPOL = 0) then
  75. s_sclk_d <= (others => '0');
  76. else
  77. s_sclk_d <= (others => '1');
  78. end if;
  79. s_ste_d <= (others => '1');
  80. s_mosi_d <= (others => '0');
  81. elsif rising_edge(Clk_i) then
  82. s_sclk_d <= s_sclk_d(1 downto 0) & SpiSclk_i;
  83. s_ste_d <= s_ste_d(1 downto 0) & SpiSte_i;
  84. s_mosi_d <= s_mosi_d(1 downto 0) & SpiMosi_i;
  85. end if;
  86. end process SpiSyncP;
  87. --* Save local data input when new data is provided and
  88. --* we're not inside a running SPI transmission
  89. --* Beware: Last saved data before a started SPI transmission "wins"
  90. SendRegisterP : process (Reset_n_i, Clk_i) is
  91. begin
  92. if (Reset_n_i = '0') then
  93. s_send_register <= (others => '0');
  94. DataAccept_o <= '0';
  95. elsif rising_edge(Clk_i) then
  96. DataAccept_o <= '0';
  97. if (DataValid_i = '1' and s_spi_state = IDLE) then
  98. s_send_register <= Data_i;
  99. DataAccept_o <= '1';
  100. end if;
  101. end if;
  102. end process SendRegisterP;
  103. --* Spi slave control FSM
  104. SpiControlP : process (Reset_n_i, Clk_i) is
  105. variable v_bit_counter : natural range 0 to G_DATA_WIDTH-1;
  106. begin
  107. if (Reset_n_i = '0') then
  108. s_miso <= '0';
  109. s_recv_register <= (others => '0');
  110. v_bit_counter := C_BIT_COUNTER_START;
  111. s_transfer_valid <= false;
  112. s_spi_state <= IDLE;
  113. elsif rising_edge(Clk_i) then
  114. case s_spi_state is
  115. when IDLE =>
  116. s_miso <= '0';
  117. s_recv_register <= (others => '0');
  118. v_bit_counter := C_BIT_COUNTER_START;
  119. s_transfer_valid <= false;
  120. if (a_ste = '0') then
  121. if (G_SPI_CPHA = 0) then
  122. s_miso <= s_send_register(v_bit_counter);
  123. end if;
  124. s_spi_state <= TRANSFER;
  125. end if;
  126. when TRANSFER =>
  127. if s_read_edge then
  128. s_recv_register(v_bit_counter) <= a_mosi;
  129. if (v_bit_counter = C_BIT_COUNTER_END) then
  130. s_spi_state <= STORE;
  131. else
  132. if (G_DATA_DIR = 0) then
  133. v_bit_counter := v_bit_counter + 1;
  134. else
  135. v_bit_counter := v_bit_counter - 1;
  136. end if;
  137. end if;
  138. elsif s_write_edge then
  139. s_miso <= s_send_register(v_bit_counter);
  140. else
  141. if (a_ste = '1') then
  142. s_spi_state <= IDLE;
  143. end if;
  144. end if;
  145. when STORE =>
  146. if (a_ste = '1') then
  147. s_transfer_valid <= true;
  148. s_spi_state <= IDLE;
  149. end if;
  150. when others =>
  151. s_spi_state <= IDLE;
  152. end case;
  153. end if;
  154. end process SpiControlP;
  155. --* Provide received SPI data to local interface
  156. --* Output data is overwritten if it isn't fetched
  157. --* until next finished SPI transmission
  158. RecvRegisterP : process (Reset_n_i, Clk_i) is
  159. begin
  160. if (Reset_n_i = '0') then
  161. Data_o <= (others => '0');
  162. s_data_valid <= '0';
  163. elsif rising_edge(Clk_i) then
  164. if (s_transfer_valid) then
  165. Data_o <= s_recv_register;
  166. s_data_valid <= '1';
  167. end if;
  168. if (DataAccept_i = '1' and s_data_valid = '1') then
  169. s_data_valid <= '0';
  170. end if;
  171. end if;
  172. end process RecvRegisterP;
  173. --+ Output port connections
  174. DataValid_o <= s_data_valid;
  175. SpiMiso_o <= 'Z' when SpiSte_i = '1' else s_miso;
  176. -- psl default clock is rising_edge(Clk_i);
  177. --
  178. -- psl assert always (s_spi_state = IDLE or s_spi_state = TRANSFER or s_spi_state = STORE);
  179. -- psl assert always (s_data_valid and DataAccept_i) -> next not(s_data_valid);
  180. end architecture rtl;