156 lines
5.0 KiB
VHDL
156 lines
5.0 KiB
VHDL
library IEEE;
|
|
use IEEE.STD_LOGIC_1164.ALL;
|
|
use IEEE.NUMERIC_STD.ALL;
|
|
|
|
library UNISIM;
|
|
use UNISIM.VComponents.all;
|
|
|
|
--FT60x 245-style FIFO interface
|
|
--Copyright (C) 2016 David Shah
|
|
--Licensed under the MIT License
|
|
|
|
entity ft60x_fifo_if is
|
|
port(
|
|
reset : in std_logic; --Active high, async
|
|
enable : in std_logic; --Active high
|
|
|
|
ftdi_clock : in std_logic;
|
|
ftdi_txe_n : in std_logic;
|
|
ftdi_rxf_n : in std_logic;
|
|
ftdi_oe_n : out std_logic;
|
|
ftdi_wr_n : out std_logic;
|
|
ftdi_rd_n : out std_logic;
|
|
ftdi_be : inout std_logic_vector(3 downto 0);
|
|
ftdi_data : inout std_logic_vector(31 downto 0);
|
|
|
|
--Buffered FTDI clock out to drive FIFOs, etc
|
|
clock_out : out std_logic;
|
|
|
|
--Command FIFO write port
|
|
command_fifo_d : out std_logic_vector(31 downto 0);
|
|
command_fifo_wren : out std_logic;
|
|
command_fifo_prog_full : in std_logic; --asserted when less than full command's space in the FIFO
|
|
|
|
--Response FIFO read port
|
|
resp_fifo_q : in std_logic_vector(31 downto 0);
|
|
resp_fifo_rden : out std_logic;
|
|
resp_fifo_prog_empty : in std_logic; --asserted when response FIFO contains less than a full response
|
|
|
|
--Receive data FIFO read port
|
|
rx_fifo_q : in std_logic_vector(31 downto 0);
|
|
rx_fifo_rden : out std_logic;
|
|
rx_fifo_prog_empty : in std_logic; --asserted when rx data FIFO contains less than a full RX packet
|
|
|
|
--Misc signals
|
|
streaming_mode : in std_logic --asserted when in streaming mode (i.e. pulling data from RX FIFO)
|
|
);
|
|
end ft60x_fifo_if;
|
|
|
|
architecture Behavioral of ft60x_fifo_if is
|
|
|
|
function max(a, b: natural) return natural is
|
|
begin
|
|
if a > b then return a;
|
|
else return b;
|
|
end if;
|
|
end max;
|
|
|
|
constant command_len : natural := 32/4;
|
|
constant response_len : natural := 32/4;
|
|
constant rx_packet_len : natural := 4096/4;
|
|
|
|
signal clock_buf : std_logic; --FTDI clock after input buffer
|
|
|
|
signal current_state : natural range 0 to 7 := 0;
|
|
signal word_count : natural range 0 to max(rx_packet_len, max(response_len, command_len)) := 0;
|
|
|
|
signal streaming_mode_lat : std_logic;
|
|
begin
|
|
clkbuf : IBUFG
|
|
generic map(
|
|
IBUF_LOW_PWR => FALSE,
|
|
IOSTANDARD => "DEFAULT")
|
|
port map(
|
|
O => clock_buf,
|
|
I => ftdi_clock);
|
|
|
|
clock_out <= clock_buf;
|
|
|
|
process(clock_buf, reset)
|
|
begin
|
|
if reset = '1' then
|
|
current_state <= 0;
|
|
elsif rising_edge(clock_buf) then
|
|
if enable = '1' then
|
|
case current_state is
|
|
when 0 => --waiting for event
|
|
if ftdi_rxf_n = '0' then
|
|
current_state <= 1;
|
|
elsif ftdi_txe_n = '0' and resp_fifo_prog_empty = '0' and streaming_mode = '0' then
|
|
current_state <= 4;
|
|
elsif ftdi_txe_n = '0' and rx_fifo_prog_empty = '0' and streaming_mode = '1' then
|
|
current_state <= 6;
|
|
end if;
|
|
when 1 => --read out command start
|
|
current_state <= 2;
|
|
when 2 => --read out command start 2
|
|
current_state <= 3;
|
|
when 3 => --read out command
|
|
if word_count = command_len - 1 then
|
|
current_state <= 0;
|
|
end if;
|
|
when 4 => --write response start
|
|
current_state <= 5;
|
|
when 5 => --write response
|
|
if word_count = response_len - 1 then
|
|
current_state <= 0;
|
|
end if;
|
|
when 6 => --write rx data start
|
|
current_state <= 7;
|
|
when 7 => --write rx data
|
|
if word_count = rx_packet_len - 1 then
|
|
current_state <= 0;
|
|
end if;
|
|
when others =>
|
|
current_state <= 0;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
|
|
ftdi_wr_n <= '0' when (current_state = 5) or (current_state = 7) else '1';
|
|
ftdi_rd_n <= '0' when (current_state = 2) or (current_state = 3) else '1';
|
|
ftdi_oe_n <= '0' when (current_state = 1) or (current_state = 2) or (current_state = 3) else '1';
|
|
|
|
command_fifo_wren <= '1' when ((current_state = 2) or (current_state = 3)) and (ftdi_be = "1111") and (ftdi_rxf_n = '0') else '0';
|
|
resp_fifo_rden <= '1' when (current_state = 4) or ((current_state = 5) and (word_count < (response_len - 1))) else '0';
|
|
rx_fifo_rden <= '1' when (current_state = 6) or ((current_state = 7) and (word_count < (rx_packet_len - 1))) else '0';
|
|
|
|
command_fifo_d <= ftdi_data when (current_state = 2) or (current_state = 3) else (others => '0');
|
|
|
|
ftdi_data <= resp_fifo_q when current_state = 5 else
|
|
rx_fifo_q when current_state = 7 else
|
|
(others => 'Z');
|
|
|
|
ftdi_be <= "1111" when (current_state = 5) or (current_state = 7) else "ZZZZ";
|
|
|
|
process(clock_buf, reset)
|
|
begin
|
|
if reset = '1' then
|
|
word_count <= 0;
|
|
streaming_mode_lat <= '0';
|
|
elsif rising_edge(clock_buf) then
|
|
if enable = '1' then
|
|
streaming_mode_lat <= streaming_mode;
|
|
if current_state = 0 then
|
|
word_count <= 0;
|
|
elsif (current_state = 3) or (current_state = 5) or (current_state = 7) then
|
|
word_count <= word_count + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end Behavioral;
|