打印

异步FIFO的Verilog实现实例分析

[复制链接]
1685|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wmsk|  楼主 | 2013-1-22 11:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 wmsk 于 2013-1-22 11:36 编辑

//----------------------STYLE #1--------------------------

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产生-------------------

//-------------------

// GRAYSTYLE2 pointer

//-------------------

always @(posedge rclk or negedge rrst_n)

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);

assign rgraynext = (rbinnext>>1) ^ rbinnext;

//---------------------------------------------------------------

// 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产生------------------------------

// GRAYSTYLE2 pointer

always @(posedge wclk or negedge wrst_n)

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);

assign wgraynext = (wbinnext>>1) ^ wbinnext;

//------------------------------------------------------------------

// Simplified version of the three necessary full-tests:

// assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) &&

// (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) &&

// (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0]));

//------------------------------------------------------------------

assign wfull_val = (wgraynext=={~wq2_rptr[ASIZE:ASIZE-1],

wq2_rptr[ASIZE-2:0]});

always @(posedge wclk or negedge wrst_n)

if (!wrst_n) wfull <= 1'b0;

else wfull <= wfull_val;

endmodule

相关帖子

沙发
wmsk|  楼主 | 2013-1-22 11:34 | 只看该作者
本帖最后由 wmsk 于 2013-1-22 11:37 编辑

//---------------------STYLE #2-------------------------

module fifo2 (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;

wire [ASIZE-1:0] wptr, rptr;

wire [ASIZE-1:0] waddr, raddr;


async_cmp #(ASIZE) async_cmp(.aempty_n(aempty_n),

.afull_n(afull_n),

.wptr(wptr), .rptr(rptr),

.wrst_n(wrst_n));


fifomem2 #(DSIZE, ASIZE) fifomem2(.rdata(rdata),

.wdata(wdata),

.waddr(wptr),

.raddr(rptr),

.wclken(winc),

.wclk(wclk));


rptr_empty2 #(ASIZE) rptr_empty2(.rempty(rempty),

.rptr(rptr),

.aempty_n(aempty_n),

.rinc(rinc),

.rclk(rclk),

.rrst_n(rrst_n));


wptr_full2 #(ASIZE) wptr_full2(.wfull(wfull),

.wptr(wptr),

.afull_n(afull_n),

.winc(winc),

.wclk(wclk),

.wrst_n(wrst_n));

endmodule

module fifomem2 (rdata, wdata, waddr, raddr, wclken, wclk);

parameter DATASIZE = 8; // Memory data word width

parameter ADDRSIZE = 4; // Number of memory address bits

parameter DEPTH = 1<<ADDRSIZE; // DEPTH = 2**ADDRSIZE

output [DATASIZE-1:0] rdata;

input [DATASIZE-1:0] wdata;

input [ADDRSIZE-1:0] waddr, raddr;

input wclken, wclk;

`ifdef VENDORRAM

// instantiation of a vendor's dual-port RAM

VENDOR_RAM MEM (.dout(rdata), .din(wdata),

.waddr(waddr), .raddr(raddr),

.wclken(wclken), .clk(wclk));

`else

reg [DATASIZE-1:0] MEM [0: DEPTH-1];

assign rdata = MEM[raddr];

always @(posedge wclk)

if (wclken) MEM[waddr] <= wdata;

`endif

endmodule

module async_cmp (aempty_n, afull_n, wptr, rptr, wrst_n);

parameter ADDRSIZE = 4;

parameter N = ADDRSIZE-1;

output aempty_n, afull_n;

input [N:0] wptr, rptr;

input wrst_n;

reg direction;

wire high = 1'b1;

wire dirset_n = ~( (wptr[N]^rptr[N-1]) & ~(wptr[N-1]^rptr[N]));

wire dirclr_n = ~((~(wptr[N]^rptr[N-1]) & (wptr[N-1]^rptr[N])) |

~wrst_n);

always @(posedge high or negedge dirset_n or negedge dirclr_n)

if (!dirclr_n) direction <= 1'b0;

else if (!dirset_n) direction <= 1'b1;

else direction <= high;

//always @(negedge dirset_n or negedge dirclr_n)

//if (!dirclr_n) direction <= 1'b0;

//else direction <= 1'b1;

assign aempty_n = ~((wptr == rptr) && !direction);

assign afull_n = ~((wptr == rptr) && direction);

endmodule

module rptr_empty2 (rempty, rptr, aempty_n, rinc, rclk, rrst_n);

parameter ADDRSIZE = 4;

output rempty;

output [ADDRSIZE-1:0] rptr;

input aempty_n;

input rinc, rclk, rrst_n;

reg [ADDRSIZE-1:0] rptr, rbin;

reg rempty, rempty2;

wire [ADDRSIZE-1:0] rgnext, rbnext;

//---------------------------------------------------------------

// GRAYSTYLE2 pointer

//---------------------------------------------------------------

always @(posedge rclk or negedge rrst_n)

if (!rrst_n) begin

rbin <= 0;

rptr <= 0;

end

else begin

rbin <= rbnext;

rptr <= rgnext;

end

//---------------------------------------------------------------

// increment the binary count if not empty

//---------------------------------------------------------------

assign rbnext = !rempty ? rbin + rinc : rbin;

assign rgnext = (rbnext>>1) ^ rbnext; // binary-to-gray conversion

always @(posedge rclk or negedge aempty_n)

if (!aempty_n) {rempty,rempty2} <= 2'b11;

else {rempty,rempty2} <= {rempty2,~aempty_n};

endmodule

module wptr_full2 (wfull, wptr, afull_n, winc, wclk, wrst_n);

parameter ADDRSIZE = 4;

output wfull;

output [ADDRSIZE-1:0] wptr;

input afull_n;

input winc, wclk, wrst_n;

reg [ADDRSIZE-1:0] wptr, wbin;

reg wfull, wfull2;

wire [ADDRSIZE-1:0] wgnext, wbnext;

//---------------------------------------------------------------

// GRAYSTYLE2 pointer

//---------------------------------------------------------------

always @(posedge wclk or negedge wrst_n)

if (!wrst_n) begin

wbin <= 0;

wptr <= 0;

end

else begin

wbin <= wbnext;

wptr <= wgnext;

end

//---------------------------------------------------------------

// increment the binary count if not full

//---------------------------------------------------------------

assign wbnext = !wfull ? wbin + winc : wbin;

assign wgnext = (wbnext>>1) ^ wbnext; // binary-to-gray conversion

always @(posedge wclk or negedge wrst_n or negedge afull_n)

if (!wrst_n ) {wfull,wfull2} <= 2'b00;

else if (!afull_n) {wfull,wfull2} <= 2'b11;

else {wfull,wfull2} <= {wfull2,~afull_n};

endmodule


细心的读者会发现,第一种写法(本人做的修改)把所有信号写在同一个module里,而第二种写法则分了很多模块。哪种写法更好呢?有兴趣的可以想一想,事实上,第二种写法是推荐的写法:原因如下:

异步的多时钟设计应按以下几个原则进行设计:

1,尽可能的将多时钟的逻辑电路(非同步器)分割为多个单时钟的模块,这样有利于静态时序分析工具来进行时序验证。

2,同步器的实现应使得所有输入来自同一个时钟域,而使用另一个时钟域的异步时钟信号采样数据。

3,面向时钟信号的命名方式可以帮助我们确定那些在不同异步时钟域间需要处理的信号。

4,当存在多个跨时钟域的控制信号时,我们必须特别注意这些信号,保证这些控制信号到达新的时钟域仍然能够保持正确的顺序。

使用特权

评论回复
板凳
jlass| | 2013-1-22 11:51 | 只看该作者
从结构上讲,模块化肯定更好。

使用特权

评论回复
地板
GoldSunMonkey| | 2013-1-22 22:02 | 只看该作者
jlass 发表于 2013-1-22 11:51
从结构上讲,模块化肯定更好。

他讲的非常好。欢迎常来啊

使用特权

评论回复
5
wmsk|  楼主 | 2013-1-23 22:21 | 只看该作者
谢谢大家的支持啊

使用特权

评论回复
6
GoldSunMonkey| | 2013-1-23 22:21 | 只看该作者
wmsk 发表于 2013-1-23 22:21
谢谢大家的支持啊

不要太客气啊

使用特权

评论回复
7
vincentyeh| | 2013-2-20 16:39 | 只看该作者
AL460 Full HD FIFO DRAM 的基本结构FIFO(First in First out) 符合高速影像先进先出的结构,尤其适用于数码影像资料的暂存器使用。
一.独立的写入/ 输出程序,较低的输入clock rate,可有效地为贵司简化开发成本以及时间。
二.支援影像/图像数位资料VGA到1080p,内部架构为8Mx 16bit**体架构,最高速度可达到150MHz,可满足1080p的设计需求。
三.具有输入/输出智能控制(enable control) , 可做双倍**体(double buffer)控制,在frame 图框控制编程上尤其方便。

使用特权

评论回复
8
yuanchaonll| | 2013-8-2 16:51 | 只看该作者
请问楼主,Cyclone IV支持异步FIFO吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

411

帖子

1

粉丝