Verilog实现异步fifo


代码

module tb_asyn_fifo #(
parameter WIDTH = 16,
parameter DEPTH = 8
)(
input w_clk,
input r_clk,
input [WIDTH-1:0] w_data,
input wr_en,
input re_en,
input rst_n,
output wire full,
output wire empty,
output [WIDTH-1:0] r_data
);
reg [$clog2(DEPTH):0] w_addr;
reg [$clog2(DEPTH):0] r_addr;
//write
always@(posedge w_clk or negedge rst_n)
begin
if(!rst_n)
begin
w_addr <= 'd0;
end
else if(wr_en && !full)
begin
w_addr <= w_addr + 1'd1;
end
end
//read
always@(posedge r_clk or negedge rst_n)
begin
if(!rst_n)
begin
r_addr <= 'd0;
end
else if(re_en && !empty)
begin
r_addr <= r_addr + 1'd1;
end
end
wire [$clog2(DEPTH):0] w_addr_gray;
wire [$clog2(DEPTH):0] r_addr_gray;
reg [$clog2(DEPTH):0] w_addr_gray1;
reg [$clog2(DEPTH):0] w_addr_gray2;
reg [$clog2(DEPTH):0] r_addr_gray1;
reg [$clog2(DEPTH):0] r_addr_gray2;
assign w_addr_gray = (w_addr >> 1)^w_addr;
assign r_addr_gray = (r_addr >> 1)^r_addr;
//full
always@(posedge r_clk or negedge rst_n)
begin
if(!rst_n)
begin
w_addr_gray1 <= 'd0;
w_addr_gray2 <= 'd0;
end
else begin
w_addr_gray1 <= w_addr_gray;
w_addr_gray2 <= w_addr_gray1;
end
end
//empty
always@(posedge w_clk or negedge rst_n)
begin
if(!rst_n)
begin
r_addr_gray1 <= 'd0;
r_addr_gray2 <= 'd0;
end
else begin
r_addr_gray1 <= r_addr_gray;
r_addr_gray2 <= r_addr_gray1;
end
end
//full empty
assign empty = (w_addr_gray2 == r_addr_gray)?1'b1:1'b0;
assign full = ((w_addr_gray[$clog2(DEPTH)-2:0] == r_addr_gray2[$clog2(DEPTH)-2:0]) && ((w_addr_gray[$clog2(DEPTH):$clog2(DEPTH)-1] != r_addr_gray2[$clog2(DEPTH):$clog2(DEPTH)-1])))?1'b1:1'b0; //高两位不同,其余相同
//ram
dual_port_ram #(
.WIDTH(WIDTH),
.DEPTH(DEPTH)
)dual_port_ram_init(
.w_clk(w_clk),
.r_clk(r_clk),
.w_data(w_data),
.r_data(r_data),
.w_en(wr_en && !full),
.r_en(re_en && !empty),
.w_addr(w_addr[$clog2(DEPTH)-1:0]),
.r_addr(r_addr[$clog2(DEPTH)-1:0])
);
endmodule

ram:

module dual_port_ram #(
parameter WIDTH = 16,
parameter DEPTH = 8
)(
input w_clk,
input r_clk,
input [WIDTH-1:0] w_data,
input w_en,
input r_en,
input [$clog2(DEPTH)-1:0] w_addr,
input [$clog2(DEPTH)-1:0] r_addr,
output reg [WIDTH-1:0] r_data
);
reg [WIDTH-1:0] dual_port_ram[0:DEPTH-1];
always @(posedge w_clk )
begin
if(w_en)
dual_port_ram[w_addr] <= w_data;
end
always @(posedge r_clk)
begin
if(r_en)
r_data <= dual_port_ram[r_addr] ;
end
endmodule

仿真:

`timescale 1ns / 1ps
module asyn_fifo_tb;
reg rst_n;
reg wr_clk;
reg wr_en;
reg [15:0] data_in;
wire full;
reg rd_clk;
reg rd_en;
wire [15:0] data_out;
wire empty;
asyn_fifo asyn_fifo_inst
(
.rst_n (rst_n),
.w_clk (wr_clk),
.wr_en (wr_en),
.w_data (data_in),
.full (full),
.r_clk (rd_clk),
.re_en (rd_en),
.r_data (data_out),
.empty (empty)
);
initial wr_clk = 0;
always#10 wr_clk = ~wr_clk;
initial rd_clk = 0;
always#30 rd_clk = ~rd_clk;
always@(posedge wr_clk or negedge rst_n)begin
if(!rst_n)
data_in <= 'd0;
else if(wr_en)
data_in <= data_in + 1'b1;
else
data_in <= data_in;
end
initial begin
rst_n = 0;
wr_en = 0;
rd_en = 0;
#200;
rst_n = 1;
wr_en = 1;
#600;
wr_en = 0;
rd_en = 1;
#1000;
rd_en = 0;
$stop;
end
endmodule

本文作者:大耳毛豆

本文链接:https://www.cnblogs.com/yjxmike/p/18731309

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   大耳毛豆  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起