library ieee;
use ieee.std_logic_1164.all;
entity spi_transmit is
generic (
WIDTH : integer := 8);
port (
clk_i : in std_logic; -- Clock
rst_in : in std_logic; -- Asynchronous reset, active low
transmit_data_i : in std_logic_vector(WIDTH - 1 downto 0); -- The data to
-- transmit.
-- Change only
-- if ready_o
-- is '1'.
transmit_i : in std_logic; -- Pulse to signal new data are present
-- in transmit_data. Data has to change
-- only if ready_o is '1'
ready_o : out std_logic; -- Signals that the transmitter is
-- ready for new data on `transmit_data_i``.
transmitting_o : out std_logic; -- Signals that the transmitter is
-- currently transmitting data
transmit_bit_o : out std_logic); -- The bit to transmit (on master MOSI)
end entity spi_transmit;
architecture a1 of spi_transmit is
signal ready_reg : std_logic; -- is the transmitter ready for new data?
signal ready_next : std_logic;
signal data_prepared_reg : std_logic; -- is there data prepared for next transmission?
signal data_prepared_next : std_logic;
signal store_data_in_sr_reg : std_logic; -- should data be stored in the
-- shift register next clock cycle?
signal store_data_in_sr_next : std_logic;
signal data_bit_index_reg : integer range 0 to WIDTH;
signal data_bit_index_next : integer range 0 to WIDTH;
signal transmitting_reg : std_logic; -- is there an ongoing transmission?
signal transmitting_next : std_logic;
signal continue_in_ongoing_transmission : std_logic; -- at the end of
-- transmission, are
-- next data ready and
-- should the transmission continue?
begin -- architecture a1
ready_o <= ready_reg;
transmitting_o <= transmitting_reg;
ready_next <= '0' when ready_reg = '1' and transmit_i = '1' and transmitting_reg = '1' else
'0' when ready_reg = '0' and data_prepared_next = '1' else
'1';
data_bit_index_next <= (data_bit_index_reg + 1) mod WIDTH when transmitting_reg = '1' else
0;
continue_in_ongoing_transmission <= '1' when transmitting_reg = '1' and data_bit_index_next = 0 and store_data_in_sr_next = '1' else
'0';
transmitting_next <= '1' when continue_in_ongoing_transmission = '1' else
'0' when transmitting_reg = '1' and data_bit_index_next = 0 else
'1' when transmitting_reg = '1' else
'1' when store_data_in_sr_next = '1' else
'0';
store_data_in_sr_next <= '0' when store_data_in_sr_reg = '1' else
'1' when transmitting_reg = '0' and transmit_i = '1' else
'1' when transmitting_reg = '0' and data_prepared_reg = '1' else
'1' when transmitting_reg = '1' and data_bit_index_next = 0 and data_prepared_reg = '1' else
'0';
data_prepared_next <= '1' when transmit_i = '1' and ready_reg = '1' and transmitting_reg = '1' else
'1' when data_prepared_reg = '1' and store_data_in_sr_next = '0' else
'0';
store_next: process (clk_i) is
begin -- process store_next
if rst_in = '0' then -- synchronous reset (active low)
ready_reg <= '0';
data_prepared_reg <= '0';
store_data_in_sr_reg <= '0';
data_bit_index_reg <= 0;
transmitting_reg <= '0';
elsif rising_edge(clk_i) then -- rising clock edge
ready_reg <= ready_next;
data_prepared_reg <= data_prepared_next;
store_data_in_sr_reg <= store_data_in_sr_next;
data_bit_index_reg <= data_bit_index_next;
transmitting_reg <= transmitting_next;
end if;
end process store_next;
sr: entity work.piso_shift_register
generic map (
WIDTH => WIDTH)
port map (
clk_i => clk_i,
data_i => transmit_data_i,
store_i => store_data_in_sr_next,
q_o => transmit_bit_o
);
end architecture a1;