diff --git a/fpga/hdl/generics/fifo.vhd b/fpga/hdl/generics/fifo.vhd new file mode 100644 index 0000000..509ab30 --- /dev/null +++ b/fpga/hdl/generics/fifo.vhd @@ -0,0 +1,106 @@ +-- -------------------------------------------------------------------------- -- +-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs -- +-- -------------------------------------------------------------------------- -- +-- TODO +-- -------------------------------------------------------------------------- -- +-- Author : Markus Koch +-- Contributors : None +-- License : Mozilla Public License (MPL) Version 2 +-- -------------------------------------------------------------------------- -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; + +entity fifo is + generic( + SIZE : integer := 15 -- Entries in the FIFO (of size data), SIZE=(n^2)-1 recommended + ); + port( + -- generic ports + clk : in std_logic; -- System clock + rst_a : in std_logic; -- Asynchronous reset + clr : in std_logic; -- Remove all entries + + -- FIFO in + data_in : in std_logic_vector; -- Data input into FIFO + write : in std_logic; -- Data is latched when `data_in_valid and not full` + full : out std_logic; -- FIFO is full + + -- FIFO out + data_out : out std_logic_vector; -- Data output from FIFO + empty : out std_logic; -- FIFO is empty. '0' means "data is available". + read : in std_logic; -- Acknowledge that `data_out` was read. The word is removed and next one shifted from FIFO when `read and not empty`. + + -- FIFO meta + usage : out integer range 0 to SIZE -- Usage counter + ); +end fifo; + +architecture rtl of fifo is + constant MEMORY_WIDTH : integer := data_in'length; + subtype pointer_t is integer range 0 to SIZE - 1; + type memory_t is array (pointer_t) of std_logic_vector(MEMORY_WIDTH - 1 downto 0); + + signal memory : memory_t; + signal read_pointer : pointer_t; + signal write_pointer : pointer_t; + signal read_pointer_last : pointer_t; + +begin + fifo_p : process(rst_a, clk) is + variable succesful_read : std_logic; + variable succesful_write : std_logic; + variable write_pointer_next : pointer_t; + variable read_pointer_next : pointer_t; + begin + if rst_a then + read_pointer <= 0; + write_pointer <= 0; + read_pointer_last <= SIZE - 1; + usage <= 0; + + elsif rising_edge(clk) then + succesful_read := read and not empty; + succesful_write := write and (not full or succesful_read); + + write_pointer_next := write_pointer; + read_pointer_next := read_pointer; + + if succesful_read then + read_pointer_next := (read_pointer_next + 1) mod SIZE; + read_pointer_last <= read_pointer; + end if; + + if succesful_write then + memory(write_pointer) <= data_in; + write_pointer_next := (write_pointer_next + 1) mod SIZE; + end if; + + if succesful_write xor succesful_read then + if succesful_write then + usage <= usage + 1; + else + usage <= usage - 1; + end if; + end if; + + read_pointer <= read_pointer_next; + write_pointer <= write_pointer_next; + + if clr then + read_pointer <= 0; + write_pointer <= 0; + read_pointer_last <= SIZE - 1; + usage <= 0; + end if; + end if; + end process fifo_p; + + full <= '1' when read_pointer_last = write_pointer else '0'; + empty <= '1' when (read_pointer = write_pointer) else '0'; + + data_out <= memory(read_pointer); + +end rtl;