-- FIXME: synchronizer library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity spi_if is port( clk : in std_logic; rst : in std_logic; -- -- Local memory IF addr : out std_logic_vector(12 downto 0); data_in : in std_logic_vector(8 downto 0); data_we : out std_logic; data_out : out std_logic_vector(8 downto 0); -- -- Other control signals vsync_rq : out std_logic; -- -- SPI IF spi_cs_n : in std_logic; -- SPI chip select, active low spi_sck : in std_logic; -- SPI clock spi_mosi : in std_logic; -- SPI data input spi_miso : inout std_logic -- SPI data output ); end entity spi_if; architecture RTL of spi_if is signal spi_sck_last : std_logic; signal sr_in : std_logic_vector(3 downto 0); signal sr_out : std_logic_vector(3 downto 0); signal bit_cnt : unsigned(1 downto 0); signal rx_stb : std_logic; type state_t is (IDLE, ADDRESS, DATA, FLUSH, LOCK); signal state : state_t; signal word_cnt : unsigned(3 downto 0); signal cache_nor : std_logic_vector(2 * 4 * 4 - 1 downto 0); signal cache_extra : std_logic_vector(4 - 1 downto 0); begin spi_receiver : process(clk, rst) is begin if (rst = '1') then spi_miso <= 'Z'; bit_cnt <= (others => '0'); sr_in <= (others => '0'); rx_stb <= '0'; spi_sck_last <= '0'; elsif (rising_edge(clk)) then rx_stb <= '0'; spi_sck_last <= spi_sck; if (spi_cs_n = '0') then if (spi_sck = '1' and spi_sck_last = '0') then -- rising edge of SPI clock, write sr_in <= sr_in(sr_in'high - 1 downto 0) & spi_mosi; bit_cnt <= bit_cnt + 1; if (bit_cnt = 3) then rx_stb <= '1'; end if; elsif (spi_sck = '0' and spi_sck_last = '1') then -- falling edge of SPI clock, read end if; else spi_miso <= 'Z'; bit_cnt <= (others => '0'); sr_in <= (others => '0'); end if; end if; end process spi_receiver; proc : process(clk, rst) is begin if (rst = '1') then addr <= (others => '0'); data_we <= '0'; word_cnt <= (others => '0'); cache_nor <= (others => '0'); cache_extra <= (others => '0'); vsync_rq <= '0'; state <= IDLE; elsif (rising_edge(clk)) then data_we <= '0'; vsync_rq <= '0'; if (spi_cs_n = '0') then case state is when IDLE => if (rx_stb = '1') then word_cnt <= word_cnt + 1; if (word_cnt = 1) then if (sr_in = x"0") then -- Start at addr state <= ADDRESS; word_cnt <= (others => '0'); addr <= (others => '0'); elsif (sr_in = x"1") then -- Continue state <= DATA; word_cnt <= (others => '0'); else state <= LOCK; end if; end if; end if; when ADDRESS => if (rx_stb = '1') then addr <= addr(addr'high - 4 downto 0) & sr_in; word_cnt <= word_cnt + 1; if (word_cnt = 3) then state <= DATA; word_cnt <= (others => '0'); end if; end if; when DATA => if (data_we = '1') then -- If we came from FLUSH addr <= std_logic_vector(unsigned(addr) + 1); end if; if (rx_stb = '1') then word_cnt <= word_cnt + 1; if (word_cnt = 8) then cache_extra <= sr_in; state <= FLUSH; word_cnt <= (others => '0'); data_we <= '1'; else cache_nor <= cache_nor(cache_nor'high - 4 downto 0) & sr_in; end if; end if; when FLUSH => addr <= std_logic_vector(unsigned(addr) + 1); cache_nor <= cache_nor(cache_nor'high - 8 downto 0) & x"00"; cache_extra <= cache_extra(cache_extra'high - 1 downto 0) & '0'; data_we <= '1'; word_cnt <= word_cnt + 1; if (word_cnt = 2) then state <= DATA; word_cnt <= (others => '0'); end if; when LOCK => vsync_rq <= '1'; null; end case; else state <= IDLE; --addr <= (others => '0'); data_we <= '0'; word_cnt <= (others => '0'); end if; end if; end process proc; data_out <= cache_nor(cache_nor'high downto cache_nor'high - 7) & cache_extra(cache_extra'high); end architecture RTL;