fpga: Add generic FIFO core

This commit is contained in:
Markus Koch 2024-07-26 10:55:32 +02:00
parent e81166a82c
commit db5a14a2f0

106
fpga/hdl/generics/fifo.vhd Normal file
View File

@ -0,0 +1,106 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
-- -------------------------------------------------------------------------- --
-- TODO
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- 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;