目录
描述
输入描述:
输出描述:
参考代码
描述
请根据题目中给出的双口RAM代码和接口描述,实现异步FIFO,要求FIFO位宽和深度参数化可配置。
电路的接口如下图所示。
双口RAM端口说明:
端口名 | I/O | 描述 |
wclk | input | 写数据时钟 |
wenc | input | 写使能 |
waddr | input | 写地址 |
wdata | input | 输入数据 |
rclk | input | 读数据时钟 |
renc | input | 读使能 |
raddr | input | 读地址 |
rdata | output | 输出数据 |
同步FIFO端口说明:
端口名 | I/O | 描述 |
wclk | input | 写时钟 |
rclk | input | 读时钟 |
wrstn | input | 写时钟域异步复位 |
rrstn | input | 读时钟域异步复位 |
winc | input | 写使能 |
rinc | input | 读使能 |
wdata | input | 写数据 |
wfull | output | 写满信号 |
rempty | output | 读空信号 |
rdata | output | 读数据 |
双口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) beginif(wenc)RAM_MEM[waddr] <= wdata;
end always @(posedge rclk) beginif(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
);parameter ADDR_WIDTH = $clog2(DEPTH);/**********************addr bin gen*************************/
reg [ADDR_WIDTH:0] waddr_bin;
reg [ADDR_WIDTH:0] raddr_bin;always @(posedge wclk or negedge wrstn) beginif(~wrstn) beginwaddr_bin <= 'd0;end else if(!wfull && winc)beginwaddr_bin <= waddr_bin + 1'd1;end
end
always @(posedge rclk or negedge rrstn) beginif(~rrstn) beginraddr_bin <= 'd0;end else if(!rempty && rinc)beginraddr_bin <= raddr_bin + 1'd1;end
end/**********************addr gray gen*************************/
wire [ADDR_WIDTH:0] waddr_gray;
wire [ADDR_WIDTH:0] raddr_gray;
reg [ADDR_WIDTH:0] wptr;
reg [ADDR_WIDTH:0] rptr;
assign waddr_gray = waddr_bin ^ (waddr_bin>>1);
assign raddr_gray = raddr_bin ^ (raddr_bin>>1);
always @(posedge wclk or negedge wrstn) begin if(~wrstn) beginwptr <= 'd0;end else beginwptr <= waddr_gray;end
end
always @(posedge rclk or negedge rrstn) begin if(~rrstn) beginrptr <= 'd0;end else beginrptr <= raddr_gray;end
end
/**********************syn addr gray*************************/
reg [ADDR_WIDTH:0] wptr_buff;
reg [ADDR_WIDTH:0] wptr_syn;
reg [ADDR_WIDTH:0] rptr_buff;
reg [ADDR_WIDTH:0] rptr_syn;
always @(posedge wclk or negedge wrstn) begin if(~wrstn) beginrptr_buff <= 'd0;rptr_syn <= 'd0;end else beginrptr_buff <= rptr;rptr_syn <= rptr_buff;end
end
always @(posedge rclk or negedge rrstn) begin if(~rrstn) beginwptr_buff <= 'd0;wptr_syn <= 'd0;end else beginwptr_buff <= wptr;wptr_syn <= wptr_buff;end
end
/**********************full empty gen*************************/
assign wfull = (wptr == {~rptr_syn[ADDR_WIDTH:ADDR_WIDTH-1],rptr_syn[ADDR_WIDTH-2:0]});
assign rempty = (rptr == wptr_syn);/**********************RAM*************************/
wire wen ;
wire ren ;
wire wren;//high write
wire [ADDR_WIDTH-1:0] waddr;
wire [ADDR_WIDTH-1:0] raddr;
assign wen = winc & !wfull;
assign ren = rinc & !rempty;
assign waddr = waddr_bin[ADDR_WIDTH-1:0];
assign raddr = raddr_bin[ADDR_WIDTH-1:0];dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH)
)dual_port_RAM(.wclk (wclk), .wenc (wen), .waddr(waddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。.wdata(wdata), //数据写入.rclk (rclk), .renc (ren), .raddr(raddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。.rdata(rdata) //数据输出
);endmodule