1.创建ip核。在ipcatlog那里搜索fifo,选择fifo generator
2.首先还是选择标准的接口类型,AXI4还不知道怎么用,下面注意配置成异步时钟(common clock block ram是同步的,independent clocks的是异步),异步的才可以使读跟写是不同的时钟。否则就只能是一个时钟。失去了跨时钟域传递数据的意义。
3.第一个是标准fifo第二个是第一个字在开始。这两个就相差一个周期输出数据(目前是这样的理解,biaozhunfifo会延迟一个时钟周期)/ 位宽是一位的长度,深度能存多少个数据。8位的位宽最大存的数是255.10位最大是1023。深度是能存多少个这样的数。读是根据写来推断的。读和写的位宽最好一致,不然读出来的数据会出问题。其他的暂时还没用到
4.快空快满的信号勾上,提前一个时钟周期来判断防止出现亚稳态。
5.计数,计算fifo里面还有多少个数,。如果前面读跟写设置的同时钟这里两个数应该是一样的。如果时钟不一样就不一样了(我这里读时钟是写时钟的两倍所以读的变得块),后面的summary就是fifo的设置总结了。
6.配置完FIFOip核之后就开始写代码,分为读跟写两个部分。写的时候判断快空的信号,快空的时候,将使能拉高开始写。快满的时候开始停止写数据将使能拉低。注意当复位的时候要将写使能拉高一下不然数据清空的时候就快空的信号就无法跳高了因为已经空了。
module fifo_write(
input clk,
input rst_n,
input almost_empty ,
input almost_full ,
output reg fifo_wr_en ,
output reg [9:0] fifo_wr_data
);
reg alemp_do;
reg alemp_d1;
wire alemp_flag;
assign alemp_flag=alemp_do&!alemp_d1;
always@(posedge clk or negedge rst_n)begin//判断是否为快空
if(!rst_n)begin
alemp_do<=1'b0;
alemp_d1<=1'b0;
end
else begin
alemp_do<=almost_empty;
alemp_d1<=alemp_do;
end
end
reg [3:0]cnt_dly;
reg [1:0]state;
always@(posedge clk or negedge rst_n)begin//开始赋值
if(!rst_n)begin
fifo_wr_en<=1'b1;
fifo_wr_data<=1'b0;
cnt_dly<=1'b0;
state<=1'b0;
end
else begin
case(state)
2'd0:begin
if(alemp_flag)
state<=2'd1;
else
state<=state;
end
2'd1:begin
if(cnt_dly==4'd10)begin
state<=2'd2;
cnt_dly<=1'b0;
end
else
cnt_dly<=cnt_dly+1'b1;
end
2'd2:begin
if(almost_full)begin
fifo_wr_en<=1'b0;
fifo_wr_data<=1'b0;
state<=2'd0;
end
else begin
fifo_wr_en<=1'b1;
fifo_wr_data<=fifo_wr_data+1'b1;
end
end
default: state<=2'd0;
endcase
end
end
endmodule
7.读跟写刚好相反,判断快满的信号,快满的时候,将使能拉高开始读。快空的时候延时一段时间停止读数据,并将使能拉低。
module fifo_read(
input clk,
input rst_n,
input almost_empty ,
input almost_full ,
output reg fifo_rd_en ,
input [9:0] fifo_rd_data
);
reg alful_do;
reg alful_d1;
wire alful_flag;
reg [3:0]cnt_dly;
reg [1:0]state;
assign alful_flag=alful_do&!alful_d1;
always@(posedge clk or negedge rst_n)begin//判断满了
if(!rst_n)begin
alful_do<=1'b0;
alful_d1<=1'b0;
end
else begin
alful_do<=almost_full;
alful_d1<=alful_do;
end
end
always@(posedge clk or negedge rst_n)begin//开始赋值
if(!rst_n)begin
fifo_rd_en<=1'b0;
cnt_dly<=1'b0;
state<=1'b0;
end
else begin
case(state)
2'd0:begin
if(alful_flag)
state<=2'd1;
else
state<=state;
end
2'd1:begin
if(cnt_dly==4'd10)begin
state<=2'd2;
cnt_dly<=1'b0;
end
else
cnt_dly<=cnt_dly+1'b1;
end
2'd2:begin
if(almost_empty)begin
fifo_rd_en<=1'b0;
state<=2'd0;
end
else begin
fifo_rd_en<=1'b1;
end
end
default: state<=2'd0;
endcase
end
end
endmodule
8.最后在顶层调用就行了,注意数据的位宽。定义一个时钟ip核来产生两个不同频率的时钟。
module fifo_top(
input clk,
input rst_n
);
wire [9:0] write_data;
wire [9:0] read_data;
wire [9:0] rd_data_count;
wire [9:0] wr_data_count;
wire write_en;
wire almem;
wire almful;
wire empty;
wire full;
wire read_en;
wire clk100hz;
wire clk50hz;
fifo_write fifo_write_u(
. clk (clk100hz) ,
. rst_n (rst_n) ,
. almost_empty(almem) ,
. almost_full (almful) ,
. fifo_wr_en (write_en) ,
. fifo_wr_data(write_data)
);
fifo_read fifo_read_u(
. clk (clk50hz) ,
. rst_n (rst_n) ,
. almost_empty (almem) ,
. almost_full (almful) ,
. fifo_rd_en (read_en) ,
. fifo_rd_data (read_data)
);
clk_wiz_0 clk_u(
// Clock out ports
.clk_out1(clk50hz), // output clk_out1
.clk_out2(clk100hz), // output clk_out2
// Status and control signals
.resetn(rst_n), // input resetn
// Clock in ports
.clk_in1(clk)); // input clk_in1
fifo_generator_0 your_instance_name (
.wr_clk(clk100hz), // input wire wr_clk
.rd_clk(clk50hz), // input wire rd_clk
.din(write_data), // input wire [7 : 0] din
.wr_en(write_en), // input wire wr_en
.rd_en(read_en), // input wire rd_en
.dout(read_data), // output wire [7 : 0] dout
.full(full), // output wire full
.almost_full(almful), // output wire almost_full
.empty(empty), // output wire empty
.almost_empty(almem), // output wire almost_empty
.rd_data_count(rd_data_count), // output wire [7 : 0] rd_data_count
.wr_data_count(wr_data_count) // output wire [7 : 0] wr_data_count
);
ila_0 ila_u (
.clk(clk), // input wire clk
.probe0(write_en), // input wire [0:0] probe0
.probe1(read_en), // input wire [0:0] probe1
.probe2(almful), // input wire [0:0] probe2
.probe3(full), // input wire [0:0] probe3
.probe4(almem), // input wire [0:0] probe4
.probe5(empty), // input wire [0:0] probe5
.probe6(write_data), // input wire [9:0] probe6
.probe7(read_data), // input wire [9:0] probe7
.probe8(clk100hz), // input wire [0:0] probe8
.probe9(clk50hz) // input wire [0:0] probe9
);
endmodule
可以看到读确实比写要快一倍