FIFO,First In First Out ,是一种先进先出的数据缓存器。
没有外部读写地址线,只能顺序写入数据,顺序的读出数据, 其数据地址由内部读写指针自动加1完成。
不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
FIFO一般用于不同时钟域之间的数据传输,根据工作的时钟域,分为同步FIFO和异步FIFO。
同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。
异步FIFO是指读写时钟不一致,读写时钟是互相独立的。
同步FIFO
1 `timescale 1ns / 1ps 2 ////////////////////////////////////////////////////////////////////////////////// 3 // Company: 4 // Engineer: 5 // 6 // Create Date: 2018/05/02 21:34:02 7 // Design Name: 8 // Module Name: FIFO_16bits_16 9 // Project Name: 10 // Target Devices: 11 // Tool Versions: 12 // Description: synchronous fifo 16bits * 16 13 // 14 // Dependencies: 15 // 16 // Revision: 17 // Revision 0.01 - File Created 18 // Additional Comments: 19 // 20 ////////////////////////////////////////////////////////////////////////////////// 21 `define ADDR_WIDTH 4 //ADDR WIDTH = 4, 22 `define FIFO_DEPTH 16 //FIFO DEPTH 23 `define FIFO_WIDTH 16 //FIFO WIDTH 16 BITS 24 25 module myFIFO( 26 input wire clk, 27 input wire rst_n, 28 input wire wr_en, 29 input wire rd_en, //wire write/read enable 30 input wire [`FIFO_WIDTH:0] buf_in, // data input to be pushed to buffer 31 output reg [`FIFO_WIDTH:0] buf_out, // port to output the data using pop. 32 output wire buf_empty, 33 output wire buf_full, // fifo buffer empty/full indication 34 output reg [`ADDR_WIDTH:0] fifo_cnt // number of data pushed in to buffer,16-> FULL;0-> EMPTY 35 ); 36 37 reg [`ADDR_WIDTH-1:0] rd_ptr,wr_ptr; //ADDR PTR .INDEX ,CYCLE 0->15->0->15 38 reg [`FIFO_WIDTH:0] buf_mem[0:`FIFO_DEPTH-1]; 39 reg rst_nr; 40 //juge full/empty 41 assign buf_empty = (fifo_cnt == 0)?1:0; 42 assign buf_full = (fifo_cnt == `FIFO_DEPTH)?1:0; 43 //Asynchronous reset,synch release 44 // always @(posedge clk)begin 45 // rst_nr <= rst_n; 46 // end 47 //FIFO_CNT 48 always @(posedge clk or negedge rst_n)begin 49 if(!rst_n) 50 fifo_cnt <= 0; 51 else if((!buf_full&&wr_en)&&(!buf_empty&&rd_en)) //WRTITE & READ ,HOLD 52 fifo_cnt <= fifo_cnt; 53 else if(!buf_full && wr_en) //WRITE-> +1 54 fifo_cnt <= fifo_cnt + 1; 55 else if(!buf_empty && rd_en) //READ -> -1 56 fifo_cnt <= fifo_cnt-1; 57 else 58 fifo_cnt <= fifo_cnt; 59 end 60 //READ 61 always @(posedge clk or negedge rst_n) begin 62 if(!rst_n) 63 buf_out <= 0; 64 if(rd_en && !buf_empty) 65 buf_out <= buf_mem[rd_ptr]; 66 end 67 //WRITE 68 always @(posedge clk) begin 69 if(wr_en && !buf_full) 70 buf_mem[wr_ptr] <= buf_in; 71 end 72 //wr_ptr & rd_ptr ,ADDR PTR 73 always @(posedge clk or negedge rst_n) begin 74 if(!rst_n) begin 75 wr_ptr <= 0; 76 rd_ptr <= 0; 77 end 78 else begin 79 if(!buf_full && wr_en) 80 wr_ptr <= wr_ptr + 1; 81 if(!buf_empty && rd_en) 82 rd_ptr <= rd_ptr + 1; 83 end 84 end 85 86 endmodule
testbench
1 `timescale 1ns / 1ps 2 ////////////////////////////////////////////////////////////////////////////////// 3 // Company: 4 // Engineer: 5 // 6 // Create Date: 2018/05/02 21:42:06 7 // Design Name: 8 // Module Name: tb 9 // Project Name: 10 // Target Devices: 11 // Tool Versions: 12 // Description: 13 // 14 // Dependencies: 15 // 16 // Revision: 17 // Revision 0.01 - File Created 18 // Additional Comments: 19 // 20 ////////////////////////////////////////////////////////////////////////////////// 21 `define ADDR_WIDTH 4 //ADDR WIDTH = 4, 22 `define BUF_DEPTH 16 //FIFO DEPTH 23 `define FIFO_WIDTH 16 //FIFO WIDTH 16 BITS 24 25 module tb; 26 reg clk,rst_n; 27 reg wr_en,rd_en; 28 reg [15:0] buf_in; // data input to be pushed to buffer 29 wire [15:0] buf_out; // port to output the data using pop. 30 wire buf_empty,buf_full; // buffer empty and full indication 31 wire [`ADDR_WIDTH-1:0] fifo_cnt; // number of data pushed in to buffer 32 33 myFIFO dut( 34 .clk(clk), 35 .rst_n(rst_n), 36 .buf_in(buf_in), 37 .buf_out(buf_out), 38 .wr_en(wr_en), 39 .rd_en(rd_en), 40 .buf_empty(buf_empty), 41 .buf_full(buf_full), 42 .fifo_cnt(fifo_cnt) 43 ); 44 45 always #10 clk = ~clk; 46 47 reg [15:0] tempdata = 0; 48 initial begin 49 clk = 0; 50 rst_n = 0; 51 wr_en = 0; 52 rd_en = 0; 53 buf_in = 0; 54 #15; 55 rst_n = 1; 56 57 push(1); 58 fork 59 push(2); 60 pop(tempdata); 61 join //push and pop together 62 push(10); 63 push(20); 64 push(30); 65 push(40); 66 push(50); 67 push(60); 68 push(70); 69 push(80); 70 push(90); 71 push(100); 72 push(110); 73 push(120); 74 push(130); 75 push(140); 76 push(150); 77 push(160); 78 push(170); 79 push(180); 80 push(190); 81 82 pop(tempdata); 83 push(tempdata); 84 85 pop(tempdata); 86 pop(tempdata); 87 pop(tempdata); 88 pop(tempdata); 89 push(200); 90 pop(tempdata); 91 push(tempdata); 92 pop(tempdata); 93 pop(tempdata); 94 pop(tempdata); 95 pop(tempdata); 96 pop(tempdata); 97 pop(tempdata); 98 pop(tempdata); 99 pop(tempdata); 100 pop(tempdata); 101 pop(tempdata); 102 pop(tempdata); 103 push(5); 104 pop(tempdata); 105 pop(tempdata); 106 pop(tempdata); 107 pop(tempdata); 108 pop(tempdata); 109 pop(tempdata); 110 pop(tempdata); 111 pop(tempdata); 112 pop(tempdata); 113 pop(tempdata); 114 pop(tempdata); 115 pop(tempdata); 116 pop(tempdata); 117 pop(tempdata); 118 pop(tempdata); 119 120 #3; 121 rst_n = 0; 122 #3; 123 rst_n = 1; 124 push(1); 125 fork 126 push(2); 127 pop(tempdata); 128 join //push and pop together 129 push(10); 130 push(20); 131 push(30); 132 pop(tempdata); 133 pop(tempdata); 134 pop(tempdata); 135 end 136 137 task push (input [7:0] data); 138 if(buf_full) 139 $display("---Cannot push %d: Buffer Full---",data); 140 else begin 141 $display("Push:%d",data); 142 buf_in = data; 143 wr_en = 1; 144 @(posedge clk); 145 #5 wr_en = 0; 146 end 147 endtask 148 149 task pop(output[7:0] data); 150 if(buf_empty) 151 $display("---Cannot Pop: Buffer Empty---"); 152 else begin 153 rd_en = 1; 154 @(posedge clk); 155 #3 rd_en = 0; 156 data = buf_out; 157 $display("------Poped:%d",data); 158 end 159 endtask 160 161 endmodule
在综合是出现错误
[Synth 8-91] ambiguous clock in event control [:61]
是因为该段没有else语句,于是将该段改为
1 //READ 2 always @(posedge clk or negedge rst_n) begin 3 if(!rst_n) 4 buf_out <= 0; 5 else begin 6 if(rd_en && !buf_empty) 7 buf_out <= buf_mem[rd_ptr]; 8 end 9 end
通过。
//********************************************************************************
异步FIFO
参考了很多文章。
直接上代码
1 `timescale 1ns / 1ps 2 ////////////////////////////////////////////////////////////////////////////////// 3 // Company: 4 // Engineer: 5 // 6 // Create Date: 2018/05/03 13:56:26 7 // Design Name: 8 // Module Name: AsyncFIFO 9 // Project Name: 10 // Target Devices: 11 // Tool Versions: 12 // Description: asynchronous fifo 13 // 14 // Dependencies: 15 // 16 // Revision: 17 // Revision 0.01 - File Created 18 // Additional Comments: 19 // 20 ////////////////////////////////////////////////////////////////////////////////// 21 22 23 module AsyncFIFO 24 #( 25 parameter fifo_width = 16, 26 parameter fifo_depth = 16, // = ((1<<addr_width) -1) 27 parameter addr_width = 4 28 ) 29 ( 30 input wire wclk, 31 input wire rclk, 32 input wire wrst_n, 33 input wire rrst_n, 34 input wire winc, 35 input wire rinc, 36 input wire [fifo_width-1:0] wdata, 37 output wire [fifo_width-1:0] rdata, 38 output reg wfull, 39 output reg rempty 40 //output reg [addr_0] fifo_cnt 41 ); 42 43 reg [addr_0] wptr,rptr; 44 reg [addr_0] rbin,wbin; 45 reg [addr_0] wq1_rptr,rq1_wptr,wq2_rptr,rq2_wptr; 46 reg [fifo_width-1:0] fifo_mem [0:fifo_depth-1]; 47 wire [addr_width-1:0] waddr,raddr; 48 wire [addr_0] rgraynext,rbinnext,wgraynext,wbinnext; 49 wire rempty_val,wfull_val; 50 //snyc wptr 51 always @(posedge wclk or negedge wrst_n) 52 if(!wrst_n) begin 53 {wq2_rptr,wq1_rptr} <= 0; 54 end 55 else begin 56 {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr}; 57 end 58 //snyc rptr 59 always @(posedge wclk or negedge wrst_n) 60 if (!wrst_n) begin 61 {rq2_wptr,rq1_wptr} <= 0; 62 end 63 else begin 64 {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr}; 65 end 66 //dualRAM 67 assign rdata = fifo_mem[raddr]; 68 always@(posedge wclk) 69 if (winc && !wfull) fifo_mem[waddr] <= wdata; 70 //------------------------rempty & raddr---------------------------- 71 always @(posedge rclk or negedge rrst_n) // GRAYSTYLE-2 pointer 72 if (!rrst_n) {rbin, rptr} <= 0; 73 else {rbin, rptr} <= {rbinnext, rgraynext}; 74 // Memory read-address pointer (okay to use binary to address memory) 75 assign raddr = rbin[addr_width-1:0]; 76 assign rbinnext = rbin + (rinc & ~rempty); 77 assign rgraynext = (rbinnext>>1) ^ rbinnext;//binary to gray 78 // FIFO empty when the next rptr == synchronized wptr or on reset 79 assign rempty_val = (rgraynext == rq2_wptr)?1:0; 80 always @(posedge rclk or negedge rrst_n) 81 if (!rrst_n) rempty <= 1'b1; 82 else rempty <= rempty_val; 83 //-----------------------wfull & waddr------------------------------ 84 always @(posedge wclk or negedge wrst_n) // GRAYSTYLE2 pointer 85 if (!wrst_n) {wbin, wptr} <= 0; 86 else {wbin, wptr} <= {wbinnext, wgraynext}; 87 // Memory write-address pointer (okay to use binary to address memory) 88 assign waddr = wbin[addr_width-1:0]; 89 assign wbinnext = wbin + (winc & ~wfull); 90 assign wgraynext = (wbinnext>>1) ^ wbinnext; 91 //------------------------------------------------------------------ 92 // Simplified version of the three necessary full-tests: 93 // assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) && 94 // (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) && 95 // (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0])); 96 //------------------------------------------------------------------ 97 assign wfull_val = (wgraynext=={~wq2_rptr[addr_addr_width-1], wq2_rptr[addr_width-2:0]}); 98 always @(posedge wclk or negedge wrst_n) 99 if (!wrst_n) wfull <= 1'b0; 100 else wfull <= wfull_val; 101 102 endmodule
测试程序
1 `timescale 1ns / 1ps 2 ////////////////////////////////////////////////////////////////////////////////// 3 // Company: 4 // Engineer: 5 // 6 // Create Date: 2018/05/03 16:53:39 7 // Design Name: 8 // Module Name: tb 9 // Project Name: 10 // Target Devices: 11 // Tool Versions: 12 // Description: 13 // 14 // Dependencies: 15 // 16 // Revision: 17 // Revision 0.01 - File Created 18 // Additional Comments: 19 // 20 ////////////////////////////////////////////////////////////////////////////////// 21 22 23 module tb; 24 // parameter fifo_width = 16; 25 // parameter fifo_depth = 16; 26 // parameter addr_width = 4; 27 28 reg wclk,rclk,wrst_n,rrst_n; 29 reg winc,rinc; 30 reg [15:0] wdata; 31 wire [15:0] rdata; 32 wire rempty,wfull; 33 34 35 36 AsyncFIFO i1( 37 .wclk(wclk), 38 .rclk(rclk), 39 .wrst_n(wrst_n), 40 .rrst_n(rrst_n), 41 .winc(winc), 42 .rinc(rinc), 43 .wdata(wdata), 44 .rdata(rdata), 45 .wfull(wfull), 46 .rempty(rempty) 47 ); 48 always #20 wclk = ~wclk; 49 always #10 rclk = ~rclk; 50 51 reg [15:0] tempdata; 52 reg [15:0] data1; 53 reg [15:0] data2; 54 initial begin 55 wclk = 0; 56 rclk = 0; 57 wrst_n = 0; 58 rrst_n = 0; 59 winc = 0; 60 rinc = 0; 61 wdata = 0; 62 data1 = 0; 63 64 #15 65 fork 66 wrst_n = 1; 67 rrst_n = 1; 68 join 69 #5 70 push(3); 71 push(2); 72 push(1); 73 push(0); 74 #20 75 //pop(tempdata); 76 //push and pop together 77 while(1)begin 78 fork 79 wr; 80 rd; 81 join 82 end 83 push(10); 84 push(20); 85 push(30); 86 push(40); 87 push(50); 88 89 end 90 91 task wr;begin 92 while(!wfull)begin 93 push(data1); 94 data1 =data1+3; 95 end 96 end 97 endtask 98 99 task rd;begin 100 while(!rempty) 101 #15 pop(tempdata); 102 103 end 104 endtask 105 106 task push (input [15:0] data); 107 if(wfull) 108 $display("---Cannot push %d: Buffer Full---",data); 109 else begin 110 $display("Push:%d",data); 111 wdata = data; 112 winc = 1; 113 @(posedge wclk); 114 #5 winc = 0; 115 end 116 endtask 117 118 task pop(output[15:0] data); 119 if(rempty) 120 $display("---Cannot Pop: Buffer Empty---"); 121 else begin 122 rinc = 1; 123 @(posedge rclk); 124 #3 rinc = 0; 125 data = rdata; 126 $display("------Poped:%d",data); 127 end 128 endtask 129 130 131 endmodule
测试算是通过,但还是有点问题。相同再弄了。