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 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期