首先,这个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
