求解惑 | 异步FIFO
目的:如果RAM地址为非2^N,如何用格雷码实现?
64-65 75-76手动修改变化时机,为啥就不能通过呢,自己写的testbench两个代码结果却又是一致的
`timescale 1ns/1ns
/***************************************RAM*****************************************/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。
,input [WIDTH-1:0] wdata //数据写入
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。
,output reg [WIDTH-1:0] rdata //数据输出
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/***************************************AFIFO*****************************************/
module asyn_fifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input wclk ,
input rclk ,
input wrstn , //
input rrstn , //
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,
output wire wfull , //
output wire rempty , //
output wire [WIDTH-1:0] rdata
);
//讀寫使能
wire wenc,renc;
assign wenc = winc & !wfull;
assign renc = rinc & !rempty;
//讀寫地址邏輯
parameter addr_len = $clog2(DEPTH);
reg [addr_len:0] waddr;
reg [addr_len:0] raddr;
always @(posedge wclk or negedge wrstn)
begin
if(!wrstn)
waddr <='d0;
else if (waddr[addr_len-1:0] == DEPTH-1)
waddr <= {~waddr[addr_len],{addr_len{1'b0}}};
else if(wenc)
waddr <= waddr + 1'b1;
end
always @(posedge rclk or negedge rrstn)
begin
if(!rrstn)
raddr <='d0;
else if (raddr[addr_len-1:0] == DEPTH-1)
raddr <= {~raddr[addr_len],{addr_len{1'b0}}};
else if(renc)
raddr <= raddr + 1'b1;
end
//消除亞穩態;
//A.格雷碼【addr⊕(addr>>1)】相鄰只變換一個位,可有效防止繼存存捕獲中間態。
//如011-100,變了三位,格雷碼 011-010,只變了一位
//B.常規打二拍
wire [addr_len:0] waddr_gray,raddr_gray;
reg [addr_len:0] waddr_gray_pat,raddr_gray_pat,waddr_pat1,waddr_pat2,raddr_pat1,raddr_pat2;
assign waddr_gray = waddr ^ (waddr >> 1 );
assign raddr_gray = raddr ^ (raddr >> 1 );
always @(posedge wclk or negedge wrstn)
begin
if(~wrstn) begin
waddr_gray_pat <='d0;
end
else begin
waddr_gray_pat <= waddr_gray;
end
end
always @(posedge rclk or negedge rrstn)
begin
if(~rrstn) begin
raddr_gray_pat <='d0;
end
else begin
raddr_gray_pat <= raddr_gray;
end
end
always @(posedge wclk or negedge wrstn)
begin
if(~wrstn) begin
raddr_pat1 <='d0;
raddr_pat2 <='d0;
end
else begin
raddr_pat1 <= raddr_gray_pat;
raddr_pat2 <= raddr_pat1;
end
end
always @(posedge rclk or negedge rrstn)
begin
if(~rrstn) begin
waddr_pat1 <='d0;
waddr_pat2 <='d0;
end
else begin
waddr_pat1 <= waddr_gray_pat;
waddr_pat2 <= waddr_pat1;
end
end
//滿/空判斷
// 要求實時性反應,采用組合邏輯
assign wfull = waddr_gray_pat == {~raddr_pat2[addr_len:addr_len-1],raddr_pat2[addr_len-2:0]};
assign rempty = raddr_gray_pat == waddr_pat2;
//連綫
wire [addr_len-1:0] waddr_f,raddr_f;
assign waddr_f = waddr[addr_len-1:0];
assign raddr_f = raddr[addr_len-1:0];
dual_port_RAM #(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
dual_port_RAM0(
.wclk (wclk),
.wenc (wenc),
.waddr (waddr_f), //
.wdata (wdata),
.rclk (rclk),
.renc (renc),
.raddr (raddr_f), //
.rdata (rdata)
);
endmodule
