@@ 13,63 13,186 @@ entity spi_peripheral is
);
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;
-
+ 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_o : out std_logic;
- miso_i : in std_logic;
- mosi_o : out std_logic;
- csn_o : out std_logic;
-
+ sck_io : inout std_logic;
+ miso_io : inout std_logic;
+ mosi_io : inout std_logic;
+ csn_io : inout 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);
+ 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 STATUS_ADDRESS : std_logic_vector(2 downto 0) := "010";
- constant DATA_ADDRESS : std_logic_vector(2 downto 0) := "011";
+ 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;
- signal rx_buffer : std_logic_vector(MAX_SIZE - 1 downto 0);
+ 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 : 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 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_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_io => sck_io,
+ miso_io => miso_io,
+ mosi_io => mosi_io,
+ csn_io => csn_io,
+ -- 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 address_i is
+ case raddress_i is
when DATA_ADDRESS => clear_rx_buffer_full <= '1';
when others => null;
end case;
@@ 81,14 204,33 @@ begin -- architecture a1
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;
+ case raddress_i is
+ when CTRL_ADDRESS => rdata_o <= reg_control;
+ when STATUS_ADDRESS => rdata_o <= reg_status;
+ when DATA_ADDRESS => rdata_o <= (rx_buffer'range => rx_buffer, others => '0');
+ when INTMASK_ADDRESS => rdata_o <= reg_intmask;
when others => null;
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
@@ 108,7 250,7 @@ begin -- architecture a1
end process rx_buffer_reader;
reg_status <= "000000000000000000000000000" &
- rx_data_lost &
+ err_lost_rx_data &
busy &
"0" &
tx_buffer_full &