summaryrefslogtreecommitdiffstats
path: root/hdl/fifo.vhd
diff options
context:
space:
mode:
authorVaino Kauppila <vaino@vke.fi>2026-04-19 12:32:58 +0300
committerVaino Kauppila <vaino@vke.fi>2026-04-19 12:32:58 +0300
commiteb8643ddbef43547eb7bfe58789a3908926c7258 (patch)
treefadfba88a1c71b266b8c67df166a3a6ead6b30d1 /hdl/fifo.vhd
parent129a1c975dbd0c042576010b1f6eb40d19fc5733 (diff)
downloadvhdl_pic-eb8643ddbef43547eb7bfe58789a3908926c7258.tar.gz
vhdl_pic-eb8643ddbef43547eb7bfe58789a3908926c7258.zip
refactor dir structure, add fib.c
Diffstat (limited to 'hdl/fifo.vhd')
-rw-r--r--hdl/fifo.vhd75
1 files changed, 75 insertions, 0 deletions
diff --git a/hdl/fifo.vhd b/hdl/fifo.vhd
new file mode 100644
index 0000000..9dd8523
--- /dev/null
+++ b/hdl/fifo.vhd
@@ -0,0 +1,75 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+-- First-word fall-through (FWFT) FIFO.
+-- dout always presents the current head combinatorially (no read latency).
+-- rd_en advances the read pointer; the next head is visible on the same cycle.
+-- DEPTH must be a power of 2; ADDR_BITS = log2(DEPTH).
+
+entity fifo is
+ generic (
+ DEPTH : positive := 16;
+ ADDR_BITS : positive := 4;
+ WIDTH : positive := 8
+ );
+ port (
+ clk : in std_logic;
+ wr_en : in std_logic;
+ rd_en : in std_logic;
+ din : in std_logic_vector(WIDTH - 1 downto 0);
+ dout : out std_logic_vector(WIDTH - 1 downto 0);
+ full : out std_logic;
+ empty : out std_logic
+ );
+end entity fifo;
+
+architecture rtl of fifo is
+
+ -- MSB pointer trick: pointers are ADDR_BITS+1 wide.
+ -- Empty: read_ptr = write_ptr
+ -- Full: (read_ptr XOR write_ptr) = DEPTH (MSBs differ, lower bits equal)
+ signal read_ptr : unsigned(ADDR_BITS downto 0) := (others => '0');
+ signal write_ptr : unsigned(ADDR_BITS downto 0) := (others => '0');
+
+ type mem_t is
+ array (0 to DEPTH - 1)
+ of std_logic_vector(WIDTH - 1 downto 0);
+
+ signal mem : mem_t := (others => (others => '0'));
+
+ signal empty_i : std_logic;
+ signal full_i : std_logic;
+
+begin
+
+ empty_i <= '1' when read_ptr = write_ptr else '0';
+ full_i <= '1' when (read_ptr xor write_ptr) = to_unsigned(DEPTH, ADDR_BITS + 1)
+ else '0';
+
+ empty <= empty_i;
+ full <= full_i;
+
+ -- FWFT: head is always visible without asserting rd_en
+ dout <= mem(to_integer(read_ptr(ADDR_BITS - 1 downto 0)));
+
+ enqueue : process(clk)
+ begin
+ if rising_edge(clk) then
+ if wr_en = '1' and full_i = '0' then
+ mem(to_integer(write_ptr(ADDR_BITS - 1 downto 0))) <= din;
+ write_ptr <= write_ptr + 1;
+ end if;
+ end if;
+ end process enqueue;
+
+ dequeue : process(clk)
+ begin
+ if rising_edge(clk) then
+ if rd_en = '1' and empty_i = '0' then
+ read_ptr <= read_ptr + 1;
+ end if;
+ end if;
+ end process dequeue;
+
+end architecture rtl;