FPGA设计——乒乓操作实现与modelsim仿真

乒乓操作是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测试:

扫描二维码关注公众号,回复: 14242648 查看本文章
`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;
在这里插入图片描述

可看到与我们前面根据原理分析出的波形相同。

猜你喜欢

转载自blog.csdn.net/H19981118/article/details/125103589