library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity flashrom_spi is generic( clk_divider : integer range 2 to 9999 := 2; max_word_length : integer := 32; max_dummy_bits : integer := 8; cs_inactive_cycles : integer := 10 ); port( clk : in std_logic; rst : in std_logic; clr : in std_logic; -- SPI flash hardware signals spi_si : out std_logic; -- SPI serial in spi_so : in std_logic; -- SPI serial out spi_sck : out std_logic; -- SPI clock spi_cs_n : out std_logic; -- SPI chip select -- Logic interface data_in_valid : in std_logic; -- Data to Flash ROM data_in : in std_logic_vector(max_word_length - 1 downto 0); data_in_length : in integer range 0 to max_word_length; data_next : out std_logic; data_out : out std_logic_vector(max_word_length - 1 downto 0); data_out_valid : out std_logic; -- Data from Flash ROM data_out_length : in integer range 0 to max_word_length; data_out_dummy_bits : in integer range 0 to max_dummy_bits; transmission_active : out std_logic ); end entity flashrom_spi; architecture RTL of flashrom_spi is type txstate_t is (IDLE, TX); signal state : txstate_t; signal ckDiv : integer range 0 to clk_divider - 2; signal shiftreg : std_logic_vector(max_word_length - 1 downto 0); signal bitCounter : integer range 0 to max_word_length - 1; signal bitCounterIn : integer range 0 to max_word_length + max_dummy_bits - 1; -- TODO: Actually this must count until the higher of the two signal data_in_length_i : integer range 0 to max_word_length; signal data_out_length_i : integer range 0 to max_word_length; signal delayCycle : std_logic; signal oneBitRead : std_logic; signal pseudoEdge : boolean; signal dummy_passed : boolean; signal prevent_retrig : boolean; signal cs_inactive_cnt : integer range 0 to cs_inactive_cycles; begin toSpi : process(clk, rst) is procedure default_state is begin data_next <= '0'; data_out_valid <= '0'; pseudoEdge <= false; cs_inactive_cnt <= 0; end procedure default_state; procedure reset_state is begin state <= IDLE; spi_sck <= '0'; shiftreg <= (others => '0'); bitCounter <= 0; bitCounterIn <= 0; data_out <= (others => '0'); delayCycle <= '0'; oneBitRead <= '0'; dummy_passed <= false; default_state; end procedure reset_state; begin if rst = '1' then reset_state; elsif rising_edge(clk) then default_state; if clr = '1' then reset_state; else case state is when IDLE => cs_inactive_cnt <= cs_inactive_cnt; prevent_retrig <= false; delayCycle <= '0'; spi_sck <= '0'; oneBitRead <= '0'; dummy_passed <= false; data_out <= (others => '0'); if ckDiv = clk_divider - 2 then -- ensures cs inactive time between transactions if cs_inactive_cnt = cs_inactive_cycles then if data_in_valid = '1' then ckDiv <= 0; state <= TX; bitCounter <= 0; bitCounterIn <= 0; data_in_length_i <= 0; pseudoEdge <= true; end if; else ckDiv <= 0; cs_inactive_cnt <= cs_inactive_cnt + 1; end if; else ckDiv <= ckDiv + 1; end if; when TX => if data_in_valid = '0' then prevent_retrig <= true; end if; if ckDiv = clk_divider - 2 or pseudoEdge then ckDiv <= 0; if not pseudoEdge then spi_sck <= not spi_sck; end if; if spi_sck = '0' and bitCounter = data_in_length_i and data_in_valid = '0' then -- Prevent last clock cycle (make it a "passive" one) spi_sck <= '0'; pseudoEdge <= true; end if; if spi_sck = '1' or pseudoEdge then -- falling edge -> provide data if bitCounter = data_in_length_i then bitCounter <= 0; if data_in_valid = '1' and not prevent_retrig then shiftreg <= data_in; data_in_length_i <= data_in_length - 1; data_out_length_i <= data_out_length - 1; data_next <= '1'; else delayCycle <= '1'; pseudoEdge <= true; end if; else bitCounter <= bitCounter + 1; shiftreg <= shiftreg(shiftreg'high - 1 downto 0) & '0'; end if; --else -- spi_sck = '1' (falling edge) data_out <= data_out(data_out'high - 1 downto 0) & spi_so; if bitCounterIn = 0 then if dummy_passed then data_out_valid <= '1'; end if; end if; if not dummy_passed then if bitCounterIn = data_out_dummy_bits then dummy_passed <= true; bitCounterIn <= 1; else bitCounterIn <= bitCounterIn + 1; end if; else if bitCounterIn = data_out_length_i then bitCounterIn <= 0; else bitCounterIn <= bitCounterIn + 1; end if; if delayCycle = '1' then spi_sck <= '0'; state <= IDLE; ckDiv <= 0; end if; end if; end if; else ckDiv <= ckDiv + 1; end if; end case; end if; end if; end process toSpi; spi_si <= shiftreg(shiftreg'high); spi_cs_n <= '0' when state = TX else '1'; transmission_active <= '1' when state = TX else '0'; end architecture RTL;