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;