異步FIFO(內有Verilog設計及仿真激勵代碼)

前言:

FIFO本質爲RAM,分爲同步FIFO(SCFIFO)和異步FIFO(DCFIFO),前者讀寫用同一個時鐘信號,後者則使用雙時鐘讀寫。不過同步FIFO實際運用中較爲少(可用做數據緩存),一般多用異步FIFO,因爲在FPGA設計中,往往都是多時鐘系統,很少爲單時鐘(除非你單純做一個流水燈之類的簡單實驗)。這裏,筆者給大家做一個簡單的異步FIFO實驗,供大家參考。(在看這個實驗之前建議大家先學習同步FIFO,文字最後面我會附上同步FIFO的實驗鏈接

1. 實驗內容
瞭解掌握DCFIFO的工作原理以及其結構,設計DCFIFO模塊以及其test_bench,最後VIVADO進行功能實現和仿真驗證。

2. 實驗原理
在兩個時鐘域之間進行數據傳遞最常用的的使用方法就是異步FIFO。異步FIFO一般包括兩個端口,其中端口A是寫入端,端口B是讀入端。AFIFO中最常用的控制信號是“空”(empty)和“滿”(full),另外,“將空”(almost empty)、“將滿”(almost full)也是兩個經常使用的控制信號。

 **下圖爲DCFIFO外部鏈接關係**

DCFIFO外部鏈接關係
確定DCFIFO的空狀態或滿狀態需要一定的數學處理以及讀指針和寫指針的比較。關鍵問題是兩個指針在不同的時鐘域產生,所以指針必須經過同步化才能在另一時鐘域中進行比較和用於計算。對於異步FIFO來說,產生準確的“空”和“滿”指示信號是比較困難的,但爲了保證操作的安全,避免“滿”後仍繼續寫入和“空”後仍繼續讀出是可以做到的。
這裏爲了方便大家理解代碼,指針以及滿空信號的產生,及爲什麼要使用格雷碼指針,我找了相關資料供大家參考:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
以上圖片資料來源於百度條詞:異步FIFO

簡單描述二進制與格雷碼轉換:
二進制數 —————————— 1 0 1 1 0
(進制數右移1位,空位補 0) — 01 0 1 1
異或運算 —————————— 1 1 1 0 1
這樣就可以實現二進制到格雷碼的轉換了,總結就是移位並且異或,verilog代碼實現就一句話:assign rgraynext = (rbinnext>>1) ^ rbinnext;

3. 實驗代碼
①設計代碼

module DCFIFO(
	wdata,
	wclk,
	rinc,
	rdata,
	wfull,
	rempty,
	rclk,
	rrst_n,
	wrst_n,
	winc);

	input [7:0] wdata;
	input wclk;
	input rinc;
	output [7:0] rdata;
	output wfull;
	output rempty;
	input rclk;
	input rrst_n;
	input wrst_n;
	input winc;
	
     //輸入,輸出引腳類型定義
	wire [7:0] wdata;   
	wire wclk;
	wire rinc;
	wire [7:0] rdata;
	reg wfull;
	reg rempty;
	wire rclk;
	wire rrst_n;
	wire wrst_n;
	wire winc;

     
	  reg [4:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr;
	  reg [4:0] rbin, wbin;
	  reg [7:0] mem[0:(1<<4)-1];
	  wire[3:0] waddr, raddr;
	  wire [4:0]  rgraynext, rbinnext,wgraynext,wbinnext;
	  wire  rempty_val,wfull_val;
	   
	 assign rdata=mem[raddr];
	 
	   always@(posedge wclk)
	     if (winc && !wfull)
	       mem[waddr] <= wdata;
	   always @(posedge wclk or negedge wrst_n)
	          if (!wrst_n) 
	           {wq2_rptr,wq1_rptr} <= 0;
	          else 
	           {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};
	always @(posedge rclk or negedge rrst_n)
	        if (!rrst_n) 
	          {rq2_wptr,rq1_wptr} <= 0;
	        else 
	           {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr};
	 always @(posedge rclk or negedge rrst_n) 
	       if (!rrst_n) 
	          {rbin, rptr} <= 0;
	       else 
	           {rbin, rptr} <= {rbinnext, rgraynext};  
	  assign raddr = rbin[3:0];
	  assign rbinnext = rbin + (rinc & ~rempty);
	  assign rgraynext = (rbinnext>>1) ^ rbinnext;   //二進制與格雷碼轉換
	  assign rempty_val = (rgraynext == ~rq2_wptr);
	   
	  always @(posedge rclk or negedge rrst_n)
	      if (!rrst_n)
	         rempty <= 1'b1;
	      else 
	         rempty <= rempty_val;
	 always @(posedge wclk or negedge wrst_n)
	   if (!wrst_n)
	      {wbin, wptr} <= 0;
	   else 
	       {wbin, wptr} <= {wbinnext, wgraynext};
	   assign waddr = wbin[3:0];
	   assign wbinnext = wbin + (winc & ~wfull);
	   assign wgraynext = (wbinnext>>1) ^ wbinnext;
	   assign wfull_val = (wgraynext=={~wq2_rptr[4:4-1],
	                       wq2_rptr[4-2:0]});
	 always @(posedge wclk or negedge wrst_n)
	     if (!wrst_n) 
	         wfull <= 1'b0;
	     else 
	         wfull <= wfull_val;
	
	
endmodule  

 

設計原理圖如下:設計原理圖
②仿真激代碼

`timescale 1ns/1ns
module DCFIFO_test();

	reg [7:0] wdata;
	reg winc;
	reg wclk;
	reg wrst_n;
	reg rinc;
	reg rclk;
	reg rrst_n;
	wire [7:0] rdata;
	wire wfull;
	wire rempty;


	integer i;
	always begin 
	#10 wclk=1;
	#10 wclk=0;
	end
	always begin
	#15 rclk=1;
	#15 rclk=0;
	end
	initial begin
	wclk=0;rclk=0;wdata=0;winc=0;rinc=0;wrst_n=0;rrst_n=0;i=0;
	#2 winc=1;
	#2 rinc=0;
	for(i=0;i<=20;i=i+1)
	   begin
	   repeat(1)@(posedge wclk);
	    wrst_n=1;
	   wdata=wdata+1;
	   end
	   repeat(1)@(posedge wclk);
	   wrst_n=0;
	#100 rinc=1;
	#2 winc=0;
	for(i=0;i<=20;i=i+1)
	   begin
	   repeat(1)@(posedge rclk);
	   #2;
	   rrst_n=1;
	   end
	repeat(1)@(posedge rclk);
	   #2;
	   rrst_n=0;
	#100 rinc=0;
	#2 $finish;
	   end
	
	
//將設計模塊例化到仿真模塊中

	DCFIFO DCFIFO1(
		.wdata(wdata),
		.wclk(wclk),
		.rinc(rinc),
		.rdata(rdata),
		.wfull(wfull),
		.rempty(rempty),
		.rclk(rclk),
		.rrst_n(rrst_n),
		.wrst_n(wrst_n),
		.winc(winc));

endmodule   

仿真波形圖如下:
仿真波形圖
**後續:**因爲時間原因代碼的註釋還沒寫,後面如果有時間會補上,並對文章進行完整講解。

這裏推薦一位朋友寫的同步FIFO,內容很詳細,建議大家看學習異步FIFO之前先看這篇文章:verilog實現FIFO設計(一)之同步8位深度

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章