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

仿真图:

相关推荐
wenchm1 小时前
细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的另一种方法
stm32·单片机·嵌入式硬件
编码追梦人2 小时前
如何实现单片机的安全启动和安全固件更新
单片机
电子工程师UP学堂3 小时前
电子应用设计方案-16:智能闹钟系统方案设计
单片机·嵌入式硬件
飞凌嵌入式3 小时前
飞凌嵌入式T113-i开发板RISC-V核的实时应用方案
人工智能·嵌入式硬件·嵌入式·risc-v·飞凌嵌入式
blessing。。4 小时前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
嵌新程6 小时前
day03(单片机高级)RTOS
stm32·单片机·嵌入式硬件·freertos·rtos·u575
Lin2012306 小时前
STM32 Keil5 attribute 关键字的用法
stm32·单片机·嵌入式硬件
电工小王(全国可飞)6 小时前
STM32 RAM在Memory Map中被分为3个区域
stm32·单片机·嵌入式硬件
maxiumII6 小时前
Diving into the STM32 HAL-----DAC笔记
笔记·stm32·嵌入式硬件
北城笑笑8 小时前
FPGA 14 ,硬件开发板分类详解,FPGA开发板与普通开发板烧录的区别
fpga开发·fpga