-- -------------------------------------------------------------------------- -- -- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs -- -- -------------------------------------------------------------------------- -- -- TODO -- -------------------------------------------------------------------------- -- -- Author : Markus Koch -- Contributors : None -- License : Mozilla Public License (MPL) Version 2 -- -------------------------------------------------------------------------- -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library trashernet; use trashernet.trashernet_pkg.all; library generics; use generics.all; use generics.wishbone_pkg.all; entity trashernet_phy_wb is generic( F_CLK : in integer; -- Clock frequency in Hz F_CLK_PHY : in integer ); port( -- Global clk : in std_logic; -- Global clock phy_clk : in std_logic; -- PHY clock rst : in std_logic; -- Asynchronous reset -- Wishbone IF wb_o : out wishbone_slave_out; -- Wishbone bus (out) wb_i : in wishbone_slave_in; -- Wishbone bus (in) -- Ethernet physical signals rx_p : in std_logic; tx_p : out std_logic; tx_n : out std_logic; -- LEDs led_tx : out std_logic; led_rx : out std_logic ); end entity trashernet_phy_wb; architecture RTL of trashernet_phy_wb is -- PHY application interface signal phy_out : phy_out_t; -- PHY application IF (out) signal phy_in : phy_in_t; -- PHY application IF (in) signal mac_out : raw_mac_out_t; -- MAC application IF (out) signal mac_in : raw_mac_in_t; -- MAC application IF (in) signal wb_adr : unsigned(2 downto 2); signal status_register : std_logic_vector(31 downto 0); signal rx_fifo_read : std_logic; signal rx_fifo_data : std_logic_vector(7 downto 0); signal tx_fifo_write : std_logic; signal tx_fifo_commit : std_logic; signal tx_fifo_empty : std_logic; signal tx_fifo_data : std_logic_vector(7 downto 0); signal rx_fifo_empty : std_logic; signal rx_bitcount : std_logic_vector(10 downto 0); signal rx_fifo_block_count : std_logic_vector(rx_bitcount'range); signal rx_block_next : std_logic; begin trashernet_phy_inst : entity trashernet.trashernet_phy_cdc generic map( F_CLK => F_CLK, F_CLK_PHY => F_CLK_PHY ) port map( clk => clk, phy_clk => phy_clk, rst => rst, phy_out => phy_out, phy_in => phy_in, rx_p => rx_p, tx_p => tx_p, tx_n => tx_n ); trashernet_raw_mac_inst : entity trashernet.trashernet_raw_mac port map( clk => clk, rst => rst, phy_out => phy_out, phy_in => phy_in, mac_out => mac_out, mac_in => mac_in ); rx_fifo_inst : entity generics.fifo_block generic map( SIZE => 2047 ) port map( clk => clk, rst_a => '0', clr => rst, data_in => mac_out.rx_mac_data, write => mac_out.rx_mac_valid, commit => mac_out.rx_mac_crc_ok, abort => mac_out.rx_mac_crc_error, full => open, data_out => rx_fifo_data, data_first => open, empty => rx_fifo_empty, read => rx_fifo_read, usage => open ); fifo_inst : entity generics.fifo generic map( SIZE => 31 ) port map( clk => clk, rst_a => '0', clr => rst, data_in => rx_bitcount, write => mac_out.rx_mac_crc_ok, full => open, data_out => rx_fifo_block_count, empty => open, read => rx_block_next, usage => open ); rxcount : process(rst, clk) is begin if rst then rx_bitcount <= (others => '0'); elsif rising_edge(clk) then if mac_out.rx_mac_crc_error or mac_out.rx_mac_crc_ok then rx_bitcount <= (others => '0'); elsif mac_out.rx_mac_valid then rx_bitcount <= std_logic_vector(unsigned(rx_bitcount) + 1); end if; end if; end process rxcount; tx_fifo_inst : entity generics.fifo_block generic map( SIZE => 2047 ) port map( clk => clk, rst_a => '0', clr => rst, data_in => wb_i.dat(7 downto 0), write => tx_fifo_write, commit => tx_fifo_commit, abort => '0', full => open, data_out => tx_fifo_data, data_first => open, empty => tx_fifo_empty, read => mac_out.tx_mac_data_ack, usage => open ); wb_adr <= unsigned(wb_i.adr(wb_adr'range)); wbif : process(clk, rst) is begin if rst then wb_o.ack <= '0'; rx_fifo_read <= '0'; tx_fifo_write <= '0'; tx_fifo_commit <= '0'; rx_block_next <= '0'; elsif rising_edge(clk) then wb_o.ack <= '0'; rx_fifo_read <= '0'; tx_fifo_write <= '0'; tx_fifo_commit <= '0'; rx_block_next <= '0'; if (wb_i.cyc and wb_i.stb) then wb_o.ack <= '1'; if wb_adr = 0 then wb_o.dat <= status_register; if wb_o.ack = '0' then if wb_i.we = '1' then tx_fifo_commit <= wb_i.dat(2); rx_block_next <= wb_i.dat(1); end if; end if; else wb_o.dat <= (others => '0'); if wb_o.ack = '0' then if wb_i.we = '1' then tx_fifo_write <= '1'; else rx_fifo_read <= '1'; end if; end if; wb_o.dat(7 downto 0) <= rx_fifo_data; end if; end if; end if; end process wbif; wb_o.err <= '0'; wb_o.rty <= '1'; wb_o.stall <= '0'; mac_in.tx_mac_data_en <= not tx_fifo_empty; -- FIXME: this does not care about inter-packet gaps indicated by `data_first` mac_in.tx_mac_data <= tx_fifo_data; status_register <= ("0" & x"0" & rx_fifo_block_count & -- 31..16 x"000" & "0" & (not tx_fifo_empty) & (not rx_fifo_empty) & phy_out.carrier_detect); ledstretch : process(clk) is constant CMAX : integer := integer(0.2 / (1.0 / real(F_CLK))); variable cnt : integer range 0 to CMAX; begin if rising_edge(clk) then if cnt = 0 then led_rx <= phy_out.carrier_detect; if phy_out.rx_active then cnt := CMAX; end if; else led_rx <= '0'; cnt := cnt - 1; end if; end if; end process ledstretch; ledstretch2 : process(clk) is constant CMAX : integer := integer(0.2 / (1.0 / real(F_CLK))); variable cnt : integer range 0 to CMAX; begin if rising_edge(clk) then if cnt = 0 then led_tx <= '0'; if phy_out.tx_active then cnt := CMAX; end if; else led_tx <= '1'; cnt := cnt - 1; end if; end if; end process ledstretch2; end architecture RTL;