library ieee; use ieee.std_logic_1164.all; use work.spi_pkg.all; entity spi_peripheral is generic ( SIZES : natural_vector := (8, 16); SIZES_2LOG : natural := 1; DIVISORS : natural_vector := (2, 4, 6, 8, 16, 32, 64, 128, 256); DIVISORS_LOG2 : natural := 3; CSN_PULSE_CYCLES : natural := 1 ); port ( address_i : in std_logic_vector(2 downto 0); data_i : in std_logic_vector(31 downto 0); data_o : out std_logic_vector(31 downto 0); write_i : in std_logic; read_i : in std_logic; -- IOs sck_o : out std_logic; miso_i : in std_logic; mosi_o : out std_logic; csn_o : out std_logic; -- Control clk_i : in std_logic; rst_in : in std_logic; rx_data_o : out std_logic_vector(get_max_natural(SIZES) - 1 downto 0); rx_valid_o : out std_logic; tx_ready_o : out std_logic; busy_o : out std_logic; err_lost_rx_data_o : out std_logic); end entity spi_peripheral; architecture a1 of spi_peripheral is constant MAX_SIZE : natural := get_max_natural(SIZES); constant CTRL_ADDRESS : std_logic_vector(2 downto 0) := "000"; constant STATUS_ADDRESS : std_logic_vector(2 downto 0) := "010"; constant DATA_ADDRESS : std_logic_vector(2 downto 0) := "011"; signal rx_buffer : std_logic_vector(MAX_SIZE - 1 downto 0); signal rx_buffer_full : std_logic; signal tx_buffer : std_logic_vector(MAX_SIZE - 1 downto 0); signal tx_buffer_full : std_logic; signal rx_ready : std_logic; signal rx_valid : std_logic; signal tx_valid : std_logic; signal tx_ready : std_logic; signal tx_data : std_logic_vector(MAX_SIZE - 1 downto 0); signal rx_data : std_logic_vector(MAX_SIZE - 1 downto 0); signal rx_data_lost : std_logic; signal busy : std_logic; signal reg_control : std_logic_vector(31 downto 0); signal reg_status : std_logic_vector(31 downto 0); signal clear_rx_buffer_full : std_logic; begin -- architecture a1 reader: process (clk_i) is begin -- process reader if rising_edge(clk_i) then -- rising clock edge if rst_in = '0' then -- synchronous reset (active low) elsif read_i = '1' then case address_i is when DATA_ADDRESS => clear_rx_buffer_full <= '1'; when others => null; end case; else clear_rx_buffer_full <= '0'; end if; end if; end process reader; output_register: process (all) is begin -- process output_register case address_i is when CTRL_ADDRESS => data_o(reg_control'range) <= reg_control(reg_control'range); when STATUS_ADDRESS => data_o <= reg_status; when DATA_ADDRESS => data_o <= rx_buffer; when others => null; end case; end process output_register; rx_buffer_reader: process (clk_i) is begin -- process rx_buffer_full if rising_edge(clk_i) then -- rising clock edge if rst_in = '0' then -- synchronous reset (active low) rx_buffer_full <= '0'; else if clear_rx_buffer_full = '1' then rx_buffer_full <= '0'; end if; if rx_valid = '1' then rx_buffer_full <= '1'; rx_buffer <= rx_data; end if; end if; end if; end process rx_buffer_reader; reg_status <= "000000000000000000000000000" & rx_data_lost & busy & "0" & tx_buffer_full & rx_buffer_full; tx_data <= tx_buffer; rx_ready <= not rx_buffer_full; tx_valid <= tx_buffer_full; end architecture a1;