-------------------------------------------------------------------------------- -- Title : Receiver FIFO with AxiStream interfaces -- Project : Xilinx LogiCORE Virtex-6 Embedded Tri-Mode Ethernet MAC -- File : rx_client_fifo_8.vhd -- Version : 2.3 ------------------------------------------------------------------------------- -- -- (c) Copyright 2004-2011 Xilinx, Inc. All rights reserved. -- -- This file contains confidential and proprietary information -- of Xilinx, Inc. and is protected under U.S. and -- international copyright and other intellectual property -- laws. -- -- DISCLAIMER -- This disclaimer is not a license and does not grant any -- rights to the materials distributed herewith. Except as -- otherwise provided in a valid license issued to you by -- Xilinx, and to the maximum extent permitted by applicable -- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND -- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES -- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING -- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- -- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and -- (2) Xilinx shall not be liable (whether in contract or tort, -- including negligence, or under any other theory of -- liability) for any loss or damage of any kind or nature -- related to, arising under or in connection with these -- materials, including for any direct, or any indirect, -- special, incidental, or consequential loss or damage -- (including loss of data, profits, goodwill, or any type of -- loss or damage suffered as a result of any action brought -- by a third party) even if such damage or loss was -- reasonably foreseeable or Xilinx had been advised of the -- possibility of the same. -- -- CRITICAL APPLICATIONS -- Xilinx products are not designed or intended to be fail- -- safe, or for use in any application requiring fail-safe -- performance, such as life-support or safety devices or -- systems, Class III medical devices, nuclear facilities, -- applications related to the deployment of airbags, or any -- other applications that could lead to death, personal -- injury, or severe property or environmental damage -- (individually and collectively, "Critical -- Applications"). Customer assumes the sole risk and -- liability of any use of Xilinx products in Critical -- Applications, subject only to applicable laws and -- regulations governing limitations on product liability. -- -- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS -- PART OF THIS FILE AT ALL TIMES. -- -------------------------------------------------------------------------------- -- Description: This is the receiver side FIFO for the design example -- of the core. AxiStream interfaces are used. -- -- The FIFO is created from 2 Block RAMs of size 2048 -- words of 8-bits per word, giving a total frame memory capacity -- of 4096 bytes. -- -- Frame data received from the MAC receiver is written into the -- FIFO on the rx_mac_aclk. An end-of-frame marker is written to -- the BRAM parity bit on the last byte of data stored for a frame. -- This acts as frame deliniation. -- -- The rx_axis_mac_tvalid, rx_axis_mac_tlast, and rx_axis_mac_tuser signals -- qualify the frame. A frame which ends with rx_axis_mac_tuser asserted -- indicates a bad frame and will cause the FIFO write address -- pointer to be reset to the base address of that frame. In this -- way the bad frame will be overwritten with the next received -- frame and is therefore dropped from the FIFO. -- -- Frames will also be dropped from the FIFO if an overflow occurs. -- If there is not enough memory capacity in the FIFO to store the -- whole of an incoming frame, the write address pointer will be -- reset and the overflow signal asserted. -- -- When there is at least one complete frame in the FIFO, -- the 8-bit AxiStream read interface's rx_axis_fifo_tvalid signal will -- be enabled allowing data to be read from the FIFO. -- -- The FIFO has been designed to operate with different clocks -- on the write and read sides. The read clock (user side) should -- always operate at an equal or faster frequency than the write -- clock (MAC side). -- -- The FIFO is designed to work with a minimum frame length of 8 -- bytes. -- -- The FIFO memory size can be increased by expanding the rd_addr -- and wr_addr signal widths, to address further BRAMs. -- -- Requirements : -- * Minimum frame size of 8 bytes -- * Spacing between good/bad frame signaling (encoded by -- rx_axis_mac_tvalid, rx_axis_mac_tlast, rx_axis_mac_tuser), is at least 64 -- clock cycles -- * Write AxiStream clock is 125MHz downto 1.25MHz -- * Read AxiStream clock equal to or faster than write clock, -- and downto 20MHz -- -------------------------------------------------------------------------------- library unisim; use unisim.vcomponents.all; library unimacro; use unimacro.vcomponents.all; library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; -------------------------------------------------------------------------------- -- The entity declaration for the Receiver FIFO -------------------------------------------------------------------------------- entity rx_client_fifo_8 is port ( -- User-side (read-side) AxiStream interface rx_fifo_aclk : in std_logic; rx_fifo_resetn : in std_logic; rx_axis_fifo_tdata : out std_logic_vector(7 downto 0); rx_axis_fifo_tvalid : out std_logic; rx_axis_fifo_tlast : out std_logic; rx_axis_fifo_tready : in std_logic; -- MAC-side (write-side) AxiStream interface rx_mac_aclk : in std_logic; rx_mac_resetn : in std_logic; rx_axis_mac_tdata : in std_logic_vector(7 downto 0); rx_axis_mac_tvalid : in std_logic; rx_axis_mac_tlast : in std_logic; rx_axis_mac_tready : out std_logic; rx_axis_mac_tuser : in std_logic; -- FIFO status and overflow indication, -- synchronous to write-side (rx_mac_aclk) interface fifo_status : out std_logic_vector(3 downto 0); fifo_overflow : out std_logic ); end rx_client_fifo_8; architecture RTL of rx_client_fifo_8 is ------------------------------------------------------------------------------ -- Component declaration for the synchronization flip-flop pair ------------------------------------------------------------------------------ component sync_block port ( clk : in std_logic; data_in : in std_logic; data_out : out std_logic ); end component; ------------------------------------------------------------------------------ -- Define internal signals ------------------------------------------------------------------------------ signal VCC : std_logic; signal GND_BUS : std_logic_vector(8 downto 0); signal GND : std_logic_vector(0 downto 0); -- Encoded read state machine states type rd_state_typ is (WAIT_s, QUEUE1_s, QUEUE2_s, QUEUE3_s, QUEUE_SOF_s, SOF_s, DATA_s, EOF_s); signal rd_state : rd_state_typ; signal rd_nxt_state : rd_state_typ; -- Encoded write state machine states type wr_state_typ is (IDLE_s, FRAME_s, GF_s, BF_s, OVFLOW_s); signal wr_state : wr_state_typ; signal wr_nxt_state : wr_state_typ; type data_pipe is array (0 to 1) of std_logic_vector(7 downto 0); type cntl_pipe_long is array(0 to 2) of std_logic; type cntl_pipe_short is array(0 to 1) of std_logic; signal wr_en : std_logic; signal wr_en_u : std_logic; signal wr_en_u_bram : std_logic_vector(0 downto 0); signal wr_en_l : std_logic; signal wr_en_l_bram : std_logic_vector(0 downto 0); signal wr_addr : unsigned(11 downto 0); signal wr_addr_inc : std_logic; signal wr_start_addr_load : std_logic; signal wr_addr_reload : std_logic; signal wr_start_addr : unsigned(11 downto 0); signal wr_eof_data_bram : std_logic_vector(8 downto 0); signal wr_data_bram : std_logic_vector(7 downto 0); signal wr_data_pipe : data_pipe; signal wr_dv_pipe : cntl_pipe_long; signal wr_gfbf_pipe : cntl_pipe_short; signal wr_gf : std_logic; signal wr_bf : std_logic; signal wr_eof_bram_pipe : cntl_pipe_short; signal wr_eof_bram : std_logic; signal frame_in_fifo : std_logic; signal rd_addr : unsigned(11 downto 0); signal rd_addr_inc : std_logic; signal rd_addr_reload : std_logic; signal rd_eof_data_bram_u : std_logic_vector(8 downto 0); signal rd_eof_data_bram_l : std_logic_vector(8 downto 0); signal rd_data_bram_u : std_logic_vector(7 downto 0); signal rd_data_bram_l : std_logic_vector(7 downto 0); signal rd_data_pipe_u : std_logic_vector(7 downto 0); signal rd_data_pipe_l : std_logic_vector(7 downto 0); signal rd_data_pipe : std_logic_vector(7 downto 0); signal rd_valid_pipe : std_logic_vector(1 downto 0); signal rd_eof_bram_u : std_logic_vector(0 downto 0); signal rd_eof_bram_l : std_logic_vector(0 downto 0); signal rd_en : std_logic; signal rd_bram_u : std_logic; signal rd_bram_u_reg : std_logic; signal rd_pull_frame : std_logic; signal rd_eof : std_logic; signal wr_store_frame_tog : std_logic := '0'; signal rd_store_frame_sync : std_logic; signal rd_store_frame_delay : std_logic := '0'; signal rd_store_frame : std_logic; signal rd_frames : std_logic_vector(8 downto 0); signal wr_fifo_full : std_logic; signal old_rd_addr : std_logic_vector(1 downto 0); signal update_addr_tog : std_logic; signal update_addr_tog_sync : std_logic; signal update_addr_tog_sync_reg : std_logic; signal wr_rd_addr : unsigned(11 downto 0); signal wr_addr_diff_in : unsigned(12 downto 0); signal wr_addr_diff : unsigned(11 downto 0); signal wr_fifo_status : unsigned(3 downto 0); signal rx_axis_fifo_tlast_int : std_logic; signal doa_l_unused : std_logic_vector(8 downto 0); signal doa_u_unused : std_logic_vector(8 downto 0); signal rx_fifo_reset : std_logic; signal rx_mac_reset : std_logic; -------------------------------------------------------------------------------- -- Begin FIFO architecture -------------------------------------------------------------------------------- begin VCC <= '1'; GND_BUS <= (others => '0'); GND(0) <= GND_BUS(0); -- invert reset sense as architecture is optimized for active high resets rx_fifo_reset <= not rx_fifo_resetn; rx_mac_reset <= not rx_mac_resetn; ------------------------------------------------------------------------------ -- Read state machines and control ------------------------------------------------------------------------------ -- Read state machine. -- States are WAIT, QUEUE1, QUEUE2, QUEUE3, QUEUE_SOF, SOF, DATA, EOF. -- Clock state to next state. clock_rds_p : process(rx_fifo_aclk) begin if (rx_fifo_aclk'event and rx_fifo_aclk = '1') then if rx_fifo_reset = '1' then rd_state <= WAIT_s; else rd_state <= rd_nxt_state; end if; end if; end process clock_rds_p; rx_axis_fifo_tlast <= rx_axis_fifo_tlast_int; -- Decode next state, combinatorial. next_rds_p : process(rd_state, frame_in_fifo, rd_eof, rx_axis_fifo_tready, rx_axis_fifo_tlast_int, rd_valid_pipe) begin case rd_state is when WAIT_s => -- Wait until there is a full frame in the FIFO, then -- start to load the pipeline. if frame_in_fifo = '1' and rx_axis_fifo_tlast_int = '0' then rd_nxt_state <= QUEUE1_s; else rd_nxt_state <= WAIT_s; end if; -- Load the output pipeline, which takes three clock cycles. when QUEUE1_s => rd_nxt_state <= QUEUE2_s; when QUEUE2_s => rd_nxt_state <= QUEUE3_s; when QUEUE3_s => rd_nxt_state <= QUEUE_SOF_s; when QUEUE_SOF_s => -- The pipeline is full and the frame output starts now. rd_nxt_state <= DATA_s; when SOF_s => -- A new frame begins immediately following end of last frame. if rx_axis_fifo_tready = '1' then rd_nxt_state <= DATA_s; else rd_nxt_state <= SOF_s; end if; when DATA_s => -- Read data from the FIFO. When the EOF marker is detected from -- the BRAM output, move to the EOF state. if rx_axis_fifo_tready = '1' and rd_eof = '1' then rd_nxt_state <= EOF_s; else rd_nxt_state <= DATA_s; end if; when EOF_s => -- Hold in this state until tready is asserted and the EOF -- marker (tlast) is accepted on interface. -- If there is another frame in the FIFO, then it will already be -- queued into the pipeline so so move straight to SOF state. if rx_axis_fifo_tready = '1' then if rd_valid_pipe(1) = '1' then rd_nxt_state <= SOF_s; else rd_nxt_state <= WAIT_s; end if; else rd_nxt_state <= EOF_s; end if; when others => rd_nxt_state <= WAIT_s; end case; end process next_rds_p; -- Detect if frame_in_fifo was high 3 reads ago. -- This is used to ensure we only treat data in the pipeline as valid if -- frame_in_fifo goes high at or before the EOF marker of the current frame. -- It may be that there is valid data (i.e a partial frame has been written) -- but until the end of that frame we do not know if it is a good frame. rd_valid_pipe_p : process(rx_fifo_aclk) begin if (rx_fifo_aclk'event and rx_fifo_aclk = '1') then if (rx_axis_fifo_tready = '1') then rd_valid_pipe <= rd_valid_pipe(0) & frame_in_fifo; end if; end if; end process rd_valid_pipe_p; -- Decode tlast signal from EOF marker. rd_ll_decode_p : process(rx_fifo_aclk) begin if (rx_fifo_aclk'event and rx_fifo_aclk = '1') then if rx_fifo_reset = '1' then rx_axis_fifo_tlast_int <= '0'; elsif rx_axis_fifo_tready = '1' then -- Assert tlast signal when the EOF marker has been detected, and -- continue to drive it until it has been accepted on the interface. case rd_state is when EOF_s => rx_axis_fifo_tlast_int <= '1'; when others => rx_axis_fifo_tlast_int <= '0'; end case; end if; end if; end process rd_ll_decode_p; -- Decode the tvalid output based on state. rd_ll_src_p : process(rx_fifo_aclk) begin if (rx_fifo_aclk'event and rx_fifo_aclk = '1') then if rx_fifo_reset = '1' then rx_axis_fifo_tvalid <= '0'; else case rd_state is when QUEUE_SOF_s => rx_axis_fifo_tvalid <= '1'; when SOF_s => rx_axis_fifo_tvalid <= '1'; when DATA_s => rx_axis_fifo_tvalid <= '1'; when EOF_s => rx_axis_fifo_tvalid <= '1'; when others => if rx_axis_fifo_tready = '1' then rx_axis_fifo_tvalid <= '0'; end if; end case; end if; end if; end process rd_ll_src_p; -- Decode internal control signals. -- rd_en is used to enable the BRAM read and load the output pipeline. rd_en_p : process(rd_state, rx_axis_fifo_tready) begin case rd_state is when WAIT_s => rd_en <= '0'; when QUEUE1_s => rd_en <= '1'; when QUEUE2_s => rd_en <= '1'; when QUEUE3_s => rd_en <= '1'; when QUEUE_SOF_s => rd_en <= '1'; when others => rd_en <= rx_axis_fifo_tready; end case; end process rd_en_p; -- When the BRAM is being read, enable the read address to be incremented. rd_addr_inc <= rd_en; -- When the current frame is done, and if there is no frame in the FIFO, then -- the FIFO must wait until a new frame is written in. This requires the read -- address to be moved back to where the new frame will be written. The -- pipeline is then reloaded using the QUEUE states. p_rd_addr_reload : process (rx_fifo_aclk) begin if rx_fifo_aclk'event and rx_fifo_aclk = '1' then if rx_fifo_reset = '1' then rd_addr_reload <= '0'; else if rd_state = EOF_s and rd_nxt_state = WAIT_s then rd_addr_reload <= '1'; else rd_addr_reload <= '0'; end if; end if; end if; end process p_rd_addr_reload; -- Data is available if there is at least one frame stored in the FIFO. p_rd_avail : process (rx_fifo_aclk) begin if rx_fifo_aclk'event and rx_fifo_aclk = '1' then if rx_fifo_reset = '1' then frame_in_fifo <= '0'; else if rd_frames /= (rd_frames'range => '0') then frame_in_fifo <= '1'; else frame_in_fifo <= '0'; end if; end if; end if; end process p_rd_avail; -- When a frame has been stored we need to synchronize that event to the -- read clock domain for frame count store. resync_wr_store_frame_tog : sync_block port map ( clk => rx_fifo_aclk, data_in => wr_store_frame_tog, data_out => rd_store_frame_sync ); p_delay_rd_store : process (rx_fifo_aclk) begin if rx_fifo_aclk'event and rx_fifo_aclk = '1' then rd_store_frame_delay <= rd_store_frame_sync; end if; end process p_delay_rd_store; -- Edge detect of the resynchronized frame count. This creates a pulse -- when a new frame has been stored. p_sync_rd_store : process (rx_fifo_aclk) begin if rx_fifo_aclk'event and rx_fifo_aclk = '1' then if rx_fifo_reset = '1' then rd_store_frame <= '0'; else -- Edge detector if (rd_store_frame_delay xor rd_store_frame_sync) = '1' then rd_store_frame <= '1'; else rd_store_frame <= '0'; end if; end if; end if; end process p_sync_rd_store; -- This creates a pulse when a new frame has begun to be output. p_rd_pull_frame : process (rx_fifo_aclk) begin if rx_fifo_aclk'event and rx_fifo_aclk = '1' then if rx_fifo_reset = '1' then rd_pull_frame <= '0'; else if rd_state = SOF_s and rd_nxt_state /= SOF_s then rd_pull_frame <= '1'; elsif rd_state = QUEUE_SOF_s and rd_nxt_state /= QUEUE_SOF_s then rd_pull_frame <= '1'; else rd_pull_frame <= '0'; end if; end if; end if; end process p_rd_pull_frame; -- Up/down counter to monitor the number of frames stored within the FIFO. -- Note: -- * increments at the end of a frame write cycle -- * decrements at the beginning of a frame read cycle p_rd_frames : process (rx_fifo_aclk) begin if rx_fifo_aclk'event and rx_fifo_aclk = '1' then if rx_fifo_reset = '1' then rd_frames <= (others => '0'); else -- A frame is written to the FIFO in this cycle, and no frame is being -- read out on the same cycle. if rd_store_frame = '1' and rd_pull_frame = '0' then rd_frames <= rd_frames + 1; -- A frame is being read out on this cycle and no frame is being -- written on the same cycle. elsif rd_store_frame = '0' and rd_pull_frame = '1' then rd_frames <= rd_frames - 1; end if; end if; end if; end process p_rd_frames; ------------------------------------------------------------------------------ -- Write state machines and control ------------------------------------------------------------------------------ -- Write state machine. -- States are IDLE, FRAME, GF, BF, OVFLOW. -- Clock state to next state. clock_wrs_p : process(rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then if rx_mac_reset = '1' then wr_state <= IDLE_s; else wr_state <= wr_nxt_state; end if; end if; end process clock_wrs_p; -- Decode next state, combinatorial. next_wrs_p : process(wr_state, wr_dv_pipe(1), wr_gf, wr_bf, wr_fifo_full) begin case wr_state is when IDLE_s => -- There is data in incoming pipeline when dv_pipe(1) goes high. if wr_dv_pipe(1) = '1' then wr_nxt_state <= FRAME_s; else wr_nxt_state <= IDLE_s; end if; when FRAME_s => -- If FIFO is full then go to overflow state. -- If the good or bad flag is detected, then the end of the frame -- has been reached and the gf or bf state is visited before idle. -- Otherwise remain in frame state while data is written to FIFO. if wr_fifo_full = '1' then wr_nxt_state <= OVFLOW_s; elsif wr_gf = '1' then wr_nxt_state <= GF_s; elsif wr_bf = '1' then wr_nxt_state <= BF_s; else wr_nxt_state <= FRAME_s; end if; when GF_s => -- Return to idle and wait for next frame. wr_nxt_state <= IDLE_s; when BF_s => -- Return to idle and wait for next frame. wr_nxt_state <= IDLE_s; when OVFLOW_s => -- Wait until the good or bad flag received. if wr_gf = '1' or wr_bf = '1' then wr_nxt_state <= IDLE_s; else wr_nxt_state <= OVFLOW_s; end if; when others => wr_nxt_state <= IDLE_s; end case; end process next_wrs_p; -- Decode control signals, combinatorial. -- wr_en is used to enable the BRAM write and loading of the input pipeline. wr_en <= wr_dv_pipe(2) when wr_state = FRAME_s else '0'; -- The upper and lower signals are used to distinguish between the upper and -- lower BRAMs. wr_en_l <= wr_en and not(wr_addr(11)); wr_en_u <= wr_en and wr_addr(11); wr_en_l_bram(0) <= wr_en_l; wr_en_u_bram(0) <= wr_en_u; -- Increment the write address when we are receiving valid frame data. wr_addr_inc <= wr_dv_pipe(2) when wr_state = FRAME_s else '0'; -- If the FIFO overflows or a frame is to be dropped, we need to move the -- write address back to the start of the frame. This allows the data to be -- overwritten. wr_addr_reload <= '1' when wr_state = BF_s or wr_state = OVFLOW_s else '0'; -- The start address is saved when in the idle state. wr_start_addr_load <= '1' when wr_state = IDLE_s else '0'; -- We need to know when a frame is stored, in order to increment the count of -- frames stored in the FIFO. p_wr_store_tog : process (rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then if wr_state = GF_s then wr_store_frame_tog <= not wr_store_frame_tog; end if; end if; end process; ------------------------------------------------------------------------------ -- Address counters ------------------------------------------------------------------------------ -- Write address is incremented when data is being written into the FIFO. wr_addr_p : process(rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then if rx_mac_reset = '1' then wr_addr <= (others => '0'); else if wr_addr_reload = '1' then wr_addr <= wr_start_addr; elsif wr_addr_inc = '1' then wr_addr <= wr_addr + 1; end if; end if; end if; end process wr_addr_p; -- Store the start address. wr_staddr_p : process(rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then if rx_mac_reset = '1' then wr_start_addr <= (others => '0'); else if wr_start_addr_load = '1' then wr_start_addr <= wr_addr; end if; end if; end if; end process wr_staddr_p; -- Read address is incremented when data is being read from the FIFO. rd_addr_p : process(rx_fifo_aclk) begin if (rx_fifo_aclk'event and rx_fifo_aclk = '1') then if rx_fifo_reset = '1' then rd_addr <= (others => '0'); else if rd_addr_reload = '1' then rd_addr <= rd_addr - 3; elsif rd_addr_inc = '1' then rd_addr <= rd_addr + 1; end if; end if; end if; end process rd_addr_p; -- Which BRAM is read from is dependent on the upper bit of the address -- space. This needs to be registered to give the correct timing. rd_bram_p : process(rx_fifo_aclk) begin if (rx_fifo_aclk'event and rx_fifo_aclk = '1') then if rx_fifo_reset = '1' then rd_bram_u <= '0'; rd_bram_u_reg <= '0'; elsif rd_addr_inc = '1' then rd_bram_u <= rd_addr(11); rd_bram_u_reg <= rd_bram_u; end if; end if; end process rd_bram_p; ------------------------------------------------------------------------------ -- Data pipelines ------------------------------------------------------------------------------ -- Register data inputs to BRAM. -- No resets to allow for SRL16 target. reg_din_p : process(rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then wr_data_pipe(0) <= rx_axis_mac_tdata; wr_data_pipe(1) <= wr_data_pipe(0); wr_data_bram <= wr_data_pipe(1); end if; end process reg_din_p; -- The valid input enables BRAM write and is a condition for other signals. reg_dv_p : process(rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then wr_dv_pipe(0) <= rx_axis_mac_tvalid; wr_dv_pipe(1) <= wr_dv_pipe(0); wr_dv_pipe(2) <= wr_dv_pipe(1); end if; end process reg_dv_p; -- End of frame flag set when tlast and tvalid are asserted together. reg_eof_p : process(rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then wr_eof_bram_pipe(0) <= rx_axis_mac_tlast; wr_eof_bram_pipe(1) <= wr_eof_bram_pipe(0); wr_eof_bram <= wr_eof_bram_pipe(1) and wr_dv_pipe(1); end if; end process reg_eof_p; -- Upon arrival of EOF flag, the frame is good if tuser signal -- is low, and bad if tuser signal is high. reg_gf_p : process(rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then wr_gfbf_pipe(0) <= rx_axis_mac_tuser; wr_gfbf_pipe(1) <= wr_gfbf_pipe(0); wr_gf <= (not wr_gfbf_pipe(1)) and wr_eof_bram_pipe(1) and wr_dv_pipe(1); wr_bf <= wr_gfbf_pipe(1) and wr_eof_bram_pipe(1) and wr_dv_pipe(1); end if; end process reg_gf_p; -- The MAC's RX path cannot be held off, so the tready signal is always high. reg_ready_p : process(rx_mac_aclk) begin if (rx_mac_aclk'event and rx_mac_aclk = '1') then if (rx_mac_reset = '1') then rx_axis_mac_tready <= '0'; else rx_axis_mac_tready <= '1'; end if; end if; end process reg_ready_p; -- Register data outputs from BRAM. -- No resets to allow for SRL16 target. reg_dout_p : process(rx_fifo_aclk) begin if (rx_fifo_aclk'event and rx_fifo_aclk = '1') then if rd_en = '1' then rd_data_pipe_u <= rd_data_bram_u; rd_data_pipe_l <= rd_data_bram_l; if rd_bram_u_reg = '1' then rd_data_pipe <= rd_data_pipe_u; else rd_data_pipe <= rd_data_pipe_l; end if; rx_axis_fifo_tdata <= rd_data_pipe; end if; end if; end process reg_dout_p; reg_eofout_p : process(rx_fifo_aclk) begin if (rx_fifo_aclk'event and rx_fifo_aclk = '1') then if rd_en = '1' then if rd_bram_u = '1' then rd_eof <= rd_eof_bram_u(0); else rd_eof <= rd_eof_bram_l(0); end if; end if; end if; end process reg_eofout_p; ------------------------------------------------------------------------------ -- Overflow functionality ------------------------------------------------------------------------------ -- To minimize the number of read address updates the bottom 6 bits of the -- read address are not passed across and the write domain will only sample -- them when bits 5 and 4 of the read address transition from 01 to 10. -- Since this is for full detection this just means that if the read stops -- the write will hit full up to 64 locations early -- need to use two bits and look for an increment transition as reload can cause -- a decrement on this boundary (decrement is only by 3 so above bit 2 should be safe) p_rd_addr_tog : process (rx_fifo_aclk) begin if rx_fifo_aclk'event and rx_fifo_aclk = '1' then if rx_fifo_reset = '1' then old_rd_addr <= (others => '0'); update_addr_tog <= '0'; else old_rd_addr <= std_logic_vector(rd_addr(5 downto 4)); if rd_addr(5 downto 4) = "10" and old_rd_addr = "01" then update_addr_tog <= not update_addr_tog; end if; end if; end if; end process p_rd_addr_tog; sync_rd_addr_tog: sync_block port map ( clk => rx_mac_aclk, data_in => update_addr_tog, data_out => update_addr_tog_sync ); -- Obtain the difference between write and read pointers. p_sample_addr : process (rx_mac_aclk) begin if rx_mac_aclk'event and rx_mac_aclk = '1' then if rx_mac_reset = '1' then update_addr_tog_sync_reg <= '0'; wr_rd_addr <= (others => '0'); else update_addr_tog_sync_reg <= update_addr_tog_sync; if update_addr_tog_sync_reg /= update_addr_tog_sync then wr_rd_addr <= rd_addr(11 downto 6) & "000000"; end if; end if; end if; end process p_sample_addr; wr_addr_diff_in <= ('0' & wr_rd_addr) - ('0' & wr_addr); -- Obtain the difference between write and read pointers. p_addr_diff : process (rx_mac_aclk) begin if rx_mac_aclk'event and rx_mac_aclk = '1' then if rx_mac_reset = '1' then wr_addr_diff <= (others => '0'); else wr_addr_diff <= wr_addr_diff_in(11 downto 0); end if; end if; end process p_addr_diff; -- Detect when the FIFO is full. -- The FIFO is considered to be full if the write address pointer is -- within 0 to 3 of the read address pointer. p_wr_full : process (rx_mac_aclk) begin if rx_mac_aclk'event and rx_mac_aclk = '1' then if rx_mac_reset = '1' then wr_fifo_full <= '0'; else if wr_addr_diff(11 downto 4) = 0 and wr_addr_diff(3 downto 2) /= "00" then wr_fifo_full <= '1'; else wr_fifo_full <= '0'; end if; end if; end if; end process p_wr_full; -- Decode the overflow indicator output. fifo_overflow <= '1' when wr_state = OVFLOW_s else '0'; ------------------------------------------------------------------------------ -- FIFO status signals ------------------------------------------------------------------------------ -- The FIFO status is four bits which represents the occupancy of the FIFO -- in sixteenths. To generate this signal we therefore only need to compare -- the 4 most significant bits of the write address pointer with the 4 most -- significant bits of the read address pointer. p_wr_fifo_status : process (rx_mac_aclk) begin if rx_mac_aclk'event and rx_mac_aclk = '1' then if rx_mac_reset = '1' then wr_fifo_status <= "0000"; else if wr_addr_diff = (wr_addr_diff'range => '0') then wr_fifo_status <= "0000"; else wr_fifo_status(3) <= not wr_addr_diff(11); wr_fifo_status(2) <= not wr_addr_diff(10); wr_fifo_status(1) <= not wr_addr_diff(9); wr_fifo_status(0) <= not wr_addr_diff(8); end if; end if; end if; end process p_wr_fifo_status; fifo_status <= std_logic_vector(wr_fifo_status); ------------------------------------------------------------------------------ -- Instantiate FIFO block memory ------------------------------------------------------------------------------ wr_eof_data_bram(8) <= wr_eof_bram; wr_eof_data_bram(7 downto 0) <= wr_data_bram; -- Block RAM for lower address space (rx_addr(11) = '0') rd_eof_bram_l(0) <= rd_eof_data_bram_l(8); rd_data_bram_l <= rd_eof_data_bram_l(7 downto 0); ramgen_l : BRAM_TDP_MACRO generic map ( DEVICE => "VIRTEX6", BRAM_SIZE => "18Kb", WRITE_WIDTH_A => 9, WRITE_WIDTH_B => 9, READ_WIDTH_A => 9, READ_WIDTH_B => 9) port map ( DOA => doa_l_unused, DOB => rd_eof_data_bram_l, ADDRA => std_logic_vector(wr_addr(10 downto 0)), ADDRB => std_logic_vector(rd_addr(10 downto 0)), CLKA => rx_mac_aclk, CLKB => rx_fifo_aclk, DIA => wr_eof_data_bram, DIB => GND_BUS(8 downto 0), ENA => VCC, ENB => rd_en, REGCEA => VCC, REGCEB => VCC, RSTA => rx_mac_reset, RSTB => rx_fifo_reset, WEA => wr_en_l_bram, WEB => GND ); -- Block RAM for upper address space (rx_addr(11) = '1') rd_eof_bram_u(0) <= rd_eof_data_bram_u(8); rd_data_bram_u <= rd_eof_data_bram_u(7 downto 0); ramgen_u : BRAM_TDP_MACRO generic map ( DEVICE => "VIRTEX6", BRAM_SIZE => "18Kb", WRITE_WIDTH_A => 9, WRITE_WIDTH_B => 9, READ_WIDTH_A => 9, READ_WIDTH_B => 9) port map ( DOA => doa_u_unused, DOB => rd_eof_data_bram_u, ADDRA => std_logic_vector(wr_addr(10 downto 0)), ADDRB => std_logic_vector(rd_addr(10 downto 0)), CLKA => rx_mac_aclk, CLKB => rx_fifo_aclk, DIA => wr_eof_data_bram, DIB => GND_BUS(8 downto 0), ENA => VCC, ENB => rd_en, REGCEA => VCC, REGCEB => VCC, RSTA => rx_mac_reset, RSTB => rx_fifo_reset, WEA => wr_en_u_bram, WEB => GND ); end RTL;