1090|2

845

帖子

3

TA的资源

版主

楼主
 

06、国产FPGA 正点原子DFPGL22G开发板测评【学习篇】IP核FIFO [复制链接]

 

1、简介

    根据 FIFO 工作的时钟域,可以将 FIFO 分为同步 FIFO 和异步 FIFO。同步 FIFO 是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作。异步 FIFO 是指读写时钟不一致,读写时钟是互相独立的。

2、实验任务

    本节的实验任务是使用 Pango 生成 FIFO IP 核,并实现以下功能: 当 FIFO 为空时,向 FIFO 中写入数据,写入的数据量和 FIFO 深度一致,即 FIFO 被写满;然后从 FIFO 中读出数据,直到 FIFO 被读空为止。

3、程序设计

    实验一共分为fifo IP 核、写 fifo 模块、读 fifo 模块以及顶层例化模块实现前三个模块的信号交互。

 

    顶层模块ip_fifo.v:顶层模块主要是对 FIFO IP 核、写 FIFO 模块、 读 FIFO 模块进行例化。

//****************************************Copyright (c)**********************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//-----------------------------------------------------------------------------
// File name:           ip_fifo
// Last modified Date:  2019/05/10 11:31:26
// Last Version:        V1.0
// Descriptions:        FIFO实验顶层模块
//-----------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2019/05/10 11:31:51
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------
//***************************************************************************//

module ip_fifo(
    input    sys_clk ,  // 时钟信号
    input    sys_rst_n  // 复位信号
);

//wire define
wire         fifo_wr_en         /* synthesis syn_keep=1 */;// FIFO写使能信号
wire         fifo_rd_en         /* synthesis syn_keep=1 */;// FIFO读使能信号
wire  [7:0]  fifo_din           /* synthesis syn_keep=1 */;// 写入到FIFO的数据
wire  [7:0]  fifo_dout          /* synthesis syn_keep=1 */;// 从FIFO读出的数据
wire         almost_full        /* synthesis syn_keep=1 */;// FIFO将满信号
wire         almost_empty       /* synthesis syn_keep=1 */;// FIFO将空信号
wire         fifo_full          /* synthesis syn_keep=1 */;// FIFO满信号
wire         fifo_empty         /* synthesis syn_keep=1 */;// FIFO空信号
wire  [7:0]  fifo_wr_data_count /* synthesis syn_keep=1 */;// FIFO写时钟域的数据计数
wire  [7:0]  fifo_rd_data_count /* synthesis syn_keep=1 */;// FIFO读时钟域的数据计数

//*****************************************************
//**                    main code
//*****************************************************

reg  		almost_empty_d0  ;    //almost_empty 延迟一拍
reg  		almost_empty_d1  ;    //almost_empty 延迟两拍
reg  		almost_empty_syn ;    //almost_empty 延迟三拍
                                  
reg  		almost_full_d0   ;    //almost_full 延迟一拍
reg  		almost_full_d1   ;    //almost_full 延迟两拍
reg  		almost_full_syn  ;    //almost_full 延迟三拍

//因为 almost_empty 信号是属于FIFO读时钟域的
//所以要将其同步到写时钟域中
always@( posedge sys_clk ) begin
	if( !sys_rst_n ) begin
		almost_empty_d0  <= 1'b0 ;
		almost_empty_syn <= 1'b0 ;
		almost_empty_d1  <= 1'b0 ;
	end
	else begin
		almost_empty_d0  <= almost_empty ;
		almost_empty_d1  <= almost_empty_d0 ;
		almost_empty_syn  <= almost_empty_d1 ;
	end
end

//因为 almost_full 信号是属于FIFO读时钟域的
//所以要将其同步到写时钟域中
always@( posedge sys_clk ) begin
	if( !sys_rst_n ) begin
		almost_full_d0  <= 1'b0 ;
		almost_full_syn <= 1'b0 ;
		almost_full_d1  <= 1'b0 ;
	end
	else begin
		almost_full_d0  <= almost_full ;
		almost_full_d1  <= almost_full_d0 ;
        almost_full_syn  <= almost_full_d1 ;
	end
end

fifo_generator_0 u_fifo_generator_0 (
  .wr_clk            (sys_clk           ),    // input
  .wr_rst            (~sys_rst_n        ),    // input
  .wr_en             (fifo_wr_en        ),    // input
  .wr_data           (fifo_din          ),    // input [7:0]
  .wr_full           (fifo_full         ),    // output
  .wr_water_level    (fifo_wr_data_count),    // output [8:0]
  .almost_full       (almost_full       ),    // output
  .rd_clk            (sys_clk           ),    // input
  .rd_rst            (~sys_rst_n        ),    // input
  .rd_en             (fifo_rd_en        ),    // input
  .rd_data           (fifo_dout         ),    // output [7:0]
  .rd_empty          (fifo_empty        ),    // output
  .rd_water_level    (fifo_rd_data_count),    // output [8:0]
  .almost_empty      (almost_empty      )     // output
);

//例化写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_syn ),    // fifo空信号
    .almost_full    ( almost_full_syn  )     // 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_syn ),    // fifo空信号
    .almost_full    ( almost_full_syn  )     // fifo满信号
);

endmodule 

    写 FIFO 模块 fifo_wr.v:fifo_wr 模块的核心部分是一个不断进行状态循环的小状态机,如果检测到 FIFO 为空,则先延时 10拍,这里注意,由于 FIFO 的内部信号的更新比实际的数据读/写操作有所延时,所以延时 10 拍的目的是等待 FIFO 的空/满状态信号、数据计数信号等信号的更新完毕之后再进行 FIFO 写操作,如果写满,则回到状态 0,即等待 FIFO 被读空,以进行下一轮的写操作。

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           fifo_wr
// Last modified Date:  2019/05/10 13:38:04
// Last Version:        V1.0
// Descriptions:        写FIFO模块
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2019/05/10 13:38:14
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

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  [3:0]  dly_cnt    ; //延迟计数器
//*****************************************************
//**                    main code
//*****************************************************
//向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) begin  //如果检测到FIFO将被读空
                    state <= 2'd1;        //就进入延时状态
                end 
                else
                    state <= state;
            end 
			2'd1: begin
				if(dly_cnt == 10) begin  //延时10拍
											//原因是FIFO IP核内部状态信号的更新存在延时
											//延迟10拍以等待状态信号更新完毕                   
                    dly_cnt    <= 4'd0;
					state      <= 2'd2;     //开始写操作
					fifo_wr_en <= 1'b1;     //打开写使能				
				end
				else begin
					dly_cnt <= dly_cnt + 4'd1;				
				end	
            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

    读 FIFO 模块 fifo_rd.v:读模块的代码结构与写模块几乎一样,也是使用一个不断进行状态循环的小的状态机来控制操作过程。
 

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           fifo_wr
// Last modified Date:  2019/05/10 13:38:04
// Last Version:        V1.0
// Descriptions:        读FIFO模块
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2019/05/10 13:38:14
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

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

endmodule

    TestBench文件tb_ip_fifo中只要送出时钟的复位信号即可:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/08 15:25:39
// Design Name: 
// Module Name: tb_ip_ram
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module tb_ip_fifo;

reg  grs_n;
//GTP_GRS I_GTP_GRS(
    GTP_GRS GRS_INST(
    .GRS_N (grs_n)
    );
    
    initial begin
    grs_n = 1'b0;
    #5000 grs_n = 1'b1;
    end
    
    // 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

    仿真波形:实际上仿真并没有像历程里面说的那样从0-256写入数据,而是0-128-0的方式写入和读出。

 

最新回复

使用 Pango 生成 FIFO IP 核,熟悉和能熟练使用fifo IP 核、写 fifo 模块、读 fifo 模块很重要   详情 回复 发表于 2023-2-5 22:28
点赞 关注
 
 

回复
举报

1701

帖子

0

TA的资源

五彩晶圆(初级)

沙发
 

使用 Pango 生成 FIFO IP 核,熟悉和能熟练使用fifo IP 核、写 fifo 模块、读 fifo 模块很重要

点评

fifo跨时钟域很好用。  详情 回复 发表于 2023-2-6 08:06
 
 
 

回复

845

帖子

3

TA的资源

版主

板凳
 
火辣西米秀 发表于 2023-2-5 22:28 使用 Pango 生成 FIFO IP 核,熟悉和能熟练使用fifo IP 核、写 fifo 模块、读 fifo 模块很重要

fifo跨时钟域很好用




 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表