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 ( waddress_i : in std_logic_vector(2 downto 0); wdata_i : in std_logic_vector(31 downto 0); raddress_i : in std_logic_vector(2 downto 0); rdata_o : out std_logic_vector(31 downto 0); write_i : in std_logic; read_i : in std_logic; -- IOs sck_i : in std_logic; miso_i : in std_logic; mosi_i : in std_logic; csn_i : in std_logic; sck_o : out std_logic; miso_o : out std_logic; mosi_o : out std_logic; csn_o : out std_logic; sck_t : out std_logic; miso_t : out std_logic; mosi_t : out std_logic; csn_t : out std_logic; -- Control clk_i : in std_logic; rst_in : in std_logic; interrupt_o : out std_logic -- 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 INTMASK_ADDRESS : std_logic_vector(2 downto 0) := "001"; constant STATUS_ADDRESS : std_logic_vector(2 downto 0) := "010"; constant DATA_ADDRESS : std_logic_vector(2 downto 0) := "011"; constant CTRL_EN_BIT : natural := 0; constant CTRL_MASTER_BIT : natural := 1; constant CTRL_TX_EN_BIT : natural := 2; constant CTRL_RX_EN_BIT : natural := 3; constant CTRL_CLOCK_POLARITY_BIT : natural := 4; constant CTRL_CLOCK_PHASE_BIT : natural := 5; constant CTRL_PULSE_CSN_BIT : natural := 6; constant CTRL_LSBFIRST_BIT : natural := 7; -- constant CTRL_RX_BLOCK_ON_FULL_BIT : natural := 8; constant CTRL_SIZE_SEL_BIT : natural := 10; constant CTRL_DIV_SEL_BIT : natural := 20; constant INTMASK_RX_BUFFER_FULL : natural := 0; constant INTMASK_TX_BUFFER_EMPTY : natural := 1; constant INTMASK_LOST_RX_DATA : natural := 4; constant CTRL_DEFAULT : std_logic_vector(31 downto 0) := (CTRL_TX_EN_BIT => '1', CTRL_RX_EN_BIT => '1', others => '0'); constant INTMASK_DEFAULT : std_logic_vector(31 downto 0) := (others => '0'); 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 fill_tx_buffer : std_logic; signal reg_control : std_logic_vector(31 downto 0); signal reg_status : std_logic_vector(31 downto 0); signal reg_intmask : std_logic_vector(31 downto 0); signal clear_rx_buffer_full : std_logic; signal en : std_logic; signal master : std_logic; signal clock_polarity : std_logic; signal clock_phase : std_logic; signal size_sel : std_logic_vector(SIZES_2LOG - 1 downto 0); signal div_sel : std_logic_vector(DIVISORS_LOG2 - 1 downto 0); signal pulse_csn : std_logic; signal rx_block_on_full : std_logic; signal lsbfirst : std_logic; -- Rx signal rx_en : std_logic; signal rx_data : std_logic_vector(MAX_SIZE - 1 downto 0); signal rx_valid : std_logic; signal rx_ready : std_logic; -- Tx signal tx_en : std_logic; signal tx_data : std_logic_vector(MAX_SIZE - 1 downto 0); signal tx_valid : std_logic; signal tx_ready : std_logic; -- State signal busy : std_logic; signal err_lost_rx_data : std_logic; signal clear_lost_rx_data : std_logic; begin -- architecture a1 interrupt_o <= (rx_buffer_full and reg_intmask(INTMASK_RX_BUFFER_FULL)) or (not tx_buffer_full and reg_intmask(INTMASK_TX_BUFFER_EMPTY)) or (err_lost_rx_data and reg_intmask(INTMASK_LOST_RX_DATA)); en <= reg_control(CTRL_EN_BIT); master <= reg_control(CTRL_MASTER_BIT); clock_polarity <= reg_control(CTRL_CLOCK_POLARITY_BIT); clock_phase <= reg_control(CTRL_CLOCK_PHASE_BIT); pulse_csn <= reg_control(CTRL_PULSE_CSN_BIT); size_sel <= reg_control(CTRL_SIZE_SEL_BIT + SIZES_2LOG - 1 downto CTRL_SIZE_SEL_BIT); div_sel <= reg_control(CTRL_DIV_SEL_BIT + DIVISORS_LOG2 - 1 downto CTRL_DIV_SEL_BIT); lsbfirst <= reg_control(CTRL_LSBFIRST_BIT); tx_en <= reg_control(CTRL_TX_EN_BIT); rx_en <= reg_control(CTRL_RX_EN_BIT); rx_block_on_full <= '0'; masterslave : entity work.spi_masterslave generic map ( DIVISORS => DIVISORS, DIVISORS_LOG2 => DIVISORS_LOG2, SIZES => SIZES, SIZES_2LOG => SIZES_2LOG, CSN_PULSE_CYCLES => CSN_PULSE_CYCLES) port map ( -- IOs sck_o => sck_o, miso_o => miso_o, mosi_o => mosi_o, csn_o => csn_o, sck_i => sck_i, miso_i => miso_i, mosi_i => mosi_i, csn_i => csn_i, sck_t => sck_t, miso_t => miso_t, mosi_t => mosi_t, csn_t => csn_t, -- Control clk_i => clk_i, rst_in => rst_in, en_i => en, master_i => master, clock_polarity_i => clock_polarity, clock_phase_i => clock_phase, size_sel_i => size_sel, div_sel_i => div_sel, pulse_csn_i => pulse_csn, rx_block_on_full_i => rx_block_on_full, lsbfirst_i => lsbfirst, -- Data -- Rx rx_en_i => rx_en, rx_data_o => rx_data, rx_valid_o => rx_valid, rx_ready_i => rx_ready, -- Tx tx_en_i => tx_en, tx_data_i => tx_data, tx_valid_i => tx_valid, tx_ready_o => tx_ready, -- State busy_o => busy, err_lost_rx_data_o => err_lost_rx_data, clear_lost_rx_data_i => clear_lost_rx_data); writer: process (clk_i) is begin -- process writer if rising_edge(clk_i) then -- rising clock edge if rst_in = '0' then -- synchronous reset (active low) reg_control <= CTRL_DEFAULT; reg_intmask <= INTMASK_DEFAULT; fill_tx_buffer <= '0'; elsif write_i = '1' then case waddress_i is when CTRL_ADDRESS => reg_control <= wdata_i; when INTMASK_ADDRESS => reg_intmask <= wdata_i; when DATA_ADDRESS => fill_tx_buffer <= '1'; when STATUS_ADDRESS => clear_lost_rx_data <= wdata_i(4); when others => null; end case; else fill_tx_buffer <= '0'; clear_lost_rx_data <= '0'; end if; end if; end process writer; 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) clear_rx_buffer_full <= '0'; elsif read_i = '1' then case raddress_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 raddress_i is when CTRL_ADDRESS => rdata_o <= reg_control; when STATUS_ADDRESS => rdata_o <= reg_status; when DATA_ADDRESS => rdata_o <= (15 downto 0 => rx_buffer, others => '0'); when INTMASK_ADDRESS => rdata_o <= reg_intmask; when others => rdata_o <= (others => '0'); end case; end process output_register; tx_buffer_writer: process (clk_i) is begin -- process tx_buffer_writer if rising_edge(clk_i) then -- rising clock edge if rst_in = '0' then -- synchronous reset (active low) tx_buffer <= (others => '0'); tx_buffer_full <= '0'; else if fill_tx_buffer = '1' and tx_buffer_full = '0' then tx_buffer_full <= '1'; tx_buffer <= wdata_i(tx_buffer'range); tx_buffer_full <= '1'; elsif tx_ready = '1' and tx_buffer_full = '1' then tx_buffer_full <= '0'; end if; end if; end if; end process tx_buffer_writer; 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" & err_lost_rx_data & busy & "0" & (not tx_buffer_full) & rx_buffer_full; tx_data <= tx_buffer; rx_ready <= not rx_buffer_full; tx_valid <= tx_buffer_full; end architecture a1;