Bài học Thiết kế bộ nhớ đệm FIFO dùng VHDL

Lu ROm

Administrator
Staff member
25 Tháng bảy 2014
481
119
43
32
One piece
vimach.net
1, Giới thiệu
-- FIFO (First-In-First-Out) là một khối nhớ đệm đặc biệt, rất hay ứng dụng trong các hệ thống truyền dẫn số, dùng làm các khối đệm trong các thiết bị lưu trữ… Như tên gọi của nó thì dữ liệu nào ghi vào trước thì được đọc ra trước. Đối với FIFO không còn khái niệm địa chỉ mà chỉ còn các cổng điểu khiển đọc và ghi dữ liệu. Khi được cho phép ghi, dữ liệu bên ngoài sẽ ghi vào bộ nhớ đệm.Khi có tín hiệu cho phép đọc, dữ liệu sẽ được đọc từ bộ nhớ đệm ra ngoài theo thứ tự đã ghi. Tùy theo yêu cầu cụ thể mà FIFO có thể được thiết kế bằng các cách khác nhau. Sơ đồ đơn giản và tổng quát nhất của FIFO là sơ đồ sử dụng khối RAM đồng bộ hai cổng đọc ghi độc lập.
FIFO Buffer.png

-- Như vậy, khi dữ liệu được đọc nó được xem như bị loại bỏ khỏi bộ đệm lưu trữ, và như thế ta có thể ghi nhiều dữ liệu hơn.
2,Thiết kế FIFO.
--Các đầu vào và ra của một FIFO hoàn chỉnh:
FbkQZarLqk1KTfodPALSjwDtevuM8NAnkJlyutvq6t4=w683-h471-no

-- Để thiết kế được FIFO chúng ta hãy tưởng tượng các thành phần bộ nhớ nằm trong vòng tròn với hai con trỏ write (ghi) và read (đọc). Đầu tiên ta có 2 con trỏ ghi và đọc ở đầu vòng tròn.Ta tăng lần lượt con trỏ đọc lên để ghi dữ liệu vào bộ đệm. Sau khi đã ghi được một ô nhỏ trong vòng tròn ta bắt đầu tang con trỏ đọc lên để đọc dữ liệu ra. Cứ như thế cho hết vòng tròn ta được dữ liệu ra y như giá trị dữ liệu ban đầu.
FIFO%2BVerilog.png

++ Bộ đệm này cũng gồm 2 flags ( cờ ): empty ( rỗng ) và full ( đầy).
- Flags full là trạng thái khi con trỏ ghi đã thực hiện ghi dữ liệu được một vòng tròn và gặp con trỏ đọc tại vòng tròn thứ 2. Nói cách khác, con trỏ đọc trùng với con trỏ ghi khi vòng quay con trỏ ghi lớn hơn con trỏ đọc 1 vòng. Dữ liệu chưa được đọc ra mà đã có tín hiệu ghi vào ô nhớ đó.Khi đó ta sẽ không được phép ghi dữ liệu vào nữa.
- Flags empty: là trạng thái con trỏ đọc trùng với con trỏ ghi khi cả 2 con trỏ cùng một vòng. Dữ liệu chưa được ghi vào đã có tín hiệu đọc ra => xem như dữ liệu cũng bị mất.
3,CODE
Mã:
_FIFO.vhdADA

library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

entity STD_FIFO is
    Generic (
        constant DATA_WIDTH  : positive := 8;
        constant FIFO_DEPTH    : positive := 256
    );
    Port (
        CLK        : in  STD_LOGIC;
        RST        : in  STD_LOGIC;
        WriteEn    : in  STD_LOGIC;
        DataIn    : in  STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        ReadEn    : in  STD_LOGIC;
        DataOut    : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        Empty    : out STD_LOGIC;
        Full    : out STD_LOGIC
    );
end STD_FIFO;

architecture Behavioral of STD_FIFO is

begin

    -- Memory Pointer Process
    fifo_proc : process (CLK)
        type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        variable Memory : FIFO_Memory;
       
        variable Head : natural range 0 to FIFO_DEPTH - 1;
        variable Tail : natural range 0 to FIFO_DEPTH - 1;
       
        variable Looped : boolean;
    begin
        if rising_edge(CLK) then
            if RST = '1' then
                Head := 0;
                Tail := 0;
               
                Looped := false;
               
                Full  <= '0';
                Empty <= '1';
            else
                if (ReadEn = '1') then
                    if ((Looped = true) or (Head /= Tail)) then
                        -- Update data output
                        DataOut <= Memory(Tail);
                       
                        -- Update Tail pointer as needed
                        if (Tail = FIFO_DEPTH - 1) then
                            Tail := 0;
                           
                            Looped := false;
                        else
                            Tail := Tail + 1;
                        end if;
                       
                       
                    end if;
                end if;
               
                if (WriteEn = '1') then
                    if ((Looped = false) or (Head /= Tail)) then
                        -- Write Data to Memory
                        Memory(Head) := DataIn;
                       
                        -- Increment Head pointer as needed
                        if (Head = FIFO_DEPTH - 1) then
                            Head := 0;
                           
                            Looped := true;
                        else
                            Head := Head + 1;
                        end if;
                    end if;
                end if;
               
                -- Update Empty and Full flags
                if (Head = Tail) then
                    if Looped then
                        Full <= '1';
                    else
                        Empty <= '1';
                    end if;
                else
                    Empty    <= '0';
                    Full    <= '0';
                end if;
            end if;
        end if;
    end process;
       
end Behavioral;

library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
entity STD_FIFO is
    Generic (
        constant DATA_WIDTH  : positive := 8;
        constant FIFO_DEPTH    : positive := 256
    );
    Port (
        CLK        : in  STD_LOGIC;
        RST        : in  STD_LOGIC;
        WriteEn    : in  STD_LOGIC;
        DataIn    : in  STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        ReadEn    : in  STD_LOGIC;
        DataOut    : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        Empty    : out STD_LOGIC;
        Full    : out STD_LOGIC
    );
end STD_FIFO;
architecture Behavioral of STD_FIFO is
begin
    -- Memory Pointer Process
    fifo_proc : process (CLK)
        type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
        variable Memory : FIFO_Memory;
       
        variable Head : natural range 0 to FIFO_DEPTH - 1;
        variable Tail : natural range 0 to FIFO_DEPTH - 1;
       
        variable Looped : boolean;
    begin
        if rising_edge(CLK) then
            if RST = '1' then
                Head := 0;
                Tail := 0;
               
                Looped := false;
               
                Full  <= '0';
                Empty <= '1';
            else
                if (ReadEn = '1') then
                    if ((Looped = true) or (Head /= Tail)) then
                        -- Update data output
                        DataOut <= Memory(Tail);
                       
                        -- Update Tail pointer as needed
                        if (Tail = FIFO_DEPTH - 1) then
                            Tail := 0;
                           
                            Looped := false;
                        else
                            Tail := Tail + 1;
                        end if;
                       
                       
                    end if;
                end if;
               
                if (WriteEn = '1') then
                    if ((Looped = false) or (Head /= Tail)) then
                        -- Write Data to Memory
                        Memory(Head) := DataIn;
                       
                        -- Increment Head pointer as needed
                        if (Head = FIFO_DEPTH - 1) then
                            Head := 0;
                           
                            Looped := true;
                        else
                            Head := Head + 1;
                        end if;
                    end if;
                end if;
               
                -- Update Empty and Full flags
                if (Head = Tail) then
                    if Looped then
                        Full <= '1';
                    else
                        Empty <= '1';
                    end if;
                else
                    Empty    <= '0';
                    Full    <= '0';
                end if;
            end if;
        end if;
    end process;
       
end Behavioral;

Testbench
Mã:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

ENTITY TB_STD_FIFO IS
END TB_STD_FIFO;

ARCHITECTURE behavior OF TB_STD_FIFO IS
   
    -- Component Declaration for the Unit Under Test (UUT)
    component STD_FIFO
        Generic (
            constant DATA_WIDTH  : positive := 8;
            constant FIFO_DEPTH    : positive := 16
        );
        port (
            CLK        : in std_logic;
            RST        : in std_logic;
            DataIn    : in std_logic_vector(7 downto 0);
            WriteEn    : in std_logic;
            ReadEn    : in std_logic;
            DataOut    : out std_logic_vector(7 downto 0);
            Full    : out std_logic;
            Empty    : out std_logic
        );
    end component;
   
    --Inputs
    signal CLK        : std_logic := '0';
    signal RST        : std_logic := '0';
    signal DataIn    : std_logic_vector(7 downto 0) := (others => '0');
    signal ReadEn    : std_logic := '0';
    signal WriteEn    : std_logic := '0';
   
    --Outputs
    signal DataOut    : std_logic_vector(7 downto 0);
    signal Empty    : std_logic;
    signal Full        : std_logic;
   
    -- Clock period definitions
    constant CLK_period : time := 10 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
    uut: STD_FIFO
        PORT MAP (
            CLK        => CLK,
            RST        => RST,
            DataIn    => DataIn,
            WriteEn    => WriteEn,
            ReadEn    => ReadEn,
            DataOut    => DataOut,
            Full    => Full,
            Empty    => Empty
        );
   
    -- Clock process definitions
    CLK_process :process
    begin
        CLK <= '0';
        wait for CLK_period/2;
        CLK <= '1';
        wait for CLK_period/2;
    end process;
   
    -- Reset process
    rst_proc : process
    begin
    wait for CLK_period * 5;
       
        RST <= '1';
       
        wait for CLK_period * 5;
       
        RST <= '0';
       
        wait;
    end process;
   
    -- Write process
    wr_proc : process
        variable counter : unsigned (7 downto 0) := (others => '0');
    begin       
        wait for CLK_period * 20;

        for i in 1 to 32 loop
            counter := counter + 1;
           
            DataIn <= std_logic_vector(counter);
           
            wait for CLK_period * 1;
           
            WriteEn <= '1';
           
            wait for CLK_period * 1;
       
            WriteEn <= '0';
        end loop;
       
        wait for clk_period * 20;
       
        for i in 1 to 32 loop
            counter := counter + 1;
           
            DataIn <= std_logic_vector(counter);
           
            wait for CLK_period * 1;
           
            WriteEn <= '1';
           
            wait for CLK_period * 1;
           
            WriteEn <= '0';
        end loop;
       
        wait;
    end process;
   
    -- Read process
    rd_proc : process
    begin
        wait for CLK_period * 20;
       
        wait for CLK_period * 40;
           
        ReadEn <= '1';
       
        wait for CLK_period * 60;
       
        ReadEn <= '0';
       
        wait for CLK_period * 256 * 2;
       
        ReadEn <= '1';
       
        wait;
    end process;

END;
 
  • Like
Reactions: co_coc_can