diff options
Diffstat (limited to 'netfpga10g/hdl/buff.vhd')
-rw-r--r-- | netfpga10g/hdl/buff.vhd | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/netfpga10g/hdl/buff.vhd b/netfpga10g/hdl/buff.vhd new file mode 100644 index 0000000..39b3a80 --- /dev/null +++ b/netfpga10g/hdl/buff.vhd @@ -0,0 +1,192 @@ + +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; + |