summaryrefslogtreecommitdiffstats
path: root/PIC/fifo.vhd
blob: 9dd852381d82c4f207b1d7a7b2322d527e5eb43f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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;