LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; use std.textio.all; -- Imports the standard textio package. use work.utils_pkg.all; use work.spi_types.all; ENTITY spi_tx IS Generic ( word_width : natural := 32 ); Port ( rst : in STD_LOGIC; clk : in STD_LOGIC; cmd_vld : in STD_LOGIC; cmd_ack : out STD_LOGIC; cmd : in cmd_t; din_vld : in STD_LOGIC; din_re : out STD_LOGIC; din : in unsigned(word_width-1 downto 0); shift_en : in STD_LOGIC; data_out : out STD_LOGIC; clk_out : out STD_LOGIC ); END spi_tx; ARCHITECTURE behavior OF spi_tx IS type state_t is (idle, prepare, shift, finish); signal xfer_count : unsigned(NextExpBaseTwo(XFER_SIZE_MAX)-1 downto 0); signal data_count : unsigned(NextExpBaseTwo(XFER_SIZE_MAX)-1 downto 0); signal word_count : unsigned(NextExpBaseTwo(XFER_SIZE_MAX)-1 downto 0); signal cmd_reg : cmd_t; signal state : state_t; signal state_next : state_t; signal cmd_reg_we : std_logic; signal xfer_count_en : std_logic; signal data_count_en : std_logic; signal xfer_count_busy : std_logic; signal data_count_busy : std_logic; signal clk_en : std_logic; -------------------------------------------------------------------------- begin clk_out <= clk and clk_en; -------------------------------------------------------------------------- proc_state_next: process(clk) begin if rising_edge(clk) then if rst = '1' then state <= idle; else state <= state_next; end if; end if; end process; proc_fsm: process(state, cmd_vld, xfer_count_busy) begin state_next <= state; cmd_reg_we <= '0'; cmd_ack <= '0'; xfer_count_en <= '0'; data_count_en <= '0'; clk_en <= '0'; case state is when idle => cmd_ack <= cmd_vld; if cmd_vld = '1' then cmd_reg_we <= '1'; state_next <= prepare; end if; when prepare => xfer_count_en <= '1'; data_count_en <= '1'; state_next <= shift; when shift => clk_en <= '1'; xfer_count_en <= '1'; data_count_en <= '1'; if xfer_count_busy = '0' then state_next <= finish; end if; when finish => state_next <= idle; when others => state_next <= idle; end case; end process; process(clk) begin if rising_edge(clk) then if xfer_count_en = '0' then xfer_count <= cmd.xfer_size; xfer_count_busy <= '0'; elsif shift_en = '1' then if xfer_count /= to_unsigned(0, xfer_count'length) then xfer_count_busy <= '1'; xfer_count <= xfer_count - 1; else xfer_count_busy <= '0'; end if; end if; end if; end process; process(clk) begin if rising_edge(clk) then din_re <= '0'; if data_count_en = '0' then word_count <= to_unsigned(0, word_count'length); data_count <= cmd.data_size; data_count_busy <= '0'; elsif shift_en = '1' then if word_count /= to_unsigned(0, word_count'length) then word_count <= word_count - 1; else din_re <= '1'; word_count <= to_unsigned(word_width, word_count'length); end if; if data_count /= to_unsigned(1, data_count'length) then data_count_busy <= '1'; data_count <= data_count - 1; else data_count_busy <= '0'; end if; end if; end if; end process; end behavior;