fx2/fpga/f2p/f2p_master.vhd

221 lines
6.7 KiB
VHDL

-- ---------------------------------------------------------------
-- (2013) Benjamin Krill <benjamin@krll.de>
-- ---------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity f2p_master is
port (
clk : in std_logic;
rst_n : in std_logic;
debug : out std_logic_vector(7 downto 0);
-- cypress interface
usb_clk : in std_logic;
usb_flag_a_i : in std_logic; -- programmable flag
usb_flag_b_i : in std_logic; -- full flag
usb_flag_c_i : in std_logic; -- empty flag
usb_cs_o : out std_logic; -- put to GND, not need for this application
usb_oe_o : out std_logic; -- active_low
usb_rd_o : out std_logic; -- active_low
usb_wr_o : out std_logic; -- active_low
usb_pktend_o : out std_logic; -- active_low
usb_adr_o : out std_logic_vector(1 downto 0); -- 00 ep2, 01 ep4, 10 ep6, 11 ep8
usb_dat_io : inout std_logic_vector(7 downto 0);
-- write/read pipe
wp_wr_i : in std_logic;
wp_full_o : out std_logic;
wp_eop_i : in std_logic;
wp_dat_i : in std_logic_vector(31 downto 0);
rp_rd_i : in std_logic;
rp_empty_o : out std_logic;
rp_dat_o : out std_logic_vector(31 downto 0)
);
end f2p_master;
architecture f2p_master of f2p_master is
constant EP2 : std_logic_vector(1 downto 0) := "00";
constant EP4 : std_logic_vector(1 downto 0) := "01";
constant EP6 : std_logic_vector(1 downto 0) := "10";
constant EP8 : std_logic_vector(1 downto 0) := "11";
signal rst : std_logic;
type sm_usb_t is (IDLE, RD_ADDRESS, RD_READ, WR_ADDRESS, WR_WRITE);
signal sm_usb : sm_usb_t;
signal usb_oe : std_logic;
signal usb_rd : std_logic;
signal usb_wr : std_logic;
signal usb_wr_cnt : unsigned(25 downto 0);
signal usb_pktend : std_logic;
signal usb_dat_out : std_logic_vector(7 downto 0);
signal usb_dat_in : std_logic_vector(7 downto 0);
signal usb_adr : std_logic;
signal uftx_din : std_logic_vector(31 downto 0);
signal uftx_wren : std_logic;
signal uftx_rden : std_logic;
signal uftx_dout : std_logic_vector( 7 downto 0);
signal uftx_full : std_logic;
signal uftx_empty : std_logic;
signal ufrx_din : std_logic_vector( 7 downto 0);
signal ufrx_wren : std_logic;
signal ufrx_rden : std_logic;
signal ufrx_dout : std_logic_vector(31 downto 0);
signal ufrx_full : std_logic;
signal ufrx_empty : std_logic;
signal uftxfin_cnt : unsigned(23 downto 0);
signal uftxfin_din : std_logic_vector(23 downto 0);
signal uftxfin_wren : std_logic;
signal uftxfin_rden : std_logic;
signal uftxfin_dout : std_logic_vector(23 downto 0);
signal uftxfin_full : std_logic;
signal uftxfin_empty : std_logic;
begin
rst <= not rst_n;
-- EP2 from host, EP6 to host
-- during IDLE monitor EF and read data from fifo
usb_adr_o <= EP2 when (usb_adr = '0' or sm_usb = RD_ADDRESS) and sm_usb /= WR_ADDRESS else EP6;
usb_cs_o <= '0';
usb_oe_o <= not usb_oe;
usb_rd_o <= not usb_rd;
usb_wr_o <= not usb_wr;
usb_pktend_o <= not usb_pktend;
usb_dat_io <= (others => 'Z') when usb_oe = '1' else usb_dat_out;
usb_dat_in <= usb_dat_io when usb_oe = '1' else (others => '0');
usb_oe <= '1' when (usb_adr = '0' or sm_usb = RD_ADDRESS) and sm_usb /= WR_ADDRESS else '0';
usb_rd <= '1' when sm_usb = RD_READ and usb_flag_c_i = '1' else '0';
usb_wr <= '1' when sm_usb = WR_WRITE and usb_flag_b_i = '1' and uftx_empty = '0' else '0';
usb_pktend <= '1' when sm_usb = WR_WRITE and uftxfin_empty = '0'
and to_integer(usb_wr_cnt(25 downto 2)) = to_integer(unsigned(uftxfin_dout)) else '0';
process (usb_clk, rst_n)
begin
if rst_n = '0' then
sm_usb <= IDLE;
usb_adr <= '0';
usb_wr_cnt <= "00" & x"000001";
elsif rising_edge(usb_clk) then
if usb_pktend = '1' then
usb_wr_cnt <= "00" & x"000001";
elsif usb_wr = '1' then
usb_wr_cnt <= usb_wr_cnt + "1";
end if;
-- EP address switch
if sm_usb = RD_ADDRESS then
usb_adr <= '0';
elsif sm_usb = WR_ADDRESS then
usb_adr <= '1';
end if;
case sm_usb is
when IDLE =>
if uftx_empty = '0' then
sm_usb <= WR_ADDRESS;
elsif ufrx_full = '0' then
sm_usb <= RD_ADDRESS;
end if;
when RD_ADDRESS =>
sm_usb <= RD_READ;
when RD_READ =>
sm_usb <= IDLE;
if usb_flag_c_i = '1' and ufrx_full = '0' then -- fifo not empty
sm_usb <= RD_READ;
end if;
when WR_ADDRESS =>
sm_usb <= WR_WRITE;
when WR_WRITE =>
if usb_pktend = '1' then
sm_usb <= IDLE;
end if;
end case;
end if;
end process;
-- --------------------------------------------------------------------
-- USB RX FIFO
-- --------------------------------------------------------------------
rp_dat_o <= ufrx_dout(7 downto 0) & ufrx_dout(15 downto 8) & ufrx_dout(23 downto 16) & ufrx_dout(31 downto 24);
rp_empty_o <= ufrx_empty;
ufrx_rden <= rp_rd_i;
ufrx_din <= usb_dat_in;
ufrx_wren <= usb_rd;
usb_fifo_rx_0: entity work.usb_fifo_rx
port map (
rst => rst,
wr_clk => usb_clk,
wr_en => ufrx_wren,
din => ufrx_din,
full => ufrx_full,
rd_clk => clk,
rd_en => ufrx_rden,
dout => ufrx_dout,
empty => ufrx_empty
);
-- --------------------------------------------------------------------
-- USB TX FIFO
-- --------------------------------------------------------------------
uftx_din <= wp_dat_i;
uftx_wren <= wp_wr_i;
wp_full_o <= uftx_full;
uftx_rden <= usb_wr;
usb_dat_out <= uftx_dout;
usb_fifo_tx_0: entity work.usb_fifo_tx
port map (
rst => rst,
wr_clk => clk,
wr_en => uftx_wren,
din => uftx_din,
full => uftx_full,
rd_clk => usb_clk,
rd_en => uftx_rden,
dout => uftx_dout,
empty => uftx_empty
);
process (clk, rst_n)
begin
if rst_n = '0' then
uftxfin_cnt <= x"000001";
elsif rising_edge(clk) then
if uftxfin_wren = '1' then
uftxfin_cnt <= x"000001";
elsif wp_wr_i = '1' then
uftxfin_cnt <= uftxfin_cnt + "1";
end if;
end if;
end process;
uftxfin_wren <= wp_wr_i and wp_eop_i and not uftxfin_full;
uftxfin_din <= std_logic_vector(uftxfin_cnt);
uftxfin_rden <= usb_pktend and not uftxfin_empty;
usb_fifo_txfin_0: entity work.usb_fifo_tx_fin
port map (
rst => rst,
wr_clk => clk,
wr_en => uftxfin_wren,
din => uftxfin_din,
full => uftxfin_full,
rd_clk => usb_clk,
rd_en => uftxfin_rden,
dout => uftxfin_dout,
empty => uftxfin_empty
);
end f2p_master;