126 lines
4.1 KiB
VHDL
126 lines
4.1 KiB
VHDL
|
-- -------------------------------------------------------------------------- --
|
||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||
|
-- -------------------------------------------------------------------------- --
|
||
|
-- TODO
|
||
|
-- -------------------------------------------------------------------------- --
|
||
|
-- Author : Markus Koch <markus@notsyncing.net>
|
||
|
-- Contributors : None
|
||
|
-- License : Mozilla Public License (MPL) Version 2
|
||
|
-- -------------------------------------------------------------------------- --
|
||
|
|
||
|
-- Tech hint: Width of FIFO will be width of `data_in` + 1.
|
||
|
|
||
|
library ieee;
|
||
|
use ieee.std_logic_1164.all;
|
||
|
use ieee.numeric_std.all;
|
||
|
use ieee.math_real.all;
|
||
|
|
||
|
entity fifo_block 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`
|
||
|
commit : in std_logic; -- Finalize block
|
||
|
abort : in std_logic; -- Abort current block
|
||
|
full : out std_logic; -- FIFO is full
|
||
|
|
||
|
-- FIFO out
|
||
|
data_out : out std_logic_vector; -- Data output from FIFO
|
||
|
data_first : out std_logic; -- Currently visible word is first in packet
|
||
|
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 -- Usage counter
|
||
|
);
|
||
|
end fifo_block;
|
||
|
|
||
|
architecture rtl of fifo_block is
|
||
|
constant MEMORY_WIDTH : integer := data_in'length + 1;
|
||
|
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;
|
||
|
signal write_pointer_committed : pointer_t;
|
||
|
signal current_is_first : std_logic;
|
||
|
|
||
|
begin
|
||
|
fifo : 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;
|
||
|
write_pointer_committed <= 0;
|
||
|
current_is_first <= '1';
|
||
|
|
||
|
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) <= current_is_first & data_in;
|
||
|
write_pointer_next := (write_pointer_next + 1) mod SIZE;
|
||
|
current_is_first <= '0';
|
||
|
end if;
|
||
|
|
||
|
if succesful_write xor succesful_read then
|
||
|
if succesful_write then
|
||
|
usage <= usage + 1;
|
||
|
else
|
||
|
usage <= usage - 1;
|
||
|
end if;
|
||
|
end if;
|
||
|
|
||
|
if commit then
|
||
|
write_pointer_committed <= write_pointer;
|
||
|
current_is_first <= '1';
|
||
|
elsif abort then
|
||
|
write_pointer_next := write_pointer_committed;
|
||
|
current_is_first <= '1';
|
||
|
end if;
|
||
|
|
||
|
read_pointer <= read_pointer_next;
|
||
|
write_pointer <= write_pointer_next;
|
||
|
|
||
|
if clr then
|
||
|
read_pointer <= 0;
|
||
|
write_pointer <= 0;
|
||
|
write_pointer_committed <= 0;
|
||
|
current_is_first <= '1';
|
||
|
usage <= 0;
|
||
|
end if;
|
||
|
end if;
|
||
|
end process fifo;
|
||
|
|
||
|
full <= '1' when read_pointer_last = write_pointer else '0';
|
||
|
empty <= '1' when (read_pointer = write_pointer_committed) else '0';
|
||
|
|
||
|
data_out <= memory(read_pointer)(data_out'range);
|
||
|
data_first <= memory(read_pointer)(MEMORY_WIDTH - 1);
|
||
|
|
||
|
end rtl;
|