Thông báo

Collapse
No announcement yet.

[HELP] Asynchronous FIFO

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • [HELP] Asynchronous FIFO

    Em chào các bác,
    Em là mem mới, đang tập tọe tìm hiểu về Vi điện tử nên trong bài này có chỗ nào "hỏi ngu" mong các bác bỏ qua và tận tình giúp đỡ em với nhé .

    Em đang tìm hiểu về loại bộ nhớ FIFO không đồng bộ này. Theo em hiểu thì nó hoạt động với 2 xung đồng hồ khác nhau phục vụ cho việc đọc và ghi dữ liệu vào FIFO riêng rẽ.

    Em cũng thử code bằng VHDL theo Guide Asynchronous FIFO 6.1 của Xilinx nhưng còn một số chỗ chưa được hiểu rõ lắm nên muốn hỏi các bác ạ.
    Code của em đây:

    Code:
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_arith.all;
    use ieee.std_logic_unsigned.all;
    
    entity FIFO is
    	generic(
    		DEPTH : natural := 128;
    		WIDTH : natural := 4
    	);
    	port(
    		Reset       : in std_logic;				-- reset to default FIFO
    		wclk        : in std_logic; 				-- write clock
    		rclk        : in std_logic;                          	-- read clock 
    		
    		DataIn      : in std_logic_vector(WIDTH -1 downto 0);   -- Data input
    		WriteEnable : in std_logic;                          	-- write enable flag
    
    		DataOut     : out std_logic_vector(WIDTH -1 downto 0);  -- Data output
    		ReadEnable  : in std_logic;                          	-- read enable flag
    		
    		empty       : out std_logic;                            -- FIFO is empty
    		full        : out std_logic                          	-- FIFO is full
    	);
    end entity FIFO;
    
    architecture structural of FIFO is
    	function bitcount(n : in natural) return natural is
    		variable tmp : unsigned(4 downto 1);
    		variable cnt : natural;
    	begin
    		tmp := conv_unsigned(n, 4);
    		cnt := 4;
    		for dummy in 4 downto 1 loop
    			if (tmp(cnt) = '0') then
    				cnt := cnt -1;
    			end if;
    		end loop;
    
    		return cnt;
    	end function bitcount;
    
    	constant ADEPTH : natural := bitcount(DEPTH -1); -- 256 entries: range 255 downto 0
    
    	type Memory is array (DEPTH -1 downto 0) of std_logic_vector(WIDTH -1 downto 0);
    	signal Mem : Memory;
    
    	signal rpt, wpt : unsigned(ADEPTH -1 downto 0);
    	signal wr_cnt,rd_cnt : unsigned(ADEPTH downto 0);
    begin
    	
    	-- write pointer
    	U1_write_point: process(wclk, Reset)
    	begin
    		if (Reset = '0') then
    			wpt <= (others => '0');
    		elsif (wclk'event and wclk = '1') then
    			if (WriteEnable = '1') then
    				wpt <= wpt +1;
    			end if;
    		end if;
    	end process U1_write_point;
    
    	-- read pointer
    	U2_read_point: process(rclk, Reset)
    	begin
    		if (Reset = '0') then
    			rpt <= (others => '0');
    		elsif (rclk'event and rclk = '1') then
    			if (ReadEnable = '1') then
    				rpt <= rpt +1;
    			end if;
    		end if;
    	end process U2_read_point;
    
    
    	-- writing and reading memory processes
    	write_mem: process(wclk)
    	begin
    		if (wclk'event and wclk = '1') then
    			if (WriteEnable = '1') then
    				Mem(conv_integer(wpt)) <= DataIn; -- writing synchronous with write clock
    			end if;	
    		end if;
    	end process write_mem;
    
    	read_mem: process(rclk)
    	begin
    		if (rclk'event and rclk = '1') then
    			if (ReadEnable = '1') then
    				DataOut <= Mem(conv_integer(rpt)); -- synchronous with read clock
    			end if;
    		end if;
    	end process read_mem;
    
    
    	-- counting words in fifo
    	count_fifo_write: process(wclk, Reset, wr_cnt, WriteEnable)
    		variable count : unsigned(ADEPTH downto 0);
    	begin
    		count := wr_cnt;
    
    		if (WriteEnable = '1') then
    			count := count +1;
    		end if;
    		
    		if (Reset = '0') then
    			wr_cnt <= (others => '0');
    		else
    			wr_cnt <= count;
    		end if;
    	end process count_fifo_write;
    
    	count_fifo_read: process(rclk, Reset, rd_cnt, ReadEnable)
    		variable count : unsigned(ADEPTH downto 0);
    	begin
    		count := rd_cnt;
    
    		if (ReadEnable = '1') then
    			count := count +1;
    		end if;
    		
    		if (Reset = '0') then
    			rd_cnt <= (others => '0');
    		else
    			rd_cnt <= count;
    		end if;
    	end process count_fifo_read;
    
    	-- status flags
    	empty <= '1' when (wr_cnt = 0) else '0';
    	full  <= wr_cnt(ADEPTH);
    end architecture structural;
    Mấy chỗ em bôi đen là mấy chỗ em còn đang "lăn tăn" - không biết giải quyết thế nào. Cụ thể là:
    - Khi đọc một dữ liệu ra ngoài FIFO thì con trỏ read tăng lên 1 hay vẫn giữ nguyên? (vì theo em hiểu là khi FIFO thực hiện đọc một dữ liệu cũng là lấy dữ liệu ra khỏi FIFO luôn, vậy để lần đọc tiếp theo được thực hiện thì FIFO vẫn ở nguyên vị trí cũ là đọc được phần tử khác, cho đến khi gặp cờ empty)
    - Việc truyền dữ liệu và đọc dữ liệu ra khỏi FIFO như em viết trên kia có đúng ko ạ? Đoạn -- writing and reading memory processes


    Em mới "vỡ lòng" VHDL được một thời gian thôi nên code còn hạn chế lắm. Các bác xem rồi giúp em với ạ. Em cảm ơn nhiều nhiều

    PS: Bác nào có code của thằng này thì gửi lên cho em tham khảo với nhá, em tìm thử trên mạng nhưng không thấy có hoặc toàn code bằng Verilog (mà Verilog thì em mù tịt ). Hoặc các bác cứ hướng dẫn để em tự sửa cũng được

  • #2
    Nguyên văn bởi Mr.Hano Xem bài viết
    Em chào các bác,
    Em là mem mới, đang tập tọe tìm hiểu về Vi điện tử nên trong bài này có chỗ nào "hỏi ngu" mong các bác bỏ qua và tận tình giúp đỡ em với nhé .

    Em đang tìm hiểu về loại bộ nhớ FIFO không đồng bộ này. Theo em hiểu thì nó hoạt động với 2 xung đồng hồ khác nhau phục vụ cho việc đọc và ghi dữ liệu vào FIFO riêng rẽ.

    Em cũng thử code bằng VHDL theo Guide Asynchronous FIFO 6.1 của Xilinx nhưng còn một số chỗ chưa được hiểu rõ lắm nên muốn hỏi các bác ạ.
    Code của em đây:

    Code:
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_arith.all;
    use ieee.std_logic_unsigned.all;
    
    entity FIFO is
    	generic(
    		DEPTH : natural := 128;
    		WIDTH : natural := 4
    	);
    	port(
    		Reset       : in std_logic;				-- reset to default FIFO
    		wclk        : in std_logic; 				-- write clock
    		rclk        : in std_logic;                          	-- read clock 
    		
    		DataIn      : in std_logic_vector(WIDTH -1 downto 0);   -- Data input
    		WriteEnable : in std_logic;                          	-- write enable flag
    
    		DataOut     : out std_logic_vector(WIDTH -1 downto 0);  -- Data output
    		ReadEnable  : in std_logic;                          	-- read enable flag
    		
    		empty       : out std_logic;                            -- FIFO is empty
    		full        : out std_logic                          	-- FIFO is full
    	);
    end entity FIFO;
    
    architecture structural of FIFO is
    	function bitcount(n : in natural) return natural is
    		variable tmp : unsigned(4 downto 1);
    		variable cnt : natural;
    	begin
    		tmp := conv_unsigned(n, 4);
    		cnt := 4;
    		for dummy in 4 downto 1 loop
    			if (tmp(cnt) = '0') then
    				cnt := cnt -1;
    			end if;
    		end loop;
    
    		return cnt;
    	end function bitcount;
    
    	constant ADEPTH : natural := bitcount(DEPTH -1); -- 256 entries: range 255 downto 0
    
    	type Memory is array (DEPTH -1 downto 0) of std_logic_vector(WIDTH -1 downto 0);
    	signal Mem : Memory;
    
    	signal rpt, wpt : unsigned(ADEPTH -1 downto 0);
    	signal wr_cnt,rd_cnt : unsigned(ADEPTH downto 0);
    begin
    	
    	-- write pointer
    	U1_write_point: process(wclk, Reset)
    	begin
    		if (Reset = '0') then
    			wpt <= (others => '0');
    		elsif (wclk'event and wclk = '1') then
    			if (WriteEnable = '1') then
    				wpt <= wpt +1;
    			end if;
    		end if;
    	end process U1_write_point;
    
    	-- read pointer
    	U2_read_point: process(rclk, Reset)
    	begin
    		if (Reset = '0') then
    			rpt <= (others => '0');
    		elsif (rclk'event and rclk = '1') then
    			if (ReadEnable = '1') then
    				rpt <= rpt +1;
    			end if;
    		end if;
    	end process U2_read_point;
    
    
    	-- writing and reading memory processes
    	write_mem: process(wclk)
    	begin
    		if (wclk'event and wclk = '1') then
    			if (WriteEnable = '1') then
    				Mem(conv_integer(wpt)) <= DataIn; -- writing synchronous with write clock
    			end if;	
    		end if;
    	end process write_mem;
    
    	read_mem: process(rclk)
    	begin
    		if (rclk'event and rclk = '1') then
    			if (ReadEnable = '1') then
    				DataOut <= Mem(conv_integer(rpt)); -- synchronous with read clock
    			end if;
    		end if;
    	end process read_mem;
    
    
    	-- counting words in fifo
    	count_fifo_write: process(wclk, Reset, wr_cnt, WriteEnable)
    		variable count : unsigned(ADEPTH downto 0);
    	begin
    		count := wr_cnt;
    
    		if (WriteEnable = '1') then
    			count := count +1;
    		end if;
    		
    		if (Reset = '0') then
    			wr_cnt <= (others => '0');
    		else
    			wr_cnt <= count;
    		end if;
    	end process count_fifo_write;
    
    	count_fifo_read: process(rclk, Reset, rd_cnt, ReadEnable)
    		variable count : unsigned(ADEPTH downto 0);
    	begin
    		count := rd_cnt;
    
    		if (ReadEnable = '1') then
    			count := count +1;
    		end if;
    		
    		if (Reset = '0') then
    			rd_cnt <= (others => '0');
    		else
    			rd_cnt <= count;
    		end if;
    	end process count_fifo_read;
    
    	-- status flags
    	empty <= '1' when (wr_cnt = 0) else '0';
    	full  <= wr_cnt(ADEPTH);
    end architecture structural;
    Mấy chỗ em bôi đen là mấy chỗ em còn đang "lăn tăn" - không biết giải quyết thế nào. Cụ thể là:
    - Khi đọc một dữ liệu ra ngoài FIFO thì con trỏ read tăng lên 1 hay vẫn giữ nguyên? (vì theo em hiểu là khi FIFO thực hiện đọc một dữ liệu cũng là lấy dữ liệu ra khỏi FIFO luôn, vậy để lần đọc tiếp theo được thực hiện thì FIFO vẫn ở nguyên vị trí cũ là đọc được phần tử khác, cho đến khi gặp cờ empty)
    - Việc truyền dữ liệu và đọc dữ liệu ra khỏi FIFO như em viết trên kia có đúng ko ạ? Đoạn -- writing and reading memory processes


    Em mới "vỡ lòng" VHDL được một thời gian thôi nên code còn hạn chế lắm. Các bác xem rồi giúp em với ạ. Em cảm ơn nhiều nhiều

    PS: Bác nào có code của thằng này thì gửi lên cho em tham khảo với nhá, em tìm thử trên mạng nhưng không thấy có hoặc toàn code bằng Verilog (mà Verilog thì em mù tịt ). Hoặc các bác cứ hướng dẫn để em tự sửa cũng được
    Hello, bạn còn theo dõi thread này ko?

    Comment


    • #3
      Có, em vẫn đang theo dõi nó đây ạ.
      Em cũng đã tự tìm hiểu và trả lời đc các câu hỏi trên kia rồi nhưng em vẫn còn một chỗ hơi băn khoăn.
      Hình như code này của em viết sai, tức là việc báo full và empty của em chỉ phụ thuộc vào từng xung clock riêng biệt, nhưng như thế rất khó để đưa ra thông báo đúng (và em nghĩ code này chẳng khác gì code của FIFO đồng bộ @@!).
      Em đọc trong tài liệu Asynchronous FIFO 6.1 của XILINX thì thấy họ dùng kỹ thuật sử dụng vector đếm WRITE_COUNT và READ_COUNT để thông báo trạng thái chiếm bộ nhớ của FIFO, nhưng em cũng chưa hiểu rõ kỹ thuật này lắm và lúc nào thì báo full, lúc nào empty.
      Một tài liệu khác em đọc thì họ đề cập đến việc so sánh các con trỏ bằng mã Gray để chỉ ra full và empty và kỹ thuật đồng bộ con trỏ trên các xung miền clock đối lập (rptr trên wclk, còn wptr trên rclk). Em muốn hỏi là tại sao phải đồng bộ hóa con trỏ như vậy và với code mà em viết như ở trên thì việc đồng bộ hóa phải thực hiện ở chỗ nào ạ.

      Thank anh nhỉu

      P/S: Không biết anh hỏi để định giúp đỡ em, hay định close topic, nhưng em cứ đánh liều hỏi vì biết anh là cao thủ trong mảng này mà. Hì hì

      Comment


      • #4
        Ừ, mình hỏi để biết coi bạn còn theo dõi ko, không thôi trả lời chỉ có ma nó đọc.

        Trong async fifo, có 2 pointer 1 dùng để read và 1 để write: rptr, wptr. Mạch read ptr và wptr của bạn đã viết đúng. Không có gì phải bàn.
        Nói về full với empty trước đã, khoan nói vể write-count với read count.

        Mạch full sẽ synchronous với miền wclk, mạch empty sẽ synchronous với miền rclk. Ví dụ:

        Mạch sẽ full sau khi ghi thêm một giá trị nữa lúc wrptr = rdptr - 1 (ví dụ wrptr = 4, rdptr = 5) (1)
        Mạch sẽ empty sau khi đọc ra giá trị nữa lúc rdptr = wrptr - 1 (ví dụ rdptr = 4, wrptr = 5) (2)

        Nhưng vấn đề là phải thực hiện phép tính (1) ở miền wclk và phép tính (2) ở miền rclk

        Như vậy bạn phải chuyển giá trị của rdptr sang miền wclk : tạm gọi là rdptr_w. Để chuyển giá trị sang miển wclk, bạn phải chuyển đổi qua gray code trước. Chuyền miền clock và chuyển đổi lại binary code. Đặc tính của gray code là giá trị đểm kế tiếp chỉ thay đổi 1 bit so với giá trị đếm trước đó.

        ví dụ: rdptr = 4 , gray(4) = 0110, khi rdptr = 5, gray(5) = 0111 ==> Khi chuyển miền clock 4 bit 1 lúc như vậy, cần gray code để ở miền clock bên kia, mạch sẽ nhận giá trị đúng.
        Ở miền wclk, bạn lại ungray để lấy giá trị của rdptr_w. Ở miển wclk, bạn có thể dùng wrptr và rdptr_w để tính full và còn bao nhiêu ô trống.

        Tương tự cho wrptr_r ở miển rdclk.

        Comment


        • #5
          Dùng gray code vì lí do này:
          Khi bạn chuyển nhiều bit từ miền A sang miền B, thời gian để các bit này tới register của miền B sẽ khác nhau. nếu clkA và clkB hoàn toàn không liên quan gì thì sẽ có lúc bạn ghi sai.
          Vì dụ giá trị ban đấu là 0111 (7) và chuyển sang 1000 (8). Có nguy cơ là register ở miển B sẽ clock 1011. 2 bit đầu đến trước sườn của clkB, và 2 bit sau đến sau sườn của clkB

          Comment


          • #6
            Ah, em hiểu rồi. Như vậy là do hai xung đồng hồ này hoạt động độc lập nên ta cần phải có một biến so sánh kiểu như con trỏ rdptr_w kia thì mới thông báo full và empty như trên code kia được đúng ko ạ.

            Vậy bây giờ em phải viết thêm 2 components để chuyển rptr qua xung wclk và wptr qua xung rclk phải ko ạ?
            Trước tiên em phải tìm hiểu về việc chuyển từ bin sang Gray và chuyển từ Gray sang bin đã.

            Thanks bác, em đã hiểu cơ chế của nó rồi. Giờ em thử code lại xem sao đã ạ

            Comment


            • #7
              Good, hehe.

              Comment

              Về tác giả

              Collapse

              Mr.Hano Tìm hiểu thêm về Mr.Hano

              Bài viết mới nhất

              Collapse

              Đang tải...
              X