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

仿真图:

相关推荐
风痕天际11 分钟前
ESP32-S3开发教程6:硬件定时器
单片机·嵌入式硬件·嵌入式·esp32·freertos·esp32s3
Godspeed Zhao40 分钟前
现代智能汽车中的无线技术97——NearLink(4)
stm32·单片机·汽车
z20348315202 小时前
如何用状态机解决按键状态识别问题(一)
c语言·单片机
之歆5 小时前
Heartbeat 高可用集群完全指南
单片机·嵌入式硬件
浩子智控5 小时前
提升linux串口通信实时性的编程实践
linux·单片机·嵌入式硬件
Tyrion.Mon5 小时前
5脚188数码管驱动
单片机
国科安芯20 小时前
高可靠性电源方案的高温降额设计与热管理策略——基于ASP3605的温域特性实证研究
单片机·嵌入式硬件·安全威胁分析·安全性测试
白太岁20 小时前
操作系统开发:(9) 从硬件复位到程序执行:如何编写符合硬件动作的启动文件与链接脚本
c语言·汇编·嵌入式硬件·系统架构
逻辑流20 小时前
《精准测量的起点:STM32中的电压电流有效值计算算法》
stm32·单片机·嵌入式硬件·算法
隔壁大炮21 小时前
MPU6050
stm32·单片机·嵌入式硬件