描述
请根据题目中给出的双口RAM代码和接口描述,实现异步FIFO,要求FIFO位宽和深度参数化可配置。
电路的接口如下图所示。
双口RAM端口说明:
同步FIFO端口说明:
双口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
输入描述:
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
代码
`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
);
localparam PTR_WIDTH = $clog2(DEPTH);
reg [PTR_WIDTH : 0] wr_ptr, rd_ptr;
reg [PTR_WIDTH : 0] wr_ptr_gray, rd_ptr_gray; // xpm_cdc_gray
reg [PTR_WIDTH : 0] wr_ptr_gray_cdc[1:0], rd_ptr_gray_cdc[1:0];
reg [PTR_WIDTH : 0] wr_ptr_rclk, rd_ptr_wclk;
//========================================================
//= gray encode
//========================================================
integer i, j, k, l; // ......
always @(posedge rclk or negedge rrstn) begin
if (~rrstn) begin
rd_ptr_gray <= 'd0;
end else begin
rd_ptr_gray[PTR_WIDTH] <= rd_ptr[PTR_WIDTH];
for (i = 0; i < PTR_WIDTH; i = i + 1) begin
rd_ptr_gray[i] <= rd_ptr[i + 1] ^ rd_ptr[i];
end
end
end
always @(posedge wclk or negedge wrstn) begin
if (~wrstn) begin
wr_ptr_gray <= 'd0;
end else begin
wr_ptr_gray[PTR_WIDTH] <= wr_ptr[PTR_WIDTH];
for (j = 0; j < PTR_WIDTH; j = j + 1) begin
wr_ptr_gray[j] <= wr_ptr[j + 1] ^ wr_ptr[j];
end
end
end
//========================================================
//= clock domain crossing
//========================================================
always @(posedge wclk or negedge wrstn) begin
if (~wrstn) begin
rd_ptr_gray_cdc[1] <= 'd0;
rd_ptr_gray_cdc[0] <= 'd0;
end else begin
rd_ptr_gray_cdc[1] <= rd_ptr_gray_cdc[0];
rd_ptr_gray_cdc[0] <= rd_ptr_gray;
end
end
always @(posedge rclk or negedge rrstn) begin
if (~rrstn) begin
wr_ptr_gray_cdc[1] <= 'd0;
wr_ptr_gray_cdc[0] <= 'd0;
end else begin
wr_ptr_gray_cdc[1] <= wr_ptr_gray_cdc[0];
wr_ptr_gray_cdc[0] <= wr_ptr_gray;
end
end
//========================================================
//= gray decode
//========================================================
always @(*) begin
rd_ptr_wclk[PTR_WIDTH] = rd_ptr_gray_cdc[1][PTR_WIDTH];
for (k = PTR_WIDTH - 1; k >= 0; k = k - 1) begin // blocking assignment, [i + 1] need update before [i]
rd_ptr_wclk[k] = rd_ptr_wclk[k + 1] ^ rd_ptr_gray_cdc[1][k];
end
end
always @(*) begin
wr_ptr_rclk[PTR_WIDTH] = wr_ptr_gray_cdc[1][PTR_WIDTH];
for (l = PTR_WIDTH - 1; l >= 0; l = l - 1) begin
wr_ptr_rclk[l] = wr_ptr_rclk[l + 1] ^ wr_ptr_gray_cdc[1][l];
end
end
//========================================================
//= fifo pointer (clog2(DEPTH) ** 2 == DEPTH)
//========================================================
always @(posedge wclk or negedge wrstn) begin
if (~wrstn) begin
wr_ptr <= 'd0;
end else begin
if (winc & ~wfull) begin
wr_ptr <= wr_ptr + 'd1;
end
end
end
always @(posedge rclk or negedge rrstn) begin
if (~rrstn) begin
rd_ptr <= 'd0;
end else begin
if (rinc & ~rempty) begin
rd_ptr <= rd_ptr + 'd1;
end
end
end
reg wfull_s, rempty_s;
assign wfull = wfull_s;
assign rempty = rempty_s;
always @(*) begin
// if (~wrstn) begin
// wfull_s = 1'b0;
// end else begin
// wfull_s = (wr_ptr[PTR_WIDTH] != rd_ptr_wclk[PTR_WIDTH]) && (wr_ptr[PTR_WIDTH - 1 : 0] == rd_ptr_wclk[PTR_WIDTH - 1 : 0]);
wfull_s = (wr_ptr_gray[PTR_WIDTH] != rd_ptr_gray_cdc[1][PTR_WIDTH]) &&
(wr_ptr_gray[PTR_WIDTH - 1] != rd_ptr_gray_cdc[1][PTR_WIDTH - 1]) &&
(wr_ptr_gray[PTR_WIDTH - 2 : 0] == rd_ptr_gray_cdc[1][PTR_WIDTH - 2 : 0]); //比较格雷码大小
// end
end
always @(*) begin
// if (~rrstn) begin
// rempty_s = 1'b1;
// end else begin
// rempty_s = (rd_ptr == wr_ptr_rclk);
rempty_s = (rd_ptr_gray == wr_ptr_gray_cdc[1]);
// end
end
wire [WIDTH-1:0] ram_rdata;
// assign rdata = (~rrstn) ? 'd0 : ram_rdata;
assign rdata = ram_rdata;
dual_port_RAM #(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
) dual_port_RAM_inst(
.wclk (wclk ),
.wenc (winc & ~wfull ),
.waddr(wr_ptr[PTR_WIDTH - 1 : 0]),
.wdata(wdata ),
.rclk (rclk ),
.renc (rinc & ~rempty ),
.raddr(rd_ptr[PTR_WIDTH - 1 : 0]),
.rdata(ram_rdata )
);
endmodule