文章目录
FIFO乒乓操作:
乒乓操作是一个无缝的缓存高速数据流的操作,多用于两个单口RAM,可以做到没有数据丢失的高速数据流处理,再FPGA中乒乓操作可以说是它的优势之一
乒乓操作原理:
就是打乒乓球一样,一个球(数据流),两个拍子(缓存),两个拍子相互击球(轮流读写数据,写1读2,写2读1)这样就可以做到球不停一直移动(数据流不会停,数据无丢失)。
在低速处理高速数据流时,可以使用乒乓操作,举个栗子,10M的数据流,用乒乓操作,分流成两个FIFO,一个FIFO的吞吐速度只有原来的一半5M,就可以满足低速的处理方法,处理高速的数据,处理后在用合并成一个10M的数据流,数据就被不丢失且高速的处理过了,top层看起就是10M的处理速度了,(也是经典的FPGA面积换速度的方法之一)。
下面是代码,用的vivado平台的ip:
`timescale 1ns / 1ps
module FIFO_pp(
input clk,
input _rst,
input [7:0] data_in,
output [7:0] data_out
);
reg wr_en_1 = 'd0;
reg rd_en_1 = 'd0;
wire full_1;
wire empty_1;
wire [7:0] dout_1;
reg [7:0] in_1 = 'd0;
reg delay1 = 'd0;
reg delay2 = 'd0;
reg wr_en_2 = 'd0;
reg rd_en_2 = 'd0;
wire full_2;
wire empty_2;
wire [7:0] dout_2;
reg [7:0] in_2 = 'd0;
// reg [7:0] out_111 = 'd0;
// reg [7:0] out_222 = 'd0;
reg [7:0] out = 'd0;
reg [12:0] cnt = 'd0;
fifo_generator_0 fifo_1(
.clk(clk),
.srst(~_rst),
.din(in_1),
.full(full_1),
.prog_full(),
.wr_en(wr_en_1),
.empty(empty_1),
.prog_empty(),
.dout(dout_1),
.rd_en(rd_en_1)
);
fifo_generator_0 fifo_2(
.clk(clk),
.srst(~_rst),
.din(in_2),
.full(full_2),
.prog_full(),
.wr_en(wr_en_2),
.empty(empty_2),
.prog_empty(),
.dout(dout_2),
.rd_en(rd_en_2)
);
reg [2:0] status_c = 'd0 ;
reg [2:0] status_n = 'd0 ;
reg [2:0] stand = 'b000;
reg [2:0] ready = 'b111;
reg [2:0] w1_2kong = 'b101;
reg [2:0] w1_r2 = 'd001;
reg [2:0] w2_r1 = 'd010;
always @(posedge clk or negedge _rst) begin
if (!_rst) begin
status_n <= ready;
end
else begin
status_c <= status_n;
end
end
always @(posedge clk or negedge _rst) begin
//status_n = w1_r2 ;
case(status_c)
ready: status_n <= w1_r2;
w1_2kong: if(full_1) status_n <= w2_r1;
w1_r2: if(full_1||empty_2) status_n <= w2_r1;
w2_r1: if(full_2||empty_1) status_n <= w1_r2;
//stand: status_n = ready;
endcase
end
always @(posedge clk or negedge _rst) begin
case (status_n)
ready: begin
wr_en_1 <= 'd0;
rd_en_1 <= 'd0;
wr_en_2 <= 'd0;
rd_en_2 <= 'd0;
end
w1_2kong: begin
wr_en_1 <= 'd1;
rd_en_1 <= 'd0;
wr_en_2 <= 'd0;
rd_en_2 <= 'd0;
in_1 <= data_in;
out <= 'd0;
end
w1_r2: begin
wr_en_1 <= 'd1;
rd_en_1 <= 'd0;
wr_en_2 <= 'd0;
rd_en_2 <= 'd1;
in_1 <= data_in;
out <= dout_2;
end
w2_r1: begin
wr_en_1 <= 'd0;
rd_en_1 <= 'd1;
wr_en_2 <= 'd1;
rd_en_2 <= 'd0;
in_2 <= data_in;
out <= dout_1;
end
default: begin
wr_en_1 <= 'd0;
rd_en_1 <= 'd0;
wr_en_2 <= 'd0;
rd_en_2 <= 'd0;
end
endcase
end
endmodule
仿真结果:
提示:这里用的正弦波数据测试的:
问题分析:
可以看到,这里虽然数据没有丢,但是接口的数据两个都变成两个时钟周期的了,这里就以写满状态作为的状态转换没有写全,代码还需要做调整,但是整体的流程写出来了,vivado平台的FIFOip使能默认是低电平(可能可以改),用的直接输出就延迟一个时钟周期(First Word Fall Through),用的状态机控制的FIFO。
理论上,都是用单口RAM做乒乓操作比较好,但是要注意地址的控制,FPGA里FIFO主要缓存数据的,可以边读边写(真双口RAM)不用就浪费了。。。