求解惑 | 异步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