【报文数据流中的反压处理】

发布于:2024-06-10 ⋅ 阅读:(58) ⋅ 点赞:(0)

报文数据流中的反压处理


尤其是在NP芯片中,经常涉及到报文的数据流处理;为了防止数据丢失,和各模块的流水处理;因此需要到反压机制;
反压机制目前接触到的有两种:一是基于握手valid-ready信号的反压;二是基于credits的反压;
所谓反压,就是能够压住FIFO前级的发送和本级FIFO源头反压;若是有多个FIFO的话,还会涉及到调度问题;

本篇博客重点介绍带存储体(FIFO)的反压原理和实现;

1 带存储体的反压

1.1 原理图

示意图如下:基本上涉及数据流的处理,会在本级模块前级上放置一个FIFO,首先本级模块会进行处理,由于比如grant或者某些ctrl信号无法及时处理,FIFO无法pop出去,就会积压在本模块前级FIFO中,最终当累积到某种深度上,会向前级模块进行反压;不要在发送;
在这里插入图片描述

1.2 Demo

设计一个并行6输入32bit加法器,输出一个带截断的32bit加法结果,要求用三级流水设计,带反压信号;
本Demo的存储体是存储在本级模块后面中,前提是前级模块都是能够立即使用的,不需要等待什么条件

module pressure_fifo #(
	parameter	FIFO_DATA_WIDTH = 32,
	parameter 	FIFO_DEPTH 	= 8
)(
	input wire clk,
	input wire rst,
	input wire valid_i,
	output logic ready_o,	//给前级信号的准备信号
	input wire [32 -1:0] a,b,c,d,e,f,
	//output
	input wire ready_i,
	output logic [32 -1:0] dout,
	output logic valid_o
)
	
 localparam          WATERLINE = FIFO_DEPTH - 3; //three levels' pipeline
    logic               handshake;
    logic               handshake_ff1;
    logic               handshake_ff2;
    logic               wr_en;
        
    assign handshake = ready_o & valid_i;	//按理说ready_o拉高后,前级模块不应该进行发数据,在这里就是保险判断,即使valid_i有效,ready_o未准备好的话,会进行丢弃数据;

    always @ (posedge clk or posedge rst) begin
        if(rst) begin
            handshake_ff1 <= '0;
            handshake_ff2 <= '0;
        end
        else begin
            handshake_ff1 <= handshake;
            handshake_ff2 <= handshake_ff1;
        end
    end
    
    reg [31 : 0] r1_ab;
    always @ (posedge clk or posedge rst) begin
        if(rst) begin
            r1_ab <= '0;
        end
        else if(handshake)begin
            r1_ab <= a + b;
        end
    end
    
    reg [31 : 0] r1_cd;
    always @ (posedge clk or posedge rst) begin
        if(rst) begin
            r1_cd <= '0;
        end
        else if(handshake)begin
            r1_cd <= c + d;
        end
    end
    
    reg [31 : 0] r1_ef;
    always @ (posedge clk or posedge rst) begin
        if(rst) begin
            r1_ef <= '0;
        end
        else if(handshake)begin
            r1_ef <= e + f;
        end
    end
    
    reg [31 : 0] r2_abcd;
    always @ (posedge clk or posedge rst) begin
        if(rst) begin
            r2_abcd <= '0;
        end
        else if(handshake_ff1) begin
            r2_abcd <= r1_ab + r1_cd;
        end
    end
    
    reg [31 : 0] r2_ef;
    always @ (posedge clk or posedge rst) begin
        if(rst) begin
            r2_ef <= '0;
        end
        else if(handshake_ff1) begin
            r2_ef <= r1_ef;
        end
    end
    
    reg [31 : 0] r3;
    always @ (posedge clk or posedge rst) begin
        if(rst) begin
            r3 <= '0;
        end
        else if(handshake_ff2) begin
            r3 <= r2_ef + r2_abcd;
        end
    end
    
    always @ (posedge clk or posedge rst) begin
        if(rst) begin
            wr_en <= 1'b0;
        end
        else if(handshake_ff2) begin
            wr_en <= 1'b1;
        end
        else begin
            wr_en <= 1'b0;
        end
    end

    always_ff @(posedge clk)begin
        if(rst)begin
            ready_o <= 1'b0;
        end
        else if(usedw > WATERLINE)begin	//当使用的深度超过fifo存储体时,就要对上级反压;
            ready_o <= 1'b0;
        end
        else begin
            ready_o <= 1'b1;
        end
    end

    assign valid_o = ~empty;

// 同步FIFO存储体-->看用了多少fifo深度;3级流水线在反压起作用时,会一下子进入3个数据;
     sync_fifo # (
        .MEM_TYPE   ("auto"         ),
        .READ_MODE  ("fwft"         ),
        .WIDTH      (FIFO_DATA_WIDTH),
        .DEPTH      (FIFO_DEPTH     )
    )fifo_inst(
        .clk    (clk                ), // input  wire
        .rst_n  (rst_n              ), // input  wire
        .wren   (wr_en              ), // input  wire
        .din    (r3                 ), // input  wire [WIDTH-1:0]
        .rden   (ready_i            ), // input  wire
        .dout   (dout               ), // output reg  [WIDTH-1:0]
        .empty  (empty              ), // output wire
        .usedw  (usedw              )
    );

endmodule 

这个比较简单,相当于是从入口来我这的每排都有效,不要事先在前面进行先存储住;比如说另一种情况,前级模块给我发过来的数据,但是因为其他条件未准备好,我无法立即进行使用,因此也需要先暂存在本模块最前面的fifo存储体中

基本上划分模块的时候真实应用场景都是采用逐级模块向前反压,在这里简单有个概念:逐级反压和跨级反压;
在这里插入图片描述

逐级反压:流水线深度,好把握,也是项目中最经常用到的;
跨级反压:流水线深度:是waterlie3 + 在途1 + waterline1 + 在途2 + waterline2 + 在途3 (在途means 流水线深度)
【Refer】
1.https://zhuanlan.zhihu.com/p/359330607