异步FIFO的Verilog代码 DCFIFO实现

来源:互联网 发布:驱动软件下载排行榜 编辑:程序博客网 时间:2024/06/05 03:37

 异步FIFO   异步FIFO是跨时钟域设计方法的集中体现,体现了很多的方法。不过,其中最重要的有两点,一个就是亚稳态,一个就是和亚稳态类似但不相同的——多个控制/状态信号的跨时钟传递。具体地说,就是当你把一组信号传递到另外一个时钟域的话,这一组信号可能因为延迟不同,这样到达新时钟域之后,得到的数据相差一个老时钟域的时钟周期。幸好,对于FIFO,需要传递的是一个计数器,这个计数器可以编码成格雷码(gray code),这样的编码每次只变化一个位,正好解决了上面的问题(要是没有画过图,最好画一个图看一下)。真不清楚这是怎么发明的!注意,这里其实还对格雷码的相对延迟和相关的时钟周期有一个要求。这就是异步FIFO中最关键的一点,至于指针如何控制,稍微考虑一下都很容易清楚。需要注意的是,这些东西不是用嘴能说清楚的,最好画一个示意图,不要因为没有说清楚,让主考官觉得你没有清楚。


异步FIFO的Verilog代码 之一

这个是基于RAM的异步FIFO代码,个人认为代码结构简单易懂,非常适合于考试中填写。记得10月份参加威盛的笔试的时候,就考过异步FIFO的实现。想当初要是早点复习,可能就可以通过威盛的笔试了。

与之前的用RAM实现的同步FIFO的程序相比,异步更为复杂。增加了读写控制信号的跨时钟域的同步。此外,判空与判满的也稍有不同。


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


parameter DSIZE = 8; 
parameter ASIZE = 4;


output [DSIZE-1:0] rdata;
output wfull;
output rempty;
input [DSIZE-1:0] wdata;
input winc, wclk, wrst_n;
input rinc, rclk, rrst_n;


reg wfull,rempty;
reg [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr;
reg [ASIZE:0] rbin, wbin;
reg [DSIZE-1:0] mem[0:(1<<ASIZE)-1];


wire [ASIZE-1:0] waddr, raddr;
wire [ASIZE:0] rgraynext, rbinnext,wgraynext,wbinnext;
wire rempty_val,wfull_val;


//-----------------双口RAM存储器--------------------
assign rdata=mem[raddr];
always@(posedge wclk)
if (winc && !wfull) mem[waddr] <= wdata;



//-------------同步rptr 指针-------------------------
always @(posedge wclk or negedge wrst_n)
if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0;
else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};


//-------------同步wptr指针---------------------------
always @(posedge rclk or negedge rrst_n)
if (!rrst_n) {rq2_wptr,rq1_wptr} <= 0;
else {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr};


//-------------rempty产生与raddr产生-------------------
always @(posedge rclk or negedge rrst_n) // GRAYSTYLE2 pointer
begin
if (!rrst_n) {rbin, rptr} <= 0;
else {rbin, rptr} <= {rbinnext, rgraynext};
end


// Memory read-address pointer (okay to use binary to address memory)
assign raddr = rbin[ASIZE-1:0];
assign rbinnext = rbin + (rinc & ~rempty);//二进制 rbinnext
assign rgraynext = (rbinnext>>1) ^ rbinnext;//二进制 rbinnext 转为 格雷码 rgraynext


// FIFO empty when the next rptr == synchronized wptr or on reset
assign rempty_val = (rgraynext == rq2_wptr);


always @(posedge rclk or negedge rrst_n)
begin
if (!rrst_n) rempty <= 1'b1;
else rempty <= rempty_val;
end


//---------------wfull产生与waddr产生------------------------------
always @(posedge wclk or negedge wrst_n) // GRAYSTYLE2 pointer
if (!wrst_n) {wbin, wptr} <= 0;
else {wbin, wptr} <= {wbinnext, wgraynext};


// Memory write-address pointer (okay to use binary to address memory)
assign waddr = wbin[ASIZE-1:0];
assign wbinnext = wbin + (winc & ~wfull);//二进制 wbinnext
assign wgraynext = (wbinnext>>1) ^ wbinnext;//二进制 wbinnext 转为 格雷码 wgraynext


assign wfull_val = (wgraynext=={~wq2_rptr[ASIZE:ASIZE-1], wq2_rptr[ASIZE-2:0]}); 

//【可以画一下4位卡诺图,看看二进制相差8的两个格雷码:仅高两位按位取反,除高两位外的低位数值一样!】


always @(posedge wclk or negedge wrst_n)
if (!wrst_n) wfull <= 1'b0;
else wfull <= wfull_val;


endmodule



0 0
原创粉丝点击