166 lines
4.2 KiB
VHDL
166 lines
4.2 KiB
VHDL
-- 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;
|