主页 > 创业  > 

ZYNQ-PL实践课堂(五)IP核之FIFO

ZYNQ-PL实践课堂(五)IP核之FIFO

ZYNQ-PL实践课堂(四)IP核之FIFO) 1 概述2 程序2.1 FIFO IP核2.2 写FIFO模块2.3 读FIFO模块2.4 顶层例化模块 3 仿真总结

1 概述

FIFO在fpga应用过程相当于一个先进先出的缓冲器,跨时钟域传输信号传递,采用顺序写入数据并顺序独处数据。 根据FIFO工作的时钟域可以分为同步FIFO和异步FIFO。

选择同步 FIFO: 只使用 wr_clk,所有的输入输出信号都同步于 wr_clk 信号; 选择异步 FIFO: 写端口同步于写时钟 wr_clk和读端口同步于读时钟 rd_clk。

FIFO的参数如下:

FIFO 宽度 : 一次读写操作的数据位 N; FIFO 深度 : 存储多少个宽度为 N 位的数据; 将空标志 : 即将被读空; 空标志 : 已空时由 FIFO 的状态电路送出的一个信号; 将满标志 : 即将被写满。 满标志 : 已满或将要写满时由 FIFO 的状态电路送出的一个信号; 读时钟 : 读 FIFO 时所遵循的时钟,在每个时钟的上升沿触发。 写时钟 : 写 FIFO 时所遵循的时钟,在每个时钟的上升沿触发。

2 程序 2.1 FIFO IP核

选择IP Catalog添加FIFO, Basic 设置异步FIFO, 设置写FIFO深度、写FIFO宽度、读FIFO宽度如下, 设定专用的输入口, 使用“即将写满”和“即将读空”这两个信号, “Data Counts”设置 FIFO 内数据计数的输出信号, Summary如下,

2.2 写FIFO模块 module fifo_wr( //mudule clock input clk , // 时钟信号 input rst_n , // 复位信号 //FIFO interface input almost_empty, // FIFO将空信号 input almost_full , // FIFO将满信号 output reg fifo_wr_en , // FIFO写使能 output reg [7:0] fifo_wr_data // 写入FIFO的数据 ); //reg define reg [1:0] state ; //动作状态 reg almost_empty_d0 ; //almost_empty 延迟一拍 reg almost_empty_syn ; //almost_empty 延迟两拍 reg [3:0] dly_cnt ; //延迟计数器 //***************************************************** //** main code //***************************************************** //因为 almost_empty 信号是属于FIFO读时钟域的 //所以要将其同步到写时钟域中 always@( posedge clk ) begin if( !rst_n ) begin almost_empty_d0 <= 1'b0 ; almost_empty_syn <= 1'b0 ; end else begin almost_empty_d0 <= almost_empty ; almost_empty_syn <= almost_empty_d0 ; end end //向FIFO中写入数据 always @(posedge clk ) begin if(!rst_n) begin fifo_wr_en <= 1'b0; fifo_wr_data <= 8'd0; state <= 2'd0; dly_cnt <= 4'd0; end else begin case(state) 2'd0: begin if(almost_empty_syn) begin //如果检测到FIFO将被读空 state <= 2'd1; //就进入延时状态 end else state <= state; end 2'd1: begin if(dly_cnt == 4'd10) begin //延时10拍 //原因是FIFO IP核内部状态信号的更新存在延时 //延迟10拍以等待状态信号更新完毕 dly_cnt <= 4'd0; state <= 2'd2; //开始写操作 fifo_wr_en <= 1'b1; //打开写使能 end else dly_cnt <= dly_cnt + 4'd1; end 2'd2: begin if(almost_full) begin //等待FIFO将被写满 fifo_wr_en <= 1'b0; //关闭写使能 fifo_wr_data <= 8'd0; state <= 2'd0; //回到第一个状态 end else begin //如果FIFO没有被写满 fifo_wr_en <= 1'b1; //则持续打开写使能 fifo_wr_data <= fifo_wr_data + 1'd1; //且写数据值持续累加 end end default : state <= 2'd0; endcase end end endmodule 2.3 读FIFO模块 module fifo_rd( //system clock input clk , // 时钟信号 input rst_n , // 复位信号 //FIFO interface input [7:0] fifo_dout , // 从FIFO读出的数据 input almost_full ,// FIFO将满信号 input almost_empty,// FIFO将空信号 output reg fifo_rd_en // FIFO读使能 ); //reg define reg [1:0] state ; // 动作状态 reg almost_full_d0 ; // fifo_full 延迟一拍 reg almost_full_syn ; // fifo_full 延迟两拍 reg [3:0] dly_cnt ; //延迟计数器 //***************************************************** //** main code //***************************************************** //因为 fifo_full 信号是属于FIFO写时钟域的 //所以要将其同步到读时钟域中 always@( posedge clk ) begin if( !rst_n ) begin almost_full_d0 <= 1'b0 ; almost_full_syn <= 1'b0 ; end else begin almost_full_d0 <= almost_full ; almost_full_syn <= almost_full_d0 ; end end //读出FIFO的数据 always @(posedge clk ) begin if(!rst_n) begin fifo_rd_en <= 1'b0; state <= 2'd0; dly_cnt <= 4'd0; end else begin case(state) 2'd0: begin if(almost_full_syn) //如果检测到FIFO将被写满 state <= 2'd1; //就进入延时状态 else state <= state; end 2'd1: begin if(dly_cnt == 4'd10) begin //延时10拍 //原因是FIFO IP核内部状态信号的更新存在延时 //延迟10拍以等待状态信号更新完毕 dly_cnt <= 4'd0; state <= 2'd2; //开始读操作 end else dly_cnt <= dly_cnt + 4'd1; end 2'd2: begin if(almost_empty) begin //等待FIFO将被读空 fifo_rd_en <= 1'b0; //关闭读使能 state <= 2'd0; //回到第一个状态 end else //如果FIFO没有被读空 fifo_rd_en <= 1'b1; //则持续打开读使能 end default : state <= 2'd0; endcase end end 2.4 顶层例化模块

创建 源文件 ip_fifo.v,作为顶层模块,实现前三个模块信息交互。

module ip_fifo( input sys_clk , // 时钟信号 input sys_rst_n // 复位信号 ); //wire define wire fifo_wr_en ; // FIFO写使能信号 wire fifo_rd_en ; // FIFO读使能信号 wire [7:0] fifo_din ; // 写入到FIFO的数据 wire [7:0] fifo_dout ; // 从FIFO读出的数据 wire almost_full ; // FIFO将满信号 wire almost_empty ; // FIFO将空信号 wire fifo_full ; // FIFO满信号 wire fifo_empty ; // FIFO空信号 wire [7:0] fifo_wr_data_count ; // FIFO写时钟域的数据计数 wire [7:0] fifo_rd_data_count ; // FIFO读时钟域的数据计数 //例化FIFO IP核 fifo_generator_0 fifo_generator_0 ( .wr_clk ( sys_clk ), // input wire wr_clk .rd_clk ( sys_clk ), // input wire rd_clk .wr_en ( fifo_wr_en ), // input wire wr_en .rd_en ( fifo_rd_en ), // input wire rd_en .din ( fifo_din ), // input wire [7 : 0] din .dout ( fifo_dout ), // output wire [7 : 0] dout .almost_full (almost_full ), // output wire almost_full .almost_empty (almost_empty ), // output wire almost_empty .full ( fifo_full ), // output wire full .empty ( fifo_empty ), // output wire empty .wr_data_count ( fifo_wr_data_count ), // output wire [7 : 0] wr_data_count .rd_data_count ( fifo_rd_data_count ) // output wire [7 : 0] rd_data_count ); //例化 - 写FIFO模块 fifo_wr u_fifo_wr( .clk ( sys_clk ), // 写时钟 .rst_n ( sys_rst_n ), // 复位信号 .fifo_wr_en ( fifo_wr_en ) , // fifo写请求 .fifo_wr_data ( fifo_din ) , // 写入FIFO的数据 .almost_empty ( almost_empty ), // fifo空信号 .almost_full ( almost_full ) // fifo满信号 ); //例化 - 读FIFO模块 fifo_rd u_fifo_rd( .clk ( sys_clk ), // 读时钟 .rst_n ( sys_rst_n ), // 复位信号 .fifo_rd_en ( fifo_rd_en ), // fifo读请求 .fifo_dout ( fifo_dout ), // 从FIFO输出的数据 .almost_empty ( almost_empty ), // fifo空信号 .almost_full ( almost_full ) // fifo满信号 ); //例化 ILA IP核 ila_0 ila_0 ( .clk ( sys_clk ), // input wire clk .probe0 ( fifo_wr_en ), // input wire [0:0] probe0 .probe1 ( fifo_rd_en ), // input wire [0:0] probe1 .probe2 ( fifo_din ), // input wire [7:0] probe2 .probe3 ( fifo_dout ), // input wire [7:0] probe3 .probe4 ( fifo_empty ), // input wire [0:0] probe4 .probe5 ( almost_empty ), // input wire [0:0] probe5 .probe6 ( fifo_full ), // input wire [0:0] probe6 .probe7 ( almost_full ), // input wire [0:0] probe7 .probe8 ( fifo_wr_data_count ), // input wire [7:0] probe8 .probe9( fifo_rd_data_count ) // input wire [7:0] probe9 ); endmodule 3 仿真

TestBench 中只要送出时钟的复位信号。

`timescale 1ns / 1ps module tb_ip_fifo( ); // Inputs reg sys_clk; reg sys_rst_n; // Instantiate the Unit Under Test (UUT) ip_fifo u_ip_fifo ( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n) ); //Genarate the clk parameter PERIOD = 20; always begin sys_clk = 1'b0; #(PERIOD/2) sys_clk = 1'b1; #(PERIOD/2); end initial begin // Initialize Inputs sys_rst_n = 0; // Wait 100 ns for global reset to finish #100 ; sys_rst_n = 1; // Add stimulus here end endmodule 总结

本文介绍FIFO IP核及读写应用。

感谢阅读,祝君成功! -by aiziyou

标签:

ZYNQ-PL实践课堂(五)IP核之FIFO由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“ZYNQ-PL实践课堂(五)IP核之FIFO