FIFO的英文全称是First In First Out,即先进先出,常用于跨时钟域信号传递。根据工作的时钟域可分为:同步FIFO和异步FIFO。
FIFO常见参数
FIFO的宽度:FIFO一次读写操作的数据位宽。
FIFO的深度:FIFO可以存储多少个宽度为N的数据(假设位宽为N)。
一.同步FIFO ip核
1. 实验内容:创建同步FIFO ip核,实现写入0-2047个数据,然后再将写入数据读出。
2. 工程代码:
syn_fifo顶层
1 `timescale 1ns / 1ps
2
3 //------fifo深度为2048*16------//
4 module syn_fifo(
5
6 input sys_clk ,
7 input rst ,
8 input [15:0] data_in ,
9 input wr_en ,
10 input rd_en ,
11
12 output [15:0] data_out,
13 output full ,
14 output empty ,
15 output [10:0] data_count
16 );
17
18
19 synchronous_fifo u_synchronous_fifo (
20 .clk(sys_clk), // input wire clk
21 .srst(rst), // input wire srst
22 .din(data_in), // input wire [15 : 0] din
23 .wr_en(wr_en), // input wire wr_en
24 .rd_en(rd_en), // input wire rd_en
25 .dout(data_out), // output wire [15 : 0] dout
26 .full(full), // output wire full
27 .empty(empty), // output wire empty
28 .data_count(data_count) // output wire [10 : 0] data_count
29 );
30
31 endmodule
3.仿真代码:
syn_fifo_tb
1 `timescale 1ns / 1ps
2
3 module syn_fifo_tb();
4 //------端口例化------//
5 //reg类型
6 reg sys_clk ;
7 reg rst ;
8 reg [15:0] data_in ;
9 reg wr_en ;
10 reg rd_en ;
11
12 //wire类型
13 wire [15:0] data_out;
14 wire full ;
15 wire empty ;
16 wire [10:0] data_count;
17
18 //------系统初始化------//
19 initial
20 begin
21 sys_clk = 1'b1;
22 rst = 1'b1;
23 #100
24 rst = 1'b0;
25 end
26
27 //模拟系统时钟产生,50MHz
28 always #10 sys_clk <= ~sys_clk;
29
30 //--------mian-------//
31 //wr_en:写使能信号,每两个时钟周期产生一个写使能信号
32 always @(posedge sys_clk or posedge rst)
33 begin
34 if(rst)
35 wr_en <= 1'b0;
36 else if(!rd_en)
37 wr_en <= 1'b1;
38 else
39 wr_en <= 1'b0;
40 end
41
42
43 //data_in:输入数据产生
44 always @(posedge sys_clk or posedge rst)
45 begin
46 if(rst)
47 data_in <= 16'd0;
48 else if((data_in == 16'd2047) && wr_en)
49 data_in <= 16'd0;
50 else if(!full && wr_en)
51 data_in <= data_in + 1'b1;
52 else
53 data_in <= data_in;
54 end
55
56 //rd_en:读使能信号
57 always @(posedge sys_clk or posedge rst)
58 begin
59 if(rst)
60 rd_en <= 1'b0;
61 else if(full)
62 rd_en <= 1'b1;
63 else if(empty)
64 rd_en <= 1'b0;
65 else
66 rd_en <= rd_en;
67 end
68
69 syn_fifo u_syn_fifo(
70
71 .sys_clk(sys_clk),
72 .rst(rst),
73 .data_in(data_in),
74 .wr_en(wr_en),
75 .rd_en(rd_en),
76
77 .data_out(data_out),
78 .full(full),
79 .empty(empty),
80 .data_count(data_count)
81 );
82
83 endmodule
4.仿真结果
仿真结果显示,数据0-2047数据写入FIFO后,FIFO的full拉高,同时wr_en拉低rd_en拉高,开始读出FIFO中数据。
由于FIFO是先进先出,data_out输出数据为0-2047。
二.异步FIFO ip核
1.实验内容:当FIFO为空时,往FIFO写入数据,直至写满;当FIFO满时,将数据读出,直至读空。FIFO写时钟速率为50MHz, FIFO读时钟速率为100MHz。
2.工程代码
顶层asyn_fifo_top:
1 `timescale 1ns / 1ps
2 module asyn_fifo_top(
3
4 input sys_clk, //系统输入50MHz
5 input rst
6 );
7
8 wire [10:0] wr_data_count;
9 wire [11:0] rd_data_count;
10
11 wire clk_50M;
12 wire clk_25M;
13
14 wire [7:0] rd_data;
15 wire [15:0] wr_data;
16
17
18 clk_wiz_0 u_clk_wiz_0(
19 .clk_out1(clk_50M), // output clk_50M
20 .clk_out2(clk_25M), // output clk_25M
21 .reset(1'b0), // input reset
22 .locked(locked), // output locked
23 .clk_in1(sys_clk) // input clk_in1
24 );
25
26 fifo_wr u_fifo_wr(
27
28 .wrclk(clk_25M),
29 .rst(rst),
30 .full(almost_full),
31 .empty(almost_empty),
32 .wr_en(wr_en),
33 .wr_data(wr_data)
34 );
35
36 fifo_rd u_fifo_rd(
37 .rdclk(clk_50M),
38 .rst(rst),
39 .full(almost_full),
40 .empty(almost_empty),
41 .rd_data(rd_data),
42 .rd_en(rd_en)
43 );
44
45 fifo_generator_0 u_fifo_generator_0(
46 .rst(rst), // input wire rst
47 .wr_clk(clk_25M), // input wire wr_clk
48 .rd_clk(clk_50M), // input wire rd_clk
49 .din(wr_data), // input wire [15 : 0] din
50 .wr_en(wr_en), // input wire wr_en
51 .rd_en(rd_en), // input wire rd_en
52 .dout(rd_data), // output wire [7 : 0] dout
53 .full(full), // output wire full
54 .almost_full(almost_full), // output wire almost_full
55 .wr_ack(wr_ack), // output wire wr_ack
56 .empty(empty), // output wire empty
57 .almost_empty(almost_empty), // output wire almost_empty
58 .valid(valid), // output wire valid
59 .rd_data_count(rd_data_count), // output wire [11 : 0]
60 .wr_data_count(wr_data_count) // output wire [10 : 0]
61 );
62
63 endmodule
写模块fifo_wr:
1 `timescale 1ns / 1ps
2 module fifo_wr(
3
4 input wrclk,
5 input rst,
6
7 input full,
8 input empty,
9
10 output reg wr_en,
11 output reg [15:0] wr_data
12 );
13
14 parameter IDLE = 2'b01;
15 parameter WR_STATE= 2'b10;
16
17 reg [1:0] state;
18 reg empty_r1;
19 reg empty_r2;
20 wire wr_start;
21
22 assign wr_start = !empty_r2 & empty_r1; //写开始信号
23 always @(posedge wrclk or posedge rst)
24 begin
25 if(rst)
26 begin
27 empty_r1 <= 1'b0;
28 empty_r2 <= 1'b0;
29 end
30 else
31 begin
32 empty_r1 <= empty;
33 empty_r2 <= empty_r1;
34 end
35 end
36
37 //向FIFO中写入数据
38 always @(posedge wrclk or posedge rst)
39 begin
40 if(rst)
41 begin
42 wr_en <= 1'b0;
43 wr_data <= 16'd0;
44 state <= IDLE;
45 end
46 else
47 begin
48 case(state)
49 IDLE:
50 begin
51 if(wr_start)
52 state <= WR_STATE;
53 else
54 state <= state;
55 end
56
57 WR_STATE:
58 begin
59 if(full)
60 begin
61 wr_en <= 1'b0;
62 wr_data <= 16'd0;
63 state <= IDLE;
64 end
65 else
66 begin
67 wr_en <= 1'b1;
68 wr_data <= wr_data + 1'b1;
69 state <= state;
70 end
71 end
72
73 default: state <= IDLE;
74
75 endcase
76 end
77 end
78
79 endmodule
读模块fifo_rd:
1 `timescale 1ns / 1ps
2 module fifo_rd(
3
4 input rdclk,
5 input rst,
6
7 input full,
8 input empty,
9 input [7:0] rd_data,
10
11 output reg rd_en
12
13 );
14 parameter IDLE = 2'b01;
15 parameter RD_STATE= 2'b10;
16
17 reg [1:0] state;
18 reg [7:0] rd_data_r;
19 reg full_r1;
20 reg full_r2;
21
22 wire rd_start;
23
24 assign rd_start = !full_r2 & full_r1;
25 always @(posedge rdclk or posedge rst)
26 begin
27 if(rst)
28 begin
29 full_r1 <= 1'b0;
30 full_r2 <= 1'b0;
31 end
32 else
33 begin
34 full_r1 <= full;
35 full_r2 <= full_r1;
36 end
37 end
38
39 //读FIFO中数据
40 always @(posedge rdclk or posedge rst)
41 begin
42 if(rst)
43 begin
44 rd_en <= 1'b0;
45 state <= IDLE;
46 end
47 else
48 begin
49 case(state)
50 IDLE:
51 begin
52 if(rd_start)
53 state <= RD_STATE;
54 else
55 state <= state;
56 end
57
58 RD_STATE:
59 begin
60 if(empty)
61 begin
62 rd_en <= 1'b0;
63 state <= IDLE;
64 end
65 else
66 rd_en <= 1'b1;
67 end
68
69 default: state <= IDLE;
70
71 endcase
72 end
73 end
74
75 //rd_data_r:寄存FIFO中读出的数据
76 always @(posedge rdclk or posedge rst)
77 begin
78 if(rst)
79 rd_data_r <= 16'd0;
80 else
81 rd_data_r <= rd_data;
82 end
83
84 endmodule
3.仿真代码
1 `timescale 1ns / 1ps
2 module asyn_fifo_top_tb;
3 reg sys_clk;
4 reg rst;
5
6 initial
7 begin
8 sys_clk = 1'b1;
9 rst = 1'b1;
10 #2000
11 rst = 1'b0;
12 end
13
14 always #10 sys_clk = ~sys_clk;
15
16 asyn_fifo_top u_asyn_fifo_top(
17 .sys_clk(sys_clk), //系统输入50MHz
18 .rst(rst)
19 );
20
21 endmodule
4.仿真结果
仿真结果显示,写模块成功往FIFO中写入16bit 的1~2047 数据,读FIFO模块以8bit从FIFO中正确读出写入数据。