---------------------------------------------------------------------------- -- axihp_writer.vhd -- FIFO based AXIHP Writer -- Version 1.1 -- -- Copyright (C) 2013 H.Poetzl -- -- This program is free software: you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation, either version -- 2 of the License, or (at your option) any later version. -- ---------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.ALL; library unimacro; use unimacro.VCOMPONENTS.all; entity axihp_writer is generic ( DATA_WIDTH : natural := 64; DATA_COUNT : natural := 16; AWID_MASK : unsigned(5 downto 0) := "111111"; AWID_DATA : unsigned(5 downto 0) := "000000"; IN_FLIGHT_LIMIT : natural := 12 ); port ( s_axi_aclk : in std_ulogic; s_axi_areset_n : in std_ulogic; enable : in std_ulogic; -- write address s_axi_awid : out std_logic_vector(5 downto 0); s_axi_awaddr : out std_logic_vector(31 downto 0); s_axi_awburst : out std_logic_vector(1 downto 0); s_axi_awlen : out std_logic_vector(3 downto 0); s_axi_awsize : out std_logic_vector(1 downto 0); s_axi_awcache : out std_logic_vector(3 downto 0); s_axi_awvalid : out std_ulogic; s_axi_awready : in std_ulogic; s_axi_wacount : in std_logic_vector(5 downto 0); -- write data s_axi_wid : out std_logic_vector(5 downto 0); s_axi_wdata : out std_logic_vector(63 downto 0); s_axi_wstrb : out std_logic_vector(7 downto 0); s_axi_wlast : out std_ulogic; s_axi_wvalid : out std_ulogic; s_axi_wready : in std_ulogic; s_axi_wcount : in std_logic_vector(7 downto 0); -- write response s_axi_bid : in std_logic_vector(5 downto 0); s_axi_bresp : in std_logic_vector(1 downto 0); s_axi_bvalid : in std_ulogic; s_axi_bready : out std_ulogic; -- data_clk : in std_ulogic; data_enable : in std_ulogic; data_in : in std_logic_vector(DATA_WIDTH - 1 downto 0); data_full : out std_ulogic; -- addr_clk : in std_ulogic; addr_enable : in std_ulogic; addr_in : in std_logic_vector(31 downto 0); addr_full : out std_ulogic; -- writer_state : out std_logic_vector(7 downto 0) ); end entity axihp_writer; architecture RTL of axihp_writer is function cwidth_f( data_width : in natural; fifo_size : in string ) return natural is variable ret_v : natural; begin if(fifo_size = "18Kb") then case data_width is when 0|1|2|3|4 => ret_v := 12; when 5|6|7|8|9 => ret_v := 11; when 10 to 18 => ret_v := 10; when 19 to 36 => ret_v := 9; when others => ret_v := 12; end case; elsif(fifo_size = "36Kb") then case data_width is when 0|1|2|3|4 => ret_v := 13; when 5|6|7|8|9 => ret_v := 12; when 10 to 18 => ret_v := 11; when 19 to 36 => ret_v := 10; when 37 to 72 => ret_v := 9; when others => ret_v := 13; end case; end if; return ret_v; end function; constant DATA_CWIDTH : natural := cwidth_f(DATA_WIDTH, "36Kb"); constant ADDR_CWIDTH : natural := cwidth_f(32, "18Kb"); -------------------------------------------------------------------- -- FIFO Signals -------------------------------------------------------------------- signal fifo_data_out : std_logic_vector(DATA_WIDTH - 1 downto 0); signal fifo_data_enable : std_ulogic; signal fifo_data_almostempty : std_ulogic; signal fifo_data_empty : std_ulogic; signal fifo_data_rderr : std_ulogic; -- signal fifo_data_rdcount : signal fifo_data_reset : std_ulogic; signal fifo_data_rdcount : std_logic_vector(DATA_CWIDTH - 1 downto 0); signal fifo_data_wrcount : std_logic_vector(DATA_CWIDTH - 1 downto 0); signal fifo_addr_out : std_logic_vector(31 downto 0); signal fifo_addr_enable : std_ulogic; -- signal fifo_addr_almostempty : std_ulogic; signal fifo_addr_empty : std_ulogic; signal fifo_addr_rderr : std_ulogic; -- signal fifo_addr_rdcount : signal fifo_addr_reset : std_ulogic; signal fifo_addr_rdcount : std_logic_vector(ADDR_CWIDTH - 1 downto 0); signal fifo_addr_wrcount : std_logic_vector(ADDR_CWIDTH - 1 downto 0); -------------------------------------------------------------------- -- InFlight Signals -------------------------------------------------------------------- signal in_flight_inc : std_ulogic; signal in_flight_dec : std_ulogic; signal in_flight_max : std_ulogic; begin FIFO_data_inst : FIFO_DUALCLOCK_MACRO generic map ( DEVICE => "7SERIES", -- ALMOST_FULL_OFFSET => X"0080", ALMOST_EMPTY_OFFSET => to_bitvector( std_logic_vector(to_unsigned(DATA_COUNT, 16))), DATA_WIDTH => DATA_WIDTH, FIFO_SIZE => "36Kb", FIRST_WORD_FALL_THROUGH => TRUE ) port map ( DI => data_in, WRCLK => data_clk, WREN => data_enable, -- ALMOSTFULL => fifo_data_almostfull, FULL => data_full, -- WRERR => fifo_data_wrerr, WRCOUNT => fifo_data_wrcount, -- DO => fifo_data_out, RDCLK => s_axi_aclk, RDEN => fifo_data_enable, ALMOSTEMPTY => fifo_data_almostempty, EMPTY => fifo_data_empty, RDERR => fifo_data_rderr, RDCOUNT => fifo_data_rdcount, -- RST => fifo_data_reset ); fifo_data_reset <= not s_axi_areset_n; FIFO_addr_inst : FIFO_DUALCLOCK_MACRO generic map ( DEVICE => "7SERIES", -- ALMOST_FULL_OFFSET => X"0080", -- ALMOST_EMPTY_OFFSET => x"0001", DATA_WIDTH => 32, FIFO_SIZE => "18Kb", FIRST_WORD_FALL_THROUGH => TRUE ) port map ( DI => addr_in, WRCLK => addr_clk, WREN => addr_enable, -- ALMOSTFULL => fifo_addr_almostfull, FULL => addr_full, -- WRERR => fifo_addr_wrerr, WRCOUNT => fifo_addr_wrcount, -- DO => fifo_addr_out, RDCLK => s_axi_aclk, RDEN => fifo_addr_enable, -- ALMOSTEMPTY => fifo_addr_almostempty, EMPTY => fifo_addr_empty, RDERR => fifo_addr_rderr, RDCOUNT => fifo_addr_rdcount, -- RST => fifo_addr_reset ); fifo_addr_reset <= not s_axi_areset_n; write_proc : process(s_axi_aclk) constant dcnt_c : natural := DATA_COUNT - 1; variable dcnt_v : natural range DATA_COUNT - 1 downto 0; variable awid_v : unsigned(5 downto 0) := (others => '0'); variable awvalid_v : std_logic := '0'; variable wvalid_v : std_logic := '0'; variable wlast_v : std_logic := '0'; type w_state is (addr_s, data_s, incr_s, hold_s, idle_s); variable state : w_state := idle_s; begin if rising_edge(s_axi_aclk) then if s_axi_areset_n = '0' then awvalid_v := '0'; wvalid_v := '0'; wlast_v := '0'; awid_v := (others => '0'); writer_state <= (others => '0'); state := idle_s; else in_flight_inc <= '0'; fifo_addr_enable <= '0'; fifo_data_enable <= '0'; -- AWVALID ---> WVALID _ BREADY Master -- \ --__ /` \ --__ /` -- \, /--__ \, --_ / -- AWREADY -> WREADY ---> BVALID Slave case state is when addr_s => wvalid_v := '0'; wlast_v := '0'; if enable = '0' then -- disable writer state := hold_s; elsif fifo_addr_empty = '1' then -- fifo empty state := idle_s; elsif fifo_data_almostempty = '1' then -- not enough data state := idle_s; else -- go ahead awvalid_v := '1'; dcnt_v := dcnt_c; if s_axi_awready = '1' then -- slave ready in_flight_inc <= '1'; state := data_s; end if; end if; when data_s => awvalid_v := '0'; wvalid_v := '1'; if s_axi_wready = '1' then -- write ready if dcnt_v = 0 then -- last write wlast_v := '1'; state := incr_s; else dcnt_v := dcnt_v - 1; end if; fifo_data_enable <= '1'; -- fetch data else fifo_data_enable <= '0'; -- no data end if; when incr_s => wvalid_v := '0'; wlast_v := '0'; if in_flight_max = '0' then awid_v := awid_v + "1"; -- next id fifo_addr_enable <= '1'; -- fetch addr state := addr_s; end if; when hold_s => wvalid_v := '0'; wlast_v := '0'; if enable = '1' then state := addr_s; end if; when idle_s => wvalid_v := '0'; wlast_v := '0'; if fifo_data_almostempty = '0' then state := addr_s; end if; end case; end if; case state is when addr_s => writer_state(3 downto 0) <= "0001"; when data_s => writer_state(3 downto 0) <= "0010"; when incr_s => writer_state(3 downto 0) <= "0011"; when hold_s => writer_state(3 downto 0) <= "0111"; when idle_s => writer_state(3 downto 0) <= "1000"; end case; writer_state(7 downto 4) <= std_logic_vector(to_unsigned(dcnt_v, 4)); end if; s_axi_awid <= std_logic_vector( (awid_v and AWID_MASK) or AWID_DATA); s_axi_wid <= std_logic_vector( (awid_v and AWID_MASK) or AWID_DATA); s_axi_awvalid <= awvalid_v; s_axi_wvalid <= wvalid_v; s_axi_wlast <= wlast_v; end process; s_axi_wdata <= fifo_data_out; s_axi_awaddr <= fifo_addr_out; bresp_proc : process(s_axi_aclk) variable bready_v : std_logic := '0'; begin in_flight_dec <= '0'; if rising_edge(s_axi_aclk) then if s_axi_areset_n = '0' then bready_v := '0'; else bready_v := '1'; if s_axi_bvalid = '1' then in_flight_dec <= '1'; end if; end if; end if; s_axi_bready <= bready_v; end process; in_flight_proc : process(s_axi_aclk) variable cnt_v : natural range 0 to 63 := 0; variable trig_v : std_logic_vector(1 downto 0); begin if rising_edge(s_axi_aclk) then trig_v := in_flight_inc & in_flight_dec; case trig_v is when "10" => cnt_v := cnt_v + 1; when "01" => cnt_v := cnt_v - 1; when others => null; end case; end if; if cnt_v = IN_FLIGHT_LIMIT then in_flight_max <= '1'; else in_flight_max <= '0'; end if; end process; s_axi_awlen <= std_logic_vector(to_unsigned(DATA_COUNT - 1, 4)); s_axi_awburst <= "01"; s_axi_awsize <= "11"; s_axi_wstrb <= x"FF"; s_axi_awcache <= "1011"; end RTL;