首先,这个vivado的fifo和quartus有很大不同。
用BRAM来实现异步fifo。
vivado的fifo有复位,在时钟信号稳定后,复位至少三个时钟周期(读写端口的慢时钟),复位完成后30个时钟周期后再进行写操作(慢时钟)。
有两个模式:标准模式和预读模式。
标准模式,读出的数据会比读使能延后一个时钟周期,fifo的深度也会比配置的少一个。
预读模式,读出的数据会与读使能同步,深度会比配置的多一个。
犯下的错误:顶层模块,fifo的复位接到了系统复位上。
没有认真阅读正点原子开发指南,忽略了深度的问题。
模块框图:
时序图:
代码:
module fifo_wr_ctrl(input wire sys_clk , // clk_wr // 50Mhzinput 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// localparamlocalparam RST = 4'b0001 ,RST_WAIT = 4'b0010 ,DATA_IN_S = 4'b0100 ,FINISH_S = 4'b1000 ;// reg signal definereg [7:0] cnt_core ;reg finish ;reg [3:0] state ;// wire signal definewire rst_flag ;wire wait_flag ;wire data_over_flag ;// reg [7:0] cnt_core ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~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) beginif(~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) beginif(~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 ;endcaseend// 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 ; // endassign 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) beginif(~sys_rst_n) wr_en <= 1'b0 ;else if(wait_flag || data_over_flag)wr_en <= ~wr_en ;else wr_en <= wr_en ;endendmodule
module fifo_rd_ctrl(input wire sys_clk ,// clk_rdinput 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) beginif(~sys_rst_n) rd_en <= 1'b0 ;else if(almost_empty) // 将要读空后拉低读使能。因为是时序逻辑,应该正好读空fiford_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 beginsys_clk = 1'b1 ;sys_rst_n <= 1'b0 ;#( CYCLE * 5) ;sys_rst_n <= 1'b1 ;#(3000*CYCLE) ;$stop;endalways #(CYCLE/2) sys_clk = ~sys_clk ;
endmodule