From: Michael Boehmer Date: Sat, 9 Jul 2022 22:30:23 +0000 (+0200) Subject: changes to sync reset X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=fd7f7463a7c95d3aade0f283333e8ee1e349c2a6;p=trbnet.git changes to sync reset --- diff --git a/gbe_trb/base/gather_ports.vhd b/gbe_trb/base/gather_ports.vhd new file mode 100644 index 0000000..9ee21b7 --- /dev/null +++ b/gbe_trb/base/gather_ports.vhd @@ -0,0 +1,177 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + +entity gather_ports is + port( + CLK : in std_logic; + RESET : in std_logic; + -- + FRAME_AVAIL_IN : in std_logic_vector(15 downto 0) := (others => '0'); + FRAME_REQ_OUT : out std_logic_vector(15 downto 0); + FRAME_ACK_IN : in std_logic_vector(15 downto 0) := (others => '0'); + PORT_SELECT_OUT : out std_logic_vector(15 downto 0); + CYCLE_DONE_OUT : out std_logic; + -- + DEBUG : out std_logic_vector(15 downto 0) + ); +end entity gather_ports; + +architecture gather_ports_arch of gather_ports is + +-- Components + +-- state machine signals + type state_t is (IDLE, STORE, DO_PORTS, DELAY, CLEANUP); + signal STATE, NEXT_STATE : state_t; + +-- Signals + signal gather_needed_x : std_logic; + signal store_ports_x : std_logic; + signal all_ports_done_x : std_logic; + signal stored_ports : std_logic_vector(15 downto 0); + signal next_port_x : std_logic_vector(15 downto 0); + signal select_ports : std_logic_vector(15 downto 0); + signal req_ports : std_logic_vector(15 downto 0); + +begin + + -- we need to start a gather cycle if any src port has frames available + gather_needed_x <= '1' when FRAME_AVAIL_IN /= x"0000" else '0'; + + -- store the src port status + GEN_REGS: for I in 0 to 15 generate + THE_SRC_STORE_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + stored_ports(I) <= '0'; + elsif( store_ports_x = '1' ) then + stored_ports(I) <= FRAME_AVAIL_IN(I); + elsif( FRAME_ACK_IN(I) = '1' ) then + stored_ports(I) <= '0'; + end if; + end if; + end process THE_SRC_STORE_PROC; + end generate; + + all_ports_done_x <= '1' when stored_ports = x"0000" else '0'; + + -- select the port data + THE_SELECT_PORT_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if( RESET = '1' ) then + select_ports <= (others => '0'); + else + select_ports <= next_port_x; + end if; + end if; + end process THE_SELECT_PORT_PROC; + + PORT_SELECT_OUT <= select_ports; + + -- port frame request, one clock cycle pulse + req_ports <= not select_ports and next_port_x when rising_edge(CLK); + + FRAME_REQ_OUT <= req_ports; + + CYCLE_DONE_OUT <= '1' when STATE = CLEANUP else '0'; + + -- priority decoced "next port to serve" signals + THE_NEXT_PORT_PROC: process( stored_ports ) + begin + if ( stored_ports(0) = '1' ) then + next_port_x <= x"0001"; + elsif( stored_ports(1) = '1' ) then + next_port_x <= x"0002"; + elsif( stored_ports(2) = '1' ) then + next_port_x <= x"0004"; + elsif( stored_ports(3) = '1' ) then + next_port_x <= x"0008"; + elsif( stored_ports(4) = '1' ) then + next_port_x <= x"0010"; + elsif( stored_ports(5) = '1' ) then + next_port_x <= x"0020"; + elsif( stored_ports(6) = '1' ) then + next_port_x <= x"0040"; + elsif( stored_ports(7) = '1' ) then + next_port_x <= x"0080"; + elsif( stored_ports(8) = '1' ) then + next_port_x <= x"0100"; + elsif( stored_ports(9) = '1' ) then + next_port_x <= x"0200"; + elsif( stored_ports(10) = '1' ) then + next_port_x <= x"0400"; + elsif( stored_ports(11) = '1' ) then + next_port_x <= x"0800"; + elsif( stored_ports(12) = '1' ) then + next_port_x <= x"1000"; + elsif( stored_ports(13) = '1' ) then + next_port_x <= x"2000"; + elsif( stored_ports(14) = '1' ) then + next_port_x <= x"4000"; + elsif( stored_ports(15) = '1' ) then + next_port_x <= x"8000"; + else + next_port_x <= x"0000"; + end if; + end process THE_NEXT_PORT_PROC; + + ----------------------------------------------------------- + -- statemachine: clocked process + ----------------------------------------------------------- + THE_FSM: process( CLK ) + begin + if( rising_edge(CLK) ) then + if( RESET = '1' ) then + STATE <= IDLE; + else + STATE <= NEXT_STATE; + end if; + end if; + end process THE_FSM; + + THE_STATE_TRANSITIONS: process( STATE, gather_needed_x, all_ports_done_x ) + begin + store_ports_x <= '0'; + + case STATE is + + when IDLE => + if( gather_needed_x = '1' ) then + NEXT_STATE <= STORE; + store_ports_x <= '1'; + else + NEXT_STATE <= IDLE; + end if; + + when STORE => + NEXT_STATE <= DO_PORTS; + + when DO_PORTS => + if( all_ports_done_x = '1' ) then + NEXT_STATE <= DELAY; + else + NEXT_STATE <= DO_PORTS; + end if; + + when DELAY => + NEXT_STATE <= CLEANUP; + + when CLEANUP => + if( gather_needed_x = '1' ) then + NEXT_STATE <= STORE; + store_ports_x <= '1'; + else + NEXT_STATE <= IDLE; + end if; + + when others => + NEXT_STATE <= IDLE; + end case; + end process THE_STATE_TRANSITIONS; + +end architecture; diff --git a/gbe_trb/base/gbe_lsm.vhd b/gbe_trb/base/gbe_lsm.vhd new file mode 100644 index 0000000..1c9dead --- /dev/null +++ b/gbe_trb/base/gbe_lsm.vhd @@ -0,0 +1,138 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + +entity gbe_lsm is + port( + CLK : in std_logic; + RESET : in std_logic; + -- + MAC_AN_COMPLETE_IN : in std_logic; -- PCS Autonegotiation completed + MAC_READY_CONF_IN : in std_logic; -- MAC configuration completed + MAC_RECONF_OUT : out std_logic; -- start MAC configuration + -- + LINK_ACTIVE_OUT : out std_logic; + -- + DEBUG : out std_logic_vector(15 downto 0) + ); +end entity gbe_lsm; + +architecture gbe_lsm_arch of gbe_lsm is + +-- Components + +-- state machine signals + type state_t is (INACTIVE,WAIT_PCS,ENABLE_MAC,DELAY,ACTIVATED); + signal STATE, NEXT_STATE : state_t; + +-- Signals + signal dly_ctr : unsigned(15 downto 0); + signal ce_dly_ctr : std_logic; + signal rst_dly_ctr : std_logic; + signal dly_ctr_done : std_logic; + signal reconf_mac : std_logic; + +begin + + MAC_RECONF_OUT <= reconf_mac; + + LINK_ACTIVE_OUT <= '1' when (STATE = ACTIVATED) else '0'; + + THE_DLY_CTR: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + dly_ctr <= (others => '0'); + elsif( rst_dly_ctr = '1' ) then + dly_ctr <= (others => '0'); + elsif( ce_dly_ctr = '1' ) then + dly_ctr <= dly_ctr + 1; + end if; + end if; + end process THE_DLY_CTR; + + dly_ctr_done <= '1' when dly_ctr = x"ffff" else '0'; + + ----------------------------------------------------------- + -- statemachine: clocked process + ----------------------------------------------------------- + THE_FSM: process( CLK ) + begin + if( rising_edge(CLK) ) then + if( RESET = '1' ) then + STATE <= INACTIVE; + else + STATE <= NEXT_STATE; + end if; + end if; + end process THE_FSM; + + THE_STATE_TRANSITIONS: process( STATE, MAC_AN_COMPLETE_IN, MAC_READY_CONF_IN, dly_ctr_done ) + begin + reconf_mac <= '0'; + ce_dly_ctr <= '0'; + rst_dly_ctr <= '0'; + + case STATE is + + when INACTIVE => + rst_dly_ctr <= '1'; + if( MAC_AN_COMPLETE_IN = '1' ) then + NEXT_STATE <= WAIT_PCS; + else + NEXT_STATE <= INACTIVE; + end if; + + when WAIT_PCS => + ce_dly_ctr <= '1'; + if( MAC_AN_COMPLETE_IN = '0' ) then + NEXT_STATE <= INACTIVE; + else + if( dly_ctr_done = '1' ) then + NEXT_STATE <= ENABLE_MAC; + reconf_mac <= '1'; + else + NEXT_STATE <= WAIT_PCS; + end if; + end if; + + when ENABLE_MAC => + rst_dly_ctr <= '1'; + if( MAC_AN_COMPLETE_IN = '0' ) then + NEXT_STATE <= INACTIVE; + else + if( MAC_READY_CONF_IN = '1' ) then + NEXT_STATE <= DELAY; + else + NEXT_STATE <= ENABLE_MAC; + end if; + end if; + + when DELAY => + ce_dly_ctr <= '1'; + if( MAC_AN_COMPLETE_IN = '0' ) then + NEXT_STATE <= INACTIVE; + else + if( dly_ctr_done = '1' ) then + NEXT_STATE <= ACTIVATED; + else + NEXT_STATE <= DELAY; + end if; + end if; + + when ACTIVATED => + rst_dly_ctr <= '1'; + if( MAC_AN_COMPLETE_IN = '0' ) then + NEXT_STATE <= INACTIVE; + else + NEXT_STATE <= ACTIVATED; + end if; + + when others => + NEXT_STATE <= INACTIVE; + end case; + end process THE_STATE_TRANSITIONS; + +end architecture; diff --git a/gbe_trb/base/rx_rb.vhd b/gbe_trb/base/rx_rb.vhd new file mode 100644 index 0000000..0c57f46 --- /dev/null +++ b/gbe_trb/base/rx_rb.vhd @@ -0,0 +1,288 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + +entity rx_rb is + port( + CLK : in std_logic; + RESET : in std_logic; + -- MAC interface (RX) + MAC_RX_DATA_IN : in std_logic_vector(7 downto 0); -- RX data from TSMAC + MAC_RX_WR_IN : in std_logic; -- RX data write from TSMAC + MAC_RX_EOF_IN : in std_logic; -- RX EndOfFrame from TSMAC + MAC_RX_ERROR_IN : in std_logic; -- RX Error from TSMAC + MAC_RX_FIFOFULL_OUT : out std_logic; + -- FIFO interface (TX) + FIFO_FULL_IN : in std_logic; -- TX fifo full, delay read from ring buffer + FIFO_WR_OUT : out std_logic; -- TX fifo write + FIFO_Q_OUT : out std_logic_vector(8 downto 0); -- TX data + FRAME_REQ_IN : in std_logic; -- one pulse starts readout of frame stored in ring buffer + FRAME_ACK_OUT : out std_logic; -- one pulse for "end of frame" + FRAME_AVAIL_OUT : out std_logic; -- number of frames stored in ring buffer + FRAME_START_OUT : out std_logic; -- StartOfFrame signal + -- + DEBUG : out std_logic_vector(15 downto 0) + ); +end entity rx_rb; + +architecture rx_rb_arch of rx_rb is + +-- Components + component rb_4k_9 + port( + WRADDRESS : in std_logic_vector(11 downto 0); + RDADDRESS : in std_logic_vector(11 downto 0); + DATA : in std_logic_vector(8 downto 0); + WE : in std_logic; + RDCLOCK : in std_logic; + RDCLOCKEN : in std_logic; + RESET : in std_logic; + WRCLOCK : in std_logic; + WRCLOCKEN : in std_logic; + Q : out std_logic_vector(8 downto 0) + ); + end component rb_4k_9; + +-- state machine signals + type state_t is (RX_DENY,RX_READY,RX_FRAME,FRAME_OK,FRAME_BAD,FORWARD,SKIP); + signal STATE, NEXT_STATE : state_t; + +-- Signals + signal rd_ptr : unsigned(11 downto 0); + signal wr_ptr : unsigned(11 downto 0); + signal last_wr_ptr : std_logic_vector(11 downto 0); + signal rb_used : unsigned(11 downto 0); + signal rb_full : std_logic; + signal rb_empty : std_logic; + signal ce_wr_ptr : std_logic; + signal ld_wr_ptr : std_logic; + signal ce_rd_ptr : std_logic; + signal wr_ram : std_logic; + signal rd_ram : std_logic; + signal ram_q : std_logic_vector(8 downto 0); + signal frame_active : std_logic; + signal frame_requested : std_logic; + signal fifo_wr_int : std_logic; + signal empty_read_ack : std_logic; + signal normal_read_ack : std_logic; + signal sof_int : std_logic; + signal frames_avail : unsigned(7 downto 0); + + +begin + + -- FrameActive: we must not change to "receive" in the middle of a frame + -- when "buffer full" condition is deasserted + THE_FRAME_ACTIVE_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + frame_active <= '0'; + elsif( (MAC_RX_WR_IN = '1') and (frame_active = '0') ) then + frame_active <= '1'; + elsif( (MAC_RX_EOF_IN = '1') and (frame_active = '1') ) then + frame_active <= '0'; + end if; + end if; + end process THE_FRAME_ACTIVE_PROC; + + -- Write pointer for ring buffer + THE_WR_PTR_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + wr_ptr <= (others => '0'); + elsif( ld_wr_ptr = '1' ) then + wr_ptr <= unsigned(last_wr_ptr); + elsif( ce_wr_ptr = '1' ) then + wr_ptr <= wr_ptr + 1; + end if; + end if; + end process THE_WR_PTR_PROC; + + -- Read pointer for ring buffer + THE_RD_PTR_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + rd_ptr <= (others => '0'); + elsif( ce_rd_ptr = '1' ) then + rd_ptr <= rd_ptr + 1; + end if; + end if; + end process THE_RD_PTR_PROC; + + -- ring buffer fill level + rb_used <= wr_ptr - rd_ptr; + + -- ring buffer full + -- TAKE CARE: the last byte of a frame is taken into account + -- by "one less" for the full condition + rb_full <= '1' when (rb_used(11 downto 1) = b"1111_1111_111") else '0'; + + rb_empty <= '1' when (rb_used(11 downto 0) = b"0000_0000_0000") else '0'; + + MAC_RX_FIFOFULL_OUT <= rb_full; + + -- last write pointer: used to drop a broken frame, in case + THE_LAST_WR_PTR_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + last_wr_ptr <= (others => '0'); + elsif( (STATE = RX_READY) and (MAC_RX_WR_IN = '1') ) then + last_wr_ptr <= std_logic_vector(wr_ptr); + end if; + end if; + end process THE_LAST_WR_PTR_PROC; + + -- DPRAM as ring buffer + THE_DP_RAM: rb_4k_9 + port map( + WRADDRESS => std_logic_vector(wr_ptr), + RDADDRESS => std_logic_vector(rd_ptr), + DATA(8) => MAC_RX_EOF_IN, + DATA(7 downto 0) => MAC_RX_DATA_IN, + WE => wr_ram, + RDCLOCK => CLK, + RDCLOCKEN => '1', + RESET => RESET, + WRCLOCK => CLK, + WRCLOCKEN => '1', + Q => ram_q + ); + + -- write signal + wr_ram <= '1' when ((STATE = RX_READY) and (MAC_RX_WR_IN = '1') and (rb_full = '0')) or + ((STATE = RX_FRAME) and (MAC_RX_WR_IN = '1') and (rb_full = '0')) + else '0'; + ce_wr_ptr <= '1' when ((STATE = RX_READY) and (MAC_RX_WR_IN = '1') and (rb_full = '0')) or + ((STATE = RX_FRAME) and (MAC_RX_WR_IN = '1') and (rb_full = '0')) + else '0'; + + -- FrameReq signal, one pulse only + THE_FRAME_REQ_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + frame_requested <= '0'; + elsif( (FRAME_REQ_IN = '1') and (frame_requested = '0') ) then + frame_requested <= '1'; + elsif( ((ram_q(8) = '1') and (frame_requested = '1')) or (empty_read_ack = '1') ) then + frame_requested <= '0'; + end if; + end if; + end process THE_FRAME_REQ_PROC; + + -- EmptyReadAck signal, used to handle a request to RX_RB with no frame to send + empty_read_ack <= FRAME_REQ_IN and rb_empty when rising_edge(CLK); + + -- NormalReadAck signal + normal_read_ack <= ram_q(8) and fifo_wr_int; + + -- read signal + rd_ram <= '1' when ((frame_requested = '1') and (ram_q(8) = '0') and (FIFO_FULL_IN = '0') and (rb_empty = '0')) else '0'; + ce_rd_ptr <= '1' when ((frame_requested = '1') and (ram_q(8) = '0') and (FIFO_FULL_IN = '0') and (rb_empty = '0')) else '0'; + + sof_int <= FRAME_REQ_IN and not frame_requested when rising_edge(CLK); + + FRAME_ACK_OUT <= normal_read_ack or empty_read_ack; + + FRAME_START_OUT <= sof_int; + + FIFO_Q_OUT <= ram_q; + + fifo_wr_int <= rd_ram when rising_edge(CLK); + + FIFO_WR_OUT <= fifo_wr_int; + + -- FramesAvailable counter + THE_FRAMES_AVAIL_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + frames_avail <= (others => '0'); + elsif( (STATE = FRAME_OK) and (normal_read_ack = '0') ) then + -- one frame written successfully + frames_avail <= frames_avail + 1; + elsif( (STATE /= FRAME_OK) and (normal_read_ack = '1') ) then + -- one frame read successfully + frames_avail <= frames_avail - 1; + end if; + end if; + end process THE_FRAMES_AVAIL_PROC; + + FRAME_AVAIL_OUT <= '1' when (frames_avail /= x"00") else '0'; + + ----------------------------------------------------------- + -- statemachine: clocked process + ----------------------------------------------------------- + THE_FSM: process( CLK ) + begin + if( rising_edge(CLK) ) then + if( RESET = '1' ) then + STATE <= RX_DENY; + else + STATE <= NEXT_STATE; + end if; + end if; + end process THE_FSM; + + THE_STATE_TRANSITIONS: process( STATE, MAC_RX_WR_IN, MAC_RX_EOF_IN, MAC_RX_ERROR_IN, frame_active, rb_full ) + begin + ld_wr_ptr <= '0'; + + case STATE is + + when RX_DENY => + if( (frame_active = '0') and (rb_full = '0') ) then + NEXT_STATE <= RX_READY; + else + NEXT_STATE <= RX_DENY; + end if; + + when RX_READY => + if( MAC_RX_WR_IN = '1' ) then + NEXT_STATE <= RX_FRAME; + else + NEXT_STATE <= RX_READY; + end if; + + when RX_FRAME => + if ( (MAC_RX_EOF_IN = '1') and (MAC_RX_ERROR_IN = '0') and (rb_full = '0') ) then + NEXT_STATE <= FRAME_OK; + elsif( (MAC_RX_EOF_IN = '1') and ((MAC_RX_ERROR_IN = '1') or (rb_full = '1')) ) then + NEXT_STATE <= FRAME_BAD; + ld_wr_ptr <= '1'; + else + NEXT_STATE <= RX_FRAME; + end if; + + when FRAME_OK => + NEXT_STATE <= FORWARD; + + when FORWARD => + if( rb_full = '0' ) then + NEXT_STATE <= RX_READY; + else + NEXT_STATE <= RX_DENY; + end if; + + when FRAME_BAD => + NEXT_STATE <= SKIP; + + when SKIP => + if( rb_full = '0' ) then + NEXT_STATE <= RX_READY; + else + NEXT_STATE <= RX_DENY; + end if; + + when others => + NEXT_STATE <= RX_DENY; + end case; + end process THE_STATE_TRANSITIONS; + +end architecture; diff --git a/gbe_trb/base/scatter_ports.vhd b/gbe_trb/base/scatter_ports.vhd new file mode 100644 index 0000000..9e9c24b --- /dev/null +++ b/gbe_trb/base/scatter_ports.vhd @@ -0,0 +1,96 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + +entity scatter_ports is + port( + CLK : in std_logic; + RESET : in std_logic; + -- + FIFO_FULL_IN : in std_logic_vector(15 downto 0) := (others => '0'); + FIFO_FULL_OUT : out std_logic; + FRAME_AVAIL_IN : in std_logic := '0'; + FRAME_REQ_OUT : out std_logic; + FRAME_ACK_IN : in std_logic := '0'; + CYCLE_DONE_OUT : out std_logic; + -- + DEBUG : out std_logic_vector(15 downto 0) + ); +end entity scatter_ports; + +architecture scatter_ports_arch of scatter_ports is + +-- Components + +-- state machine signals + type state_t is (IDLE, DO_PORT, DELAY, CLEANUP); + signal STATE, NEXT_STATE : state_t; + +-- Signals + signal req_int : std_logic; + signal req_x : std_logic; + +begin + + CYCLE_DONE_OUT <= '1' when STATE = CLEANUP else '0'; + + FRAME_REQ_OUT <= req_int; + + FIFO_FULL_OUT <= '0' when FIFO_FULL_IN = x"0000" else '1'; + + ----------------------------------------------------------- + -- statemachine: clocked process + ----------------------------------------------------------- + THE_FSM: process( CLK ) + begin + if( rising_edge(CLK) ) then + if( RESET = '1' ) then + STATE <= IDLE; + req_int <= '0'; + else + STATE <= NEXT_STATE; + req_int <= req_x; + end if; + end if; + end process THE_FSM; + + THE_STATE_TRANSITIONS: process( STATE, FRAME_AVAIL_IN, FRAME_ACK_IN ) + begin + req_x <= '0'; + + case STATE is + + when IDLE => + if( FRAME_AVAIL_IN = '1' ) then + NEXT_STATE <= DO_PORT; + req_x <= '1'; + else + NEXT_STATE <= IDLE; + end if; + + when DO_PORT => + if( FRAME_ACK_IN = '1' ) then + NEXT_STATE <= DELAY; + else + NEXT_STATE <= DO_PORT; + end if; + + when DELAY => + NEXT_STATE <= CLEANUP; + + when CLEANUP => + if( FRAME_AVAIL_IN = '1' ) then + NEXT_STATE <= DO_PORT; + req_x <= '1'; + else + NEXT_STATE <= IDLE; + end if; + + when others => + NEXT_STATE <= IDLE; + end case; + end process THE_STATE_TRANSITIONS; + +end architecture; diff --git a/gbe_trb/base/tx_fifo.vhd b/gbe_trb/base/tx_fifo.vhd new file mode 100644 index 0000000..678143b --- /dev/null +++ b/gbe_trb/base/tx_fifo.vhd @@ -0,0 +1,119 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + +entity tx_fifo is + port( + CLK : in std_logic; + RESET : in std_logic; + -- MAC interface + MAC_TX_DATA_OUT : out std_logic_vector(7 downto 0); + MAC_TX_READ_IN : in std_logic; + MAC_FIFOEOF_OUT : out std_logic; -- end of frame marker + MAC_FIFOEMPTY_OUT : out std_logic; -- must never happen during TX + MAC_FIFOAVAIL_OUT : out std_logic; -- starts TX process in MAC + MAC_TX_DONE_IN : in std_logic; -- frame sent + -- FIFO interface + FIFO_FULL_OUT : out std_logic; + FIFO_WR_IN : in std_logic; + FIFO_D_IN : in std_logic_vector(8 downto 0); + -- Link stuff + FRAME_START_IN : in std_logic; + LINK_ACTIVE_IN : in std_logic; + -- + DEBUG : out std_logic_vector(15 downto 0) + ); +end entity tx_fifo; + +architecture tx_fifo_arch of tx_fifo is + +-- Components + component fifo_4k_9 + port( + DATA : in std_logic_vector(8 downto 0); + CLOCK : in std_logic; + WREN : in std_logic; + RDEN : in std_logic; + RESET : in std_logic; + Q : out std_logic_vector(8 downto 0); + EMPTY : out std_logic; + FULL : out std_logic; + ALMOSTFULL : out std_logic + ); + end component fifo_4k_9; + +-- state machine signals + +-- Signals + signal frames_avail : unsigned(7 downto 0); + signal frame_written : std_logic; + signal frame_read : std_logic; + signal mac_fifoeof : std_logic; + signal mac_tx_read : std_logic; + signal frame_active : std_logic; + signal fifo_wr : std_logic; + +begin + + -- FrameActice signal - used to inhibt acceptance of runt frames + THE_FRAME_ACTIVE_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + frame_active <= '0'; + elsif( FRAME_START_IN = '1' ) then + frame_active <= LINK_ACTIVE_IN; + elsif( frame_written = '1' ) then + frame_active <= '0'; + end if; + end if; + end process THE_FRAME_ACTIVE_PROC; + + fifo_wr <= FIFO_WR_IN and frame_active; + + -- TX FIFO storing full outgoing frames + THE_TX_FIFO: fifo_4k_9 + port map( + DATA => FIFO_D_IN, + CLOCK => CLK, + WREN => fifo_wr, + RDEN => MAC_TX_READ_IN, + RESET => RESET, + Q(8) => mac_fifoeof, + Q(7 downto 0) => MAC_TX_DATA_OUT, + EMPTY => MAC_FIFOEMPTY_OUT, + FULL => open, + ALMOSTFULL => FIFO_FULL_OUT + ); + + MAC_FIFOEOF_OUT <= mac_fifoeof; + + mac_tx_read <= MAC_TX_READ_IN when rising_edge(CLK); + + -- one frame written to FIFO + frame_written <= '1' when (FIFO_D_IN(8) = '1') and (FIFO_WR_IN = '1') and (frame_active = '1') else '0'; + + -- one frame read from FIFO + frame_read <= '1' when (mac_fifoeof = '1') and (mac_tx_read = '1') else '0'; + + -- FramesAvailable counter + THE_FRAMES_AVAIL_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + frames_avail <= (others => '0'); + elsif( (frame_written = '1') and (frame_read = '0') ) then + -- one frame written successfully + frames_avail <= frames_avail + 1; + elsif( (frame_written = '0') and (frame_read = '1') ) then + -- one frame read successfully + frames_avail <= frames_avail - 1; + end if; + end if; + end process THE_FRAMES_AVAIL_PROC; + + MAC_FIFOAVAIL_OUT <= '1' when (frames_avail /= x"00") else '0'; + +end architecture;