电子大神的日记本,供应链专家的功夫茶盘,在这里记录、分享与共鸣。

登录以开始

异步FIFO及verilog原码_2

两篇文章的原码
//----------------------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<>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

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

博主
362831662@qq.com
jinger1985's Blog
一名优秀的电子工程师就是不断地进步!!! --------收获点滴,感悟人生。  
点击跳转