library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; library UNISIM; use UNISIM.VComponents.all; entity buff is Port ( wr_clk : in STD_LOGIC; wr_en : in STD_LOGIC; wr_data : in STD_LOGIC_VECTOR (63 downto 0); wr_done : in STD_LOGIC; wr_cancel : in std_logic := '0'; wr_accept : out STD_LOGIC; rd_clk : in STD_LOGIC; rd_en : in STD_LOGIC; rd_data : out STD_LOGIC_VECTOR (63 downto 0) := (others => '0'); rd_length : out STD_LOGIC_VECTOR (8 downto 0) := (others => '0'); rd_valid : out STD_LOGIC := '0'); end buff; architecture arch of buff is COMPONENT ram_4kB PORT ( clka : IN STD_LOGIC; wea : IN STD_LOGIC_VECTOR(0 DOWNTO 0); addra : IN STD_LOGIC_VECTOR(8 DOWNTO 0); dina : IN STD_LOGIC_VECTOR(63 DOWNTO 0); clkb : IN STD_LOGIC; addrb : IN STD_LOGIC_VECTOR(8 DOWNTO 0); doutb : OUT STD_LOGIC_VECTOR(63 DOWNTO 0) ); END COMPONENT; signal ram_wr_en : std_logic_vector(0 downto 0); signal ram_wr_addr : std_logic_vector(8 downto 0); signal ram_wr_data : std_logic_vector(63 downto 0); signal ram_rd_addr : std_logic_vector(8 downto 0); signal ram_rd_data : std_logic_vector(63 downto 0); constant W1 : std_logic_vector(1 downto 0) := "00"; constant W2 : std_logic_vector(1 downto 0) := "11"; constant R1 : std_logic_vector(1 downto 0) := "01"; constant R2 : std_logic_vector(1 downto 0) := "10"; signal wr_owner : std_logic_vector(1 downto 0) := W1; signal rd_owner : std_logic_vector(1 downto 0) := W1; signal wr_owner_tmp : std_logic_vector(1 downto 0) := W1; signal wr_owner_sync : std_logic_vector(1 downto 0) := W1; -- MAX: 256 bytes less than 4kB, for ouroboros -- 4kB = 512 x 64 bits -- 256 bytes = 32 x 64 bits -- 512 - 32 = 480 -- 480 = "111100000" constant MAX : std_logic_vector(8 downto 0) := "111100000"; constant ZERO : std_logic_vector(8 downto 0) := "000000000"; constant ONE : std_logic_vector(8 downto 0) := "000000001"; type state_t is (state_empty, state_wait, state_full, state_first, state_valid); signal rd_state : state_t := state_empty; signal rd_addr : std_logic_vector(8 downto 0) := MAX; begin ram : ram_4kB PORT MAP ( clka => wr_clk, wea => ram_wr_en, addra => ram_wr_addr, dina => ram_wr_data, clkb => rd_clk, addrb => ram_rd_addr, doutb => ram_rd_data ); wr_accept <= '1' when (wr_owner = W1 or wr_owner = W2) and wr_done = '0' and wr_cancel = '0' else '0'; process (wr_clk) variable wr_count : std_logic_vector(8 downto 0) := ZERO; begin if rising_edge(wr_clk) then ram_wr_en(0) <= '0'; ram_wr_addr <= (others => '0'); ram_wr_data <= (others => '0'); if wr_owner = W1 or wr_owner = W2 then if wr_cancel = '1' then wr_count := ZERO; elsif wr_done = '1' then if wr_count /= ZERO then if wr_owner = W1 then wr_owner <= R1; ram_wr_data(1 downto 0) <= R1; else wr_owner <= R2; ram_wr_data(1 downto 0) <= R2; end if; ram_wr_en(0) <= '1'; ram_wr_addr <= MAX; ram_wr_data(10 downto 2) <= wr_count; wr_count := ZERO; end if; elsif wr_en = '1' then if wr_count /= MAX then ram_wr_en(0) <= '1'; ram_wr_addr <= wr_count; ram_wr_data <= wr_data; wr_count := std_logic_vector(unsigned(wr_count) + 1); end if; end if; elsif wr_owner = R1 then if wr_owner_sync = W2 then wr_owner <= W2; end if; elsif wr_owner = R2 then if wr_owner_sync = W1 then wr_owner <= W1; end if; end if; wr_owner_tmp <= rd_owner; wr_owner_sync <= wr_owner_tmp; end if; end process; ram_rd_addr <= std_logic_vector(unsigned(rd_addr) + 1) when rd_state = state_valid and rd_en = '1' else rd_addr; process (rd_clk) variable rd_count : std_logic_vector(8 downto 0) := ZERO; variable tmp : std_logic_vector(1 downto 0); begin if rising_edge(rd_clk) then if rd_state = state_empty then rd_state <= state_wait; elsif rd_state = state_wait then tmp := ram_rd_data(1 downto 0); if (rd_owner = W1 and tmp = R1) or (rd_owner = W2 and tmp = R2) then rd_state <= state_full; rd_addr <= ZERO; rd_count := ram_rd_data(10 downto 2); rd_owner <= tmp; end if; elsif rd_state = state_full then rd_state <= state_first; rd_addr <= ONE; elsif rd_state = state_first then rd_state <= state_valid; rd_valid <= '1'; rd_data <= ram_rd_data; rd_length <= rd_count; elsif rd_state = state_valid then if rd_en = '1' then if rd_addr = rd_count then rd_state <= state_empty; rd_addr <= MAX; rd_valid <= '0'; rd_data <= (others => '0'); rd_length <= ZERO; rd_count := ZERO; if rd_owner = R1 then rd_owner <= W2; else rd_owner <= W1; end if; else rd_addr <= ram_rd_addr; rd_data <= ram_rd_data; end if; end if; end if; end if; end process; end arch;