-- ----------------------------------------------------------------------------- -- Copyright (c) 2013 Benjamin Krill -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. -- ----------------------------------------------------------------------------- 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;