乒乓操作是FPGA设计中常用的一种技巧,它通过数据流控制实现按节拍相互配合的切换,来提高数据处理效率,达到无缝缓冲和处理的效果。本文针对乒乓操作进行学习总结。
完整工程
乒乓操作的原理
一、原理图如下:
1、二选一控制器来对缓冲模块1和2进行选择。
2、数据缓冲模块一般就是SDRAM,FIFO等。
3、每一时刻如何工作:
clk1 时刻,输入数据data存入到mux1选择的缓冲1中。
clk2时刻,将data数据存在mux1 选择的缓冲2中,同时mux2选择缓冲1,将缓冲1中的数据送到后续处理中。
clk3时刻,mux1选通了缓冲1,将输入data存在缓冲1,同时mux2选择缓冲2,将其中的数据送到后续处理中
4、依次切换循环,从而实现乒乓操作。
二、波形表示
通过乒乓操作,我们即可通过节拍相互配合,最终实现数据的无缝缓冲与发送。
简单来看就是缓冲1写,则缓冲2读;缓冲2读,缓冲1写。
优点:
1、 实现数据的无缝缓冲和处理;——按节拍相互配合进行切换
2、 可节约缓冲区空间;
3、 可实现低速模块处理高速模块。
乒乓操作的verilog实现
1、采用case语句来进行选择。
2、确定该模块的输入输出端口:
3、由于乒乓操作就是缓冲1写,缓冲2读;缓冲2读,缓冲1写,共这两种情况,采用state的高低电平进行选择。
其中高电平1表示写1读2,低电平0表示写2读1
4、verilog代码
module pingpong(
input clk,
input rst,
input [7:0] data_in,
output reg [7:0] data_out
);
reg [7:0] buffer_1;
reg [7:0] buffer_2;
reg wr_flag1; //写标志,wr_flag1=0,buffer_2写;wr_flag1=1,buffer_1写
reg rd_flag2; //读标志,rd_flag2=0,buffer_1读;rd_flag2=1,buffer_2读
reg state; // 1:写1读2, 0:写2读1
// 状态每一个clk,翻转一次(二分频)
always@(posedge clk or negedge rst) begin
if (!rst)
state<= 0;
else
state<= ~state;
end
//二选一多路器,原理图中的选择控制模块
always@(*)
begin
case(state)
1'b0: //buffer2写,buffer1读
begin
wr_flag1<=0;
rd_flag2<=0;
end
1'b1://buffer1写,buffer2读
begin
wr_flag1<=1;
rd_flag2<=1;
end
default:
begin
wr_flag1<=0;
rd_flag2<=0;
end
endcase
end
//写缓存buffer数据
always@(posedge clk or negedge rst)
begin
if(!rst)begin
buffer_1<=8'b0;
buffer_2<=8'b0;
end
else begin
case(wr_flag1) //根据写标志,判断往哪个缓冲中写数据
0: buffer_2<=data_in;//wr_flag1 = 0,写buffer2
1: buffer_1<=data_in;//wr_flag1 = 1,写buffer1
default:begin
buffer_1<=0;
buffer_2<=0;
end
endcase
end
end
//读缓存buffer数据
always@(posedge clk or negedge rst)
begin
if(!rst)
data_out<=8'b0;
else
case(rd_flag2)//根据读标志,判断读哪个缓冲中的数据
0:data_out<=buffer_1; //读buffer_1的数据
1:data_out<=buffer_2;
default:data_out<=0;
endcase
end
endmodule
tb测试:
`timescale 1ns / 1ps
module pingpong_operation_tb;
reg clk;
reg rst_n;
reg [7:0] data_in;
wire [7:0] data_out;
pingpong_operation u_pingpong(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.data_out(data_out)
);
initial begin
clk = 0;
rst_n = 0;
#40 rst_n =1;
#100000;
$stop;
end
always #10 clk = ~clk; //一个ck为20ns
//产生输入激励
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_in<=0;
else
data_in<=data_in+1;
end
endmodule
波形如下:
state = 1 :buffer1写,读buffer2;
state = 0 :buffer2写,读buffer1;
读写标志:
state = 1 :wr_flag1 = 1;rd_flag2= 1;
state = 0 :wr_flag1 = 0;rd_flag2= 0;
写进哪个缓冲?
wr_flag1 = 1 : buffer_1<=data_in;
wr_flag1 = 0 : buffer_2<=data_in;
读哪个缓冲中的数据?
rd_flag2 = 0 : data_out<=buffer_1;
rd_flag2 = 1 : data_out<=buffer_2;
可看到与我们前面根据原理分析出的波形相同。