当前位置: 首页 > article >正文

ZYNQ_project:test_fifo_255X8

首先,这个vivado的fifo和quartus有很大不同。

用BRAM来实现异步fifo。

vivado的fifo有复位,在时钟信号稳定后,复位至少三个时钟周期(读写端口的慢时钟),复位完成后30个时钟周期后再进行写操作(慢时钟)。

有两个模式:标准模式和预读模式。

标准模式,读出的数据会比读使能延后一个时钟周期,fifo的深度也会比配置的少一个。

预读模式,读出的数据会与读使能同步,深度会比配置的多一个。

犯下的错误:顶层模块,fifo的复位接到了系统复位上。

没有认真阅读正点原子开发指南,忽略了深度的问题。

模块框图:

时序图:

 

代码:

module  fifo_wr_ctrl(
    input       wire                sys_clk     , // clk_wr // 50Mhz
    input       wire                sys_rst_n   ,

    output      wire                rst_fifo    ,
    output      wire                wr_clk      ,
    output      wire    [7:0]       wr_din      ,
    output      reg                 wr_en       
);
    // parameter    
    parameter   RST_FIFO_CNT = 3    ,
                RST_WAIT_CNT = 30   ,
                DATA_IN_CNT  = 200  ; // 设置深度256,但实际深度只有255.写进数据0~254
    // localparam
    localparam  RST         = 4'b0001 ,
                RST_WAIT    = 4'b0010 ,
                DATA_IN_S   = 4'b0100 ,
                FINISH_S    = 4'b1000 ;
    // reg signal define
    reg     [7:0]       cnt_core    ;
    reg                 finish      ;
    reg     [3:0]       state       ;
    // wire signal define
    wire                rst_flag        ;
    wire                wait_flag       ;
    wire                data_over_flag  ;

    // reg     [7:0]       cnt_core    ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_core <= 8'd0 ;
        else if(rst_flag || wait_flag || data_over_flag || finish)
            cnt_core <= 8'd0 ;
        else 
            cnt_core <= cnt_core + 1'b1 ;
    end
    // reg                 finish          ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            finish <= 1'b0 ;
        else if(data_over_flag)
            finish <= 1'b1 ;
        else 
            finish <= finish ;
    end
    // reg     [3:0]       state       ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            state <= 4'b0001 ;
        else 
        case (state)
        RST         :   if(rst_flag)
                            state <= RST_WAIT ;
                        else 
                            state <= RST ;
        RST_WAIT    :   if(wait_flag)
                            state <= DATA_IN_S ;
                        else 
                            state <= RST_WAIT ;
        DATA_IN_S   :   if(data_over_flag)
                            state <= FINISH_S ;
                        else 
                            state <= DATA_IN_S ;
        FINISH_S    :   state <= FINISH_S ;
        default     :   state <= RST ;
        endcase
    end
    // wire                rst_flag        ;
    assign  rst_flag  = ((cnt_core == (RST_FIFO_CNT - 1)) && (state == RST)) ;
    // wire                wait_flag       ;
    assign  wait_flag = ((cnt_core == (RST_WAIT_CNT - 1)) && (state == RST_WAIT)) ;
    // wire                data_over_flag  ;
    assign  data_over_flag = ((cnt_core == (DATA_IN_CNT - 1)) && (state == DATA_IN_S)) ;
    // output      reg                 rst_fifo    ,
    // always @(posedge sys_clk or negedge sys_rst_n) begin
    //     if(~sys_rst_n) 
    //         rst_fifo <= 1'b1 ;
    //     else if(state == RST && rst_flag)
    //         rst_fifo <= 1'b1 ;
    //     else if(state == RST)
    //         rst_fifo <= 1'b0 ;
    //     else 
    //         rst_fifo <= 1'b1 ;  
    // end
    assign  rst_fifo = (state == RST) ? 1'b1 : 1'b0 ;
    // output      wire                wr_clk      ,
    assign  wr_clk = (sys_rst_n) ? sys_clk : 1'b0  ;
    // output      wire    [7:0]       wr_din      ,
    assign  wr_din = (state == DATA_IN_S) ? cnt_core : 8'd0 ;
    // output      reg                 wr_en       ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            wr_en <= 1'b0 ;
        else if(wait_flag || data_over_flag)
            wr_en <= ~wr_en ;
        else 
            wr_en <= wr_en ;
    end
    
endmodule
module  fifo_rd_ctrl(
    input       wire            sys_clk     ,// clk_rd
    input       wire            sys_rst_n   ,
    input       wire            wr_full     ,
    input       wire            almost_empty,// 将要读空

    output      reg             rd_en       ,
    output      wire            rd_clk      
);

    assign  rd_clk = (sys_rst_n) ? sys_clk : 1'b0 ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            rd_en <= 1'b0 ;
        else if(almost_empty) // 将要读空后拉低读使能。因为是时序逻辑,应该正好读空fifo
            rd_en <= 1'b0 ;
        else if(wr_full) // 写满后拉高写使能
            rd_en <= 1'b1 ;
        else 
            rd_en <= rd_en ;
    end
endmodule
module top(
    input       wire            sys_clk     ,
    input       wire            sys_rst_n   ,

    output      wire    [7:0]   data_out    
);
    // 例化间连线
	wire				clk_100Mhz	;
	wire				clk_50Mhz	;
	wire  				locked		;
	wire  				rst_n 		;

	wire                rst_fifo    ; // fifo的复位信号
	wire                wr_clk      ; // 写端口相关信号
	wire    [7:0]       wr_din      ; // 写端口相关信号
	wire                wr_en       ; // 写端口相关信号

    wire      [7:0]     dout		;
    wire                full		;
    wire                almost_full	;
    wire                empty		;
    wire                almost_empty;
    wire      [7:0]     rd_data_count;
    wire      [7:0]     wr_data_count;
    wire                wr_rst_busy	;
    wire                rd_rst_busy	;

	wire            	rd_en       ;
	wire            	rd_clk      ;

mmcm_100M_50M mmcm_100M_50M_inst (
	.resetn				( sys_rst_n 	) ,
	.clk_in1			( sys_clk 		) ,

	.clk_out1			( clk_100Mhz 	) ,
	.clk_out2			( clk_50Mhz  	) ,
	.locked				( locked	 	) 
);
	assign 	rst_n = sys_rst_n && locked ;

fifo_wr_ctrl fifo_wr_ctrl_inst(
    .sys_clk     		( clk_50Mhz 	) , // clk_wr // 50Mhz
    .sys_rst_n   		( rst_n     	) ,

    .rst_fifo    		( rst_fifo  	) ,
    .wr_clk      		( wr_clk    	) ,
    .wr_din      		( wr_din    	) ,
    .wr_en      		( wr_en     	) 
);

fifo_rd_ctrl fifo_rd_ctrl_inst(
    .sys_clk     		( clk_100Mhz 	) ,// clk_rd
    .sys_rst_n   		( rst_n 		) ,
    .wr_full     		( full 			) ,
    .almost_empty		( almost_empty  ) ,// 将要读空

    .rd_en       		( rd_en    		) ,
    .rd_clk     		( rd_clk   		)  
);

fifo_256X8 fifo_256X8_inst(
	.rst				( rst_fifo 		) ,  // 在fpga配置完成后,fifo必须要进行复位操作�?�复位信号至少保�?3个时钟周期以慢时钟为准�?�复位完成后至少经过30个时钟周期后,才能进行数据写操作�?
	.wr_clk				( wr_clk 		) ,  // 写数据时�?50Mhz // 复位高有效�??
	.rd_clk				( rd_clk 		) ,  // 读数据时�?100Mhz
	.din				( wr_din 		) ,  // 写入数据

	.wr_en				( wr_en 		) ,  // 写使�?
	.rd_en				( rd_en 		) ,  // 读使�?
	
	.dout				( data_out 		) ,  // 输出数据
	.full				( full			) ,  // 写满
	.almost_full		( almost_full	) ,  // 将写�?
	.empty				( empty			) ,  // 读空
	.almost_empty		( almost_empty	) ,  // 将读�?
	.rd_data_count		( rd_data_count	) ,  // 可读数据
	.wr_data_count		( wr_data_count	) ,  // 已写数据
	.wr_rst_busy		( wr_rst_busy	) ,  // 写复位忙�?
	.rd_rst_busy		( rd_rst_busy	)    // 读复位忙�?
); 

endmodule

 

`timescale 1ns/1ns
module  test_top();
    reg             sys_clk     ;
    reg             sys_rst_n   ;
    wire    [7:0]   data_out    ;


top top_inst(
    .sys_clk            ( sys_clk   ) ,
    .sys_rst_n          ( sys_rst_n ) ,

    .data_out           ( data_out  )  
);
    parameter CYCLE = 20 ;
    initial begin
        sys_clk = 1'b1 ;
        sys_rst_n <= 1'b0 ;
        #( CYCLE * 5) ;
        sys_rst_n <= 1'b1 ;
        #(3000*CYCLE) ;
        $stop;
    end
    always #(CYCLE/2) sys_clk = ~sys_clk ;
endmodule

 

仿真图:


http://www.kler.cn/a/134466.html

相关文章:

  • golang如何实现sse
  • WebSocket和HTTP协议的性能比较与选择
  • 俏美韵从心出发,与女性一道为健康生活贡献力量
  • 知识库管理系统:企业数字化转型的加速器
  • 带你掌握springboot集成SpringSecurity安全框架
  • group_concat配置影响程序出bug
  • 人工智能:科技的魔术师
  • Ultipa Transporter V4.3.22 即将发布,解锁更多易用功能!
  • 智慧环保:科技驱动下的环境保护新篇章
  • 概念理论类: TCP/IP、Http、Socket之间的区别
  • axios的原理及实现一个简易版axios
  • 基于 gin + websocket 即时通讯项目 (一、项目初始化)
  • SpringCloudAlibaba系列之Nacos服务注册与发现
  • 十倍增量的海外客户开发新方式来了!外贸企业可直接照做
  • 【ELK01】ELK简介以及ElasticSearch安装、ES客户端工具-Head安装、报错问题整理
  • 6 个问题搞懂 HTTPS 加密通信的原理与 HTTPS 通信安全协议
  • JPA整合Sqlite解决Dialect报错问题, 最新版Hibernate6
  • Spring cloud负载均衡@LoadBalanced LoadBalancerClient
  • “我们把最扎心的话,说给了自己最亲近的人” 何解?| IDCF
  • 多标签页之间的通信
  • GoLong的学习之路,进阶,标准库之并发(context)补充并发三部曲,你真的明白context吗?
  • 【深度学习】吴恩达课程笔记(五)——超参数调试、batch norm、Softmax 回归
  • 基于C#实现字符串相似度
  • 【PostgreSQL】日期操作
  • 邦芒支招:求职自荐的五条技巧
  • 如何为视频添加旁白,有哪些操作技巧?