FPGA_ZYNQ FIFO实践心得

张开发
2026/5/31 8:41:10 15 分钟阅读
FPGA_ZYNQ FIFO实践心得
目录1.FIFO简介2.FIFO程序设计2.1读FIFO代码2.2写FIFO代码2.3顶层代码2.4仿真3.总结1.FIFO简介1.如果前后bps传输速率不一样则写满之后写等待读空之后读等待。2.FIFO区别于ROM和RAM没有外部的读写地址FIFO分为同步 异步FIFO整体框架如下 分为读写两大部分首先说明下上图中黑色箭头表示此信号为必要信号蓝色箭头表示此信号为可选信号灰色箭头表示此信号为可选的边带信号通常指在FIFO操作中除基本控制信号如empty/full外用于提供额外状 态信息的辅助信号。从图中我们可以了解到当被配置为同步 FIFO时只使用wr_clk所有的输入输出信号都同步于wr_clk 信号。而当被配置为异步 FIFO时写端口和读端口分别有独立的时钟所有与写相关的信号都是同步于写时钟 wr_clk所有与读相关的信号都是同步于读时钟rd_clk。1.wr_en写使能2.full 写满之后拉高3.almost full 将要写满之时拉高4.prog full 设置拉高时的存储个数5.din 写入数据2.FIFO程序设计点击IP 创建FIFO本次我们设计异步FIFO可以体现跨时钟效果创建三个文件同时创建PLL锁相环 观察在跨时钟域时fifo读写2.1读FIFO代码timescale 1ns / 1ps module fifo_rd ( //system clock input rd_clk , //时钟信号 input rst_n , //复位信号 //FIFO interface input rd_rst_busy , //读复位忙信号 input [7:0] fifo_rd_data, //从 FIFO 读出的数据 input full , //FIFO 满信号 input almost_empty, //FIFO 将空信号 output reg fifo_rd_en //FIFO 读使能 ); reg full_d0; reg full_d1; //所以对 full 打两拍同步到读时钟域下 always (posedge rd_clk or negedge rst_n) begin if(!rst_n) begin full_d0 1b0; full_d1 1b0; end else begin full_d0 full; full_d1 full_d0; end end //对 fifo_rd_en 进行赋值,FIFO 写满之后开始读读空之后停止读 always (posedge rd_clk or negedge rst_n) begin if(!rst_n) fifo_rd_en 1b0; else if(!rd_rst_busy) begin if(full_d1) fifo_rd_en 1b1; else if(almost_empty) fifo_rd_en 1b0; end else fifo_rd_en 1b0; end endmodule2.2写FIFO代码timescale 1ns / 1ps module fifo_wr ( input wr_clk, input rst_n, input wr_rst_busy, input empty, input almost_full, output reg fifo_wr_en, output reg [7:0] fifo_wr_data ); reg empty_d0; reg empty_d1; //因为 empty 信号是属于 FIFO 读时钟域的 //所以对 empty 打两拍同步到写时钟域下 always (posedge wr_clk or negedge rst_n) begin if(!rst_n) begin empty_d0 1b0; empty_d1 1b0; end else begin empty_d0 empty; empty_d1 empty_d0; end end //对 fifo_wr_en 赋值当 FIFO 为空时开始写入写满后停止写 always (posedge wr_clk or negedge rst_n) begin if(!rst_n) fifo_wr_en 1b0; else if(!wr_rst_busy) // 写复位忙 0 表示空闲 begin if(empty_d1) fifo_wr_en 1b1; else if(almost_full) // 写满 fifo_wr_en 1b0; end else fifo_wr_en 1b0; end //对 fifo_wr_data 赋值,0~254 always (posedge wr_clk or negedge rst_n) begin if(!rst_n) fifo_wr_data 8b0; else if(fifo_wr_en fifo_wr_data 8d254) fifo_wr_data fifo_wr_data 8b1; else fifo_wr_data 8b0; end endmodule2.3顶层代码注意 pll fifo的复位信号是取反的timescale 1ns / 1ps module ip_fifo ( input sys_clk, input sys_rst_n ); //wire define wire clk_50m ; // 50M 时钟 wire clk_100m ; // 100M 时钟 wire locked ; // 时钟锁定信号 wire rst_n ; // 复位低有效 wire wr_rst_busy ; // 写复位忙信号 wire rd_rst_busy ; // 读复位忙信号 wire fifo_wr_en ; // FIFO 写使能信号 wire fifo_rd_en ; // FIFO 读使能信号 wire [7:0] fifo_wr_data ; // 写入到 FIFO 的数据 wire [7:0] fifo_rd_data ; // 从 FIFO 读出的数据 wire almost_full ; // FIFO 将满信号 wire almost_empty ; // FIFO 将空信号 wire full ; // FIFO 满信号 wire empty ; // FIFO 空信号 wire [7:0] wr_data_count ; // FIFO 写时钟域的数据计数 wire [7:0] rd_data_count ; // FIFO 读时钟域的数据计数 wire pll_locked; // pll output locked clk_wiz_0 clk_wiz_0_u ( // Clock out ports .clk_out1(clk_50m), // output clk_out1 .clk_out2(clk_100m), // output clk_out2 .clk_out3(), // output clk_out3 // Status and control signals .reset(~sys_rst_n), // input reset .locked(pll_locked), // output locked // Clock in ports .clk_in1(sys_clk) ); // input clk_in1 my_fifo my_fifo_u ( .rst(~rst_n), // input wire rst .wr_clk(clk_50m), // input wire wr_clk .rd_clk(clk_100m), // input wire rd_clk .din(fifo_wr_data), // input wire [7 : 0] din .wr_en(fifo_wr_en), // input wire wr_en .rd_en(fifo_rd_en), // input wire rd_en .dout(fifo_rd_data), // output wire [7 : 0] dout .full(full), // output wire full .almost_full(almost_full), // output wire almost_full .empty(empty), // output wire empty .almost_empty(almost_empty), // output wire almost_empty .rd_data_count(rd_data_count), // output wire [7 : 0] rd_data_count .wr_data_count(wr_data_count), // output wire [7 : 0] wr_data_count .wr_rst_busy(wr_rst_busy), // output wire wr_rst_busy .rd_rst_busy(rd_rst_busy) // output wire rd_rst_busy ); fifo_wr fifo_wr_u ( .wr_clk (clk_50m), .rst_n (rst_n), .wr_rst_busy (wr_rst_busy), .empty (empty), .almost_full (almost_full), .fifo_wr_en (fifo_wr_en), .fifo_wr_data (fifo_wr_data ) ); fifo_rd fifo_rd_u ( .rd_clk (clk_100m), //时钟信号 .rst_n (rst_n), //复位信号 .rd_rst_busy (rd_rst_busy), //读复位忙信号 .fifo_rd_data (fifo_rd_data), //从 FIFO 读出的数据 .full (full), //FIFO 满信号 .almost_empty (almost_empty), //FIFO 将空信号 .fifo_rd_en (fifo_rd_en)//FIFO 读使能 ); endmodule2.4仿真timescale 1ns / 1ps module tb_ip_fifo(); parameter CLK_PERIOD 20; //时钟周期 20ns reg sys_clk; reg sys_rst_n; //信号初始化 initial begin sys_clk 1b0; sys_rst_n 1b0; #200 sys_rst_n 1b1; //模拟按下复位 #10000 ; sys_rst_n 0; #160 ; sys_rst_n 1; end always #(CLK_PERIOD/2) sys_clk ~sys_clk; ip_fifo u_ip_fifo ( .sys_clk (sys_clk ), .sys_rst_n (sys_rst_n) ); endmodule我们可以看出 在中间复位信号来临之时FIFO 内部之前存储的所有数据会被全部清空复位结束后 FIFO 中无任何历史数据同时 FIFO 会恢复到空empty初始状态可直接开始新的读写操作。RTL如下3.总结经过验证可以发现 ILA波形符合我们设计即FIFO读空了写写满了读。至此IP核之FIFO读写实验验证成功。

更多文章