---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 03/28/2019 11:41:06 AM -- Design Name: -- Module Name: ngFEC_top - Behavioral -- Project Name: -- Target Devices: -- Tool Versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; --use ieee.std_logic_unsigned.all; --use ieee.std_logic_arith.all; use ieee.numeric_std.all; use IEEE.std_logic_misc.all; use work.ngFEC_pack.all; Library xpm; use xpm.vcomponents.all; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --use IEEE.NUMERIC_STD.ALL; -- Uncomment the following library declaration if instantiating -- any Xilinx leaf cells in this code. library UNISIM; use UNISIM.VComponents.all; entity AXI4_to_ipbus is Generic (aclk_period : integer := 8); -- unit in ns Port ( c2c_link_up : in std_logic; aclk : in std_logic; aresetn : in std_logic; axi_in : in axi_wbus; axi_out : out axi_rbus; ipb_clk : in std_logic; ipb_in : in ipb_rbus; ipb_out : out ipb_wbus; axi_status : out std_logic_vector(31 DOWNTO 0) ); end AXI4_to_ipbus; architecture Behavioral of AXI4_to_ipbus is component srl_fiforeg generic (N: integer := 16); port ( rst: in STD_LOGIC; clk: in STD_LOGIC; write: in STD_LOGIC; read: in STD_LOGIC; din: in STD_LOGIC_VECTOR (N-1 downto 0); dout: out STD_LOGIC_VECTOR (N-1 downto 0); empty: out STD_LOGIC ); end component; constant bit_ipb_err_flag : integer := 32; constant TIMEOUT : integer := integer(2000/aclk_period); signal idle_flag : std_logic := '0'; signal burst_flag : std_logic := '0'; signal addr_wrap : std_logic := '0'; signal word_cntr : unsigned(7 downto 0) := (others => '0'); signal length_cntr : unsigned(7 downto 0) := (others => '0'); signal axi_alen : std_logic_vector(7 downto 0) := (others => '0'); signal axi_id : std_logic_vector(5 downto 0) := (others => '0'); signal w_ipb_err : std_logic := '0'; signal w_strb_err : std_logic := '0'; signal w_wrap_err : std_logic := '0'; signal w_length_err : std_logic := '0'; signal r_wrap_err : std_logic := '0'; signal r_length_err : std_logic := '0'; signal waddr_err : std_logic := '0'; signal raddr_err : std_logic := '0'; signal timeout_err : std_logic := '0'; signal bvalid : std_logic := '0'; signal rd_strobe : std_logic := '0'; signal ipb_addr : unsigned(31 downto 0) := x"60000000"; signal ipb_toggle : std_logic := '0'; signal ipb_toggle_q : std_logic := '0'; signal ipb_phase : std_logic_vector(3 downto 1) := (others => '0'); signal ipb_strobe : std_logic := '0'; signal ipb_write : std_logic := '0'; signal ipb_full : std_logic := '0'; signal ipb_cntr : unsigned(3 downto 0) := (others => '0'); signal axi_addr : unsigned(9 downto 0) := (others => '0'); signal reset : std_logic := '0'; signal FIFO_reset : std_logic := '0'; signal w_FIFO_empty : std_logic := '0'; signal w_FIFO_rden : std_logic := '0'; signal w_FIFO_wren : std_logic := '0'; signal r_FIFO_empty : std_logic := '0'; signal r_FIFO_rden : std_logic := '0'; signal r_FIFO_wren : std_logic := '0'; signal w_FIFO_a : unsigned(3 downto 0) := (others => '1'); signal w_FIFO_do : std_logic_vector(31 downto 0) := (others => '0'); signal r_FIFO_a : unsigned(3 downto 0) := (others => '1'); signal r_FIFO_din : std_logic_vector(32 downto 0) := (others => '0'); signal r_FIFO_do : std_logic_vector(32 downto 0) := (others => '0'); signal timer : unsigned(7 downto 0) := (others => '0'); type state is (idle, w_data,r_data, w_abort, r_abort, clearFIFO); signal axi_state : state := idle; begin axi_out.c2c_link_up <= c2c_link_up; ipb_out.ipb_strobe <= ipb_strobe; process(ipb_clk) begin if(ipb_clk'event and ipb_clk = '1')then if(idle_flag = '0' and w_FIFO_empty = '0')then ipb_strobe <= '1'; else ipb_strobe <= '0'; end if; ipb_out.ipb_write <= ipb_write; ipb_out.ipb_addr <= std_logic_vector(ipb_addr); ipb_out.ipb_wdata <=w_FIFO_do; r_FIFO_din <= ipb_in.ipb_err & ipb_in.ipb_rdata; end if; end process; axi_out.axi_bid <= axi_id; axi_out.axi_rid <= axi_id; axi_out.axi_awready <= idle_flag; axi_out.axi_wready <= '1' when axi_state = w_data else '0'; axi_out.axi_arready <= idle_flag; axi_out.axi_rvalid <= '1' when axi_state = r_abort or (axi_state = r_data and r_FIFO_empty = '0') else '0'; axi_out.axi_rdata <= r_FIFO_do(31 downto 0); axi_out.axi_bvalid <= bvalid; axi_out.axi_rlast <= '1' when axi_state = r_abort or std_logic_vector(word_cntr) = axi_alen else '0'; process(aclk) begin if(aclk'event and aclk = '1')then if(idle_flag = '1' and axi_in.axi_arvalid = '1')then ipb_addr(29 downto 0) <= unsigned(axi_in.axi_araddr(31 downto 2)); elsif(idle_flag = '1' and axi_in.axi_awvalid = '1')then ipb_addr(29 downto 0) <= unsigned(axi_in.axi_awaddr(31 downto 2)); elsif(burst_flag = '1' and w_FIFO_rden = '1')then ipb_addr(9 downto 0) <= ipb_addr(9 downto 0) + 1; end if; r_FIFO_wren <= ipb_phase(3) and (ipb_in.ipb_ack or ipb_in.ipb_err); if(ipb_phase(3) = '1' and w_FIFO_empty = '0')then w_FIFO_rden <= '1'; else w_FIFO_rden <= '0'; end if; end if; end process; process(aclk, aresetn) begin if(aresetn = '0')then axi_state <= idle; idle_flag <= '1'; rd_strobe <= '0'; waddr_err <= '0'; raddr_err <= '0'; w_ipb_err <= '0'; w_strb_err <= '0'; w_wrap_err <= '0'; w_length_err <= '0'; r_wrap_err <= '0'; r_length_err <= '0'; timeout_err <= '0'; bvalid <= '0'; FIFO_reset <= '1'; elsif(aclk'event and aclk = '1')then case axi_state is when idle => rd_strobe <= '0'; bvalid <= '0'; addr_wrap <= '0'; axi_out.axi_bresp <= "00"; axi_out.axi_rresp <= "00"; word_cntr <= (others => '0'); length_cntr <= (others => '0'); timer <= (others => '0'); FIFO_reset <= '0'; if(axi_in.axi_arvalid = '1' )then ipb_write <= '0'; burst_flag <= axi_in.axi_arburst(0); axi_addr <= unsigned(axi_in.axi_araddr(11 downto 2)); axi_alen <= axi_in.axi_arlen; axi_id <= axi_in.axi_arid; if(axi_in.axi_arburst(1) = '0' and axi_in.axi_arsize = "010" and axi_in.axi_araddr(1 downto 0) = "00")then axi_state <= r_data; rd_strobe <= '1'; else raddr_err <= '1'; axi_state <= r_abort; end if; idle_flag <= '0'; elsif(axi_in.axi_awvalid = '1')then ipb_write <= '1'; burst_flag <= axi_in.axi_awburst(0); axi_addr <= unsigned(axi_in.axi_awaddr(11 downto 2)); axi_alen <= axi_in.axi_awlen; axi_id <= axi_in.axi_awid; if(axi_in.axi_awburst(1) = '0' and axi_in.axi_awsize = "010" and axi_in.axi_awaddr(1 downto 0) = "00")then -- check burst type and size axi_state <= w_data; else waddr_err <= '1'; axi_state <= w_abort; end if; idle_flag <= '0'; end if; when w_data => if(axi_in.axi_wstrb = x"f" and axi_in.axi_wvalid = '1')then length_cntr <= length_cntr + 1; if(burst_flag = '1')then if(addr_wrap = '1')then w_wrap_err <= '1'; end if; axi_addr <= axi_addr + 1; if(and_reduce(std_logic_vector(axi_addr)) = '1')then addr_wrap <= '1'; end if; end if; if(axi_in.axi_wlast = '1')then if(length_cntr /= unsigned(axi_alen))then w_length_err <= '1'; axi_out.axi_bresp <= "10"; end if; end if; end if; if(word_cntr = unsigned(axi_alen) and r_FIFO_empty = '0')then bvalid <= '1'; end if; if(bvalid = '1' and axi_in.axi_bready = '1')then axi_state <= idle; idle_flag <= '1'; bvalid <= '0'; end if; if(r_FIFO_do(bit_ipb_err_flag) = '1' and r_FIFO_empty = '0')then axi_state <= w_abort; w_ipb_err <= '1'; end if; if(axi_in.axi_wstrb /= x"f" and axi_in.axi_wvalid = '1')then axi_state <= w_abort; w_strb_err <= '1'; end if; if(r_FIFO_empty = '0')then word_cntr <= word_cntr + 1; timer <= (others => '0'); else timer <= timer + 1; end if; if(TO_INTEGER(timer) = TIMEOUT)then axi_state <= w_abort; end if; when r_data => if(length_cntr = unsigned(axi_alen))then rd_strobe <= '0'; end if; if(rd_strobe = '1')then length_cntr <= length_cntr + 1; if(addr_wrap = '1')then r_wrap_err <= '1'; end if; if(burst_flag = '1')then axi_addr <= axi_addr + 1; if(and_reduce(std_logic_vector(axi_addr)) = '1')then addr_wrap <= '1'; end if; end if; end if; if(r_FIFO_empty = '0' and axi_in.axi_rready = '1')then word_cntr <= word_cntr + 1; if(word_cntr = unsigned(axi_alen))then axi_state <= idle; idle_flag <= '1'; end if; timer <= (others => '0'); else timer <= timer + 1; end if; if(TO_INTEGER(timer) = TIMEOUT)then axi_state <= r_abort; timeout_err <= '1'; end if; when w_abort => bvalid <='1'; axi_out.axi_bresp <= "10"; timer <= (others => '0'); if(axi_in.axi_bready = '1' and bvalid = '1')then axi_state <= clearFIFO; FIFO_reset <= '1'; bvalid <= '0'; end if; when r_abort => rd_strobe <= '0'; axi_out.axi_rresp <= "10"; timer <= (others => '0'); if(axi_in.axi_rready = '1')then axi_state <= clearFIFO; FIFO_reset <= '1'; end if; when clearFIFO => timer <= timer + 1; if(TO_INTEGER(timer) = TIMEOUT)then FIFO_reset <= '0'; axi_state <= idle; idle_flag <= '1'; end if; when others => NULL; end case; end if; end process; axi_status(0) <= waddr_err; axi_status(1) <= raddr_err; axi_status(2) <= w_ipb_err; axi_status(3) <= w_strb_err; axi_status(4) <= w_wrap_err; axi_status(5) <= w_length_err; axi_status(6) <= r_wrap_err; axi_status(7) <= r_length_err; axi_status(8) <= timeout_err; axi_status(31 downto 9) <= (others => '0'); process(ipb_clk) begin if(ipb_clk'event and ipb_clk = '1')then ipb_toggle <= not ipb_toggle; end if; end process; process(aclk) begin if(aclk'event and aclk = '1')then ipb_toggle_q <= ipb_toggle; if(ipb_toggle_q /= ipb_toggle)then ipb_phase <= "001"; else ipb_phase <= ipb_phase(2 downto 1) & '0'; end if; if(FIFO_reset = '1')then ipb_cntr <= x"0"; elsif(w_FIFO_wren = '1' and r_FIFO_rden = '0')then ipb_cntr <= ipb_cntr + 1; elsif(w_FIFO_wren = '0' and r_FIFO_rden = '1')then ipb_cntr <= ipb_cntr - 1; end if; if(ipb_cntr(3 downto 1) = "111")then ipb_full <= '1'; else ipb_full <= '0'; end if; end if; end process; i_w_FIFO: srl_fiforeg generic map(N => 32) port map( rst => FIFO_reset, clk => aclk, write => w_FIFO_wren, read => w_FIFO_rden, din => axi_in.axi_wdata, dout => w_FIFO_do, empty => w_FIFO_empty ); w_FIFO_wren <= '1' when ipb_full = '0' and ((axi_in.axi_wstrb = x"f" and axi_in.axi_wvalid = '1') or rd_strobe = '1') and addr_wrap = '0' else '0'; i_r_FIFO: srl_fiforeg generic map(N => 33) port map( rst => FIFO_reset, clk => aclk, write => r_FIFO_wren, read => r_FIFO_rden, din => r_FIFO_din, dout => r_FIFO_do, empty => r_FIFO_empty ); r_FIFO_rden <= '1' when r_FIFO_empty = '0' and (axi_in.axi_rready = '1' or axi_state = w_data) else '0'; end Behavioral;