乒乓操作FIFO

文章目录

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)不用就浪费了。。。

 

 

  • 7
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
乒乓FIFO是一种特殊的FIFO(First In First Out)队列,它允许在读取数据时同时写入新的数据,并且在写入新数据时同时读取已有的数据。以下是一个使用Verilog实现乒乓FIFO的简单示例: ```verilog module PingPongFIFO ( input wire clk, // 时钟信号 input wire reset, // 复位信号 input wire write_enable, // 写使能信号 input wire read_enable, // 读使能信号 input wire [7:0] write_data, // 写入数据 output wire [7:0] read_data // 读取数据 ); reg [7:0] fifo_mem [1:0]; // FIFO内存 reg [1:0] read_index; // 读取索引 reg [1:0] write_index; // 写入索引 always @(posedge clk or posedge reset) begin if (reset) begin read_index <= 2'b00; // 复位时重置索引 write_index <= 2'b00; end else begin if (write_enable) begin fifo_mem[write_index] <= write_data; // 写入新数据到FIFO write_index <= write_index + 1; // 更新写入索引 end if (read_enable) begin read_data <= fifo_mem[read_index]; // 从FIFO读取数据 read_index <= read_index + 1; // 更新读取索引 end end end endmodule ``` 在该Verilog代码中,使用两个2位宽的索引(read_index和write_index)分别用于读取和写入FIFO的数据。在时钟上升沿触发时,根据控制信号(write_enable和read_enable)进行相应的读写操作,并更新索引。同时,使用一个二维数组(fifo_mem)作为FIFO的存储器,可以保存8位宽的数据。读取操作将读取指定索引位置的数据并传递给输出端口(read_data),写入操作将将输入端口(write_data)的数据写入指定索引位置。 通过此Verilog代码,可以实现一个简单的乒乓FIFO模块,能够同时读取和写入数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值