Intel® Hyperflex™ 体系结构高性能设计手册

ID 683353
日期 10/04/2021
Public
文档目录

2.4.2.5. 包含skid缓冲器的流程控制

您可以使用skid缓冲器来对FIFO进行流水线化。如果必要,您可以级联skid缓冲器。当插入skid缓冲器时,它们展开了包括FIFO控制信号的环路。 skid缓冲器不会消除流控逻辑中的环路,但是环路变换成一系列更短的环路。一般情况下,要尽可能地切换到almost empty和almost full信号,而不是使用skid缓冲器。
图 67. 读控制中有两个skid缓冲器的FIFO流控环路

如果环路包含FIFO控制信号,并且这些FIFO控制信号广播到很多目的地以用于流控,那么您要仔细考虑是否有消除这些广播信号的方法。对广播控制信号进行流水线化,并使用FIFO的almost full和almost empty状态比特。

Skid Buffer示例(单时钟)

/ synopsys translate_off
//`timescale 1 ps / 1 ps
// synopsys translate_on

module  singleclock_fifo_lowell
#(

    parameter DATA_WIDTH      = 8,
    parameter FIFO_DEPTH      = 16,
    parameter SHOWAHEAD       = "ON",   // "ON" = showahead mode ('pop' is an acknowledgement); /
         "OFF" = normal mode ('pop' is a request).
    parameter RAM_TYPE        = "AUTO", // "AUTO" or "MLAB" or "M20K".
    // Derived                
    parameter ADDR_WIDTH      = $clog2(FIFO_DEPTH) + 1  // e.g. clog2(64) = 6, but 7 bits /
         needed to store 64 value
) 
(
    input  wire                   clk,
    input  wire                   rst,
    input  wire  [DATA_WIDTH-1:0] in_data,    // write data
    input  wire                   pop,        // rd request
    input  wire                   push,       // wr request
    output wire                   out_valid,  // not empty
    output wire                   in_ready,   // not full
    output wire [DATA_WIDTH-1:0]  out_data,   // rd data
    output wire [ADDR_WIDTH-1:0]  fill_level
);  
    wire                      scfifo_empty;
    wire                      scfifo_full;
    wire [DATA_WIDTH-1:0]     scfifo_data_out;
    wire [ADDR_WIDTH-1:0]       scfifo_usedw;

    logic [DATA_WIDTH-1:0] out_data_1q;
    logic [DATA_WIDTH-1:0] out_data_2q;
    logic                  out_empty_1q;
    logic                  out_empty_2q;
    logic                  e_pop_1;
    logic                  e_pop_2;
    logic                  e_pop_qual;
    
    assign out_valid         = ~out_empty_2q; 
    assign in_ready          = ~scfifo_full;
    assign out_data          = out_data_2q; 
    assign fill_level        = scfifo_usedw + !out_empty_1q + !out_empty_2q;

// add output pipe 
    assign e_pop_1      = out_empty_1q || e_pop_2; 
    assign e_pop_2      = out_empty_2q || pop; 
    assign e_pop_qual = !scfifo_empty && e_pop_1;
    always_ff@(posedge clk)
    begin
      if(rst == 1'b1) 
      begin
        out_empty_1q <= 1'b1;  // empty is 1 by default
        out_empty_2q <= 1'b1;  // empty is 1 by default
      end 
      else begin 
        if(e_pop_1) 
        begin
          out_empty_1q <= scfifo_empty; 
        end 
        if(e_pop_2) 
        begin
          out_empty_2q <= out_empty_1q; 
        end 
      end 
    end 
    always_ff@(posedge clk)
    begin
      if(e_pop_1) 
        out_data_1q  <= scfifo_data_out; 
      if(e_pop_2) 
        out_data_2q   <= out_data_1q;
    end 

    scfifo scfifo_component 
    (
        .clock        (clk),
        .data         (in_data),

        .rdreq        (e_pop_qual),
        .wrreq        (push),

        .empty        (scfifo_empty),
        .full         (scfifo_full),
        .q            (scfifo_data_out),
        .usedw        (scfifo_usedw),
//        .aclr         (rst),
        .aclr         (1'b0),
        .almost_empty (),
        .almost_full  (),
        .eccstatus    (),
        //.sclr         (1'b0)
        .sclr         (rst)  // switch to sync reset
    );
    defparam
        scfifo_component.add_ram_output_register  = "ON",
        scfifo_component.enable_ecc               = "FALSE",
        scfifo_component.intended_device_family   = "Stratix",
        scfifo_component.lpm_hint                 = (RAM_TYPE == "MLAB") ? "RAM_BLOCK_TYPE=MLAB" : /
             ((RAM_TYPE == "M20K") ? "RAM_BLOCK_TYPE=M20K" : ""),
        scfifo_component.lpm_numwords             = FIFO_DEPTH,
        scfifo_component.lpm_showahead            = SHOWAHEAD,
        scfifo_component.lpm_type                 = "scfifo",
        scfifo_component.lpm_width                = DATA_WIDTH,
        scfifo_component.lpm_widthu               = ADDR_WIDTH,
        scfifo_component.overflow_checking        = "ON",
        scfifo_component.underflow_checking       = "ON",
        scfifo_component.use_eab                  = "ON";


endmodule

Skid Buffer示例(双时钟)

// synopsys translate_off
//`timescale 1 ps / 1 ps
// synopsys translate_on

module  skid_dualclock_fifo
#(

    parameter DATA_WIDTH      = 8,
    parameter FIFO_DEPTH      = 16,
    parameter SHOWAHEAD       = "ON",   
    parameter RAM_TYPE        = "AUTO", // "AUTO" or "MLAB" or "M20K".
    // Derived                
    parameter ADDR_WIDTH      = $clog2(FIFO_DEPTH) + 1  
) 
(
    input  wire                   rd_clk,
    input wire                    wr_clk,
    input  wire                   rst,
    input  wire  [DATA_WIDTH-1:0] in_data,    // write data
    input  wire                   pop,        // rd request
    input  wire                   push,       // wr request
    output wire                   out_valid,  // not empty
    output wire                   in_ready,   // not full
    output wire [DATA_WIDTH-1:0]  out_data,   // rd data
    output wire [ADDR_WIDTH-1:0]  fill_level
);  
    wire                      scfifo_empty;
    wire                      scfifo_full;
    wire [DATA_WIDTH-1:0]     scfifo_data_out;
    wire [ADDR_WIDTH-1:0]       scfifo_usedw;

    logic [DATA_WIDTH-1:0] out_data_1q;
    logic [DATA_WIDTH-1:0] out_data_2q;
    logic                  out_empty_1q;
    logic                  out_empty_2q;
    logic                  e_pop_1;
    logic                  e_pop_2;
    logic                  e_pop_qual;
    
    assign out_valid         = ~out_empty_2q; 
    assign in_ready          = ~scfifo_full;
    assign out_data          = out_data_2q; 
    assign fill_level        = scfifo_usedw + !out_empty_1q + !out_empty_2q;

// add output pipe 
    assign e_pop_1      = out_empty_1q || e_pop_2; 
    assign e_pop_2      = out_empty_2q || pop; 
    assign e_pop_qual = !scfifo_empty && e_pop_1;
    always_ff@(posedge rd_clk)
    begin
      if(rst == 1'b1) 
      begin
        out_empty_1q <= 1'b1;  // empty is 1 by default
        out_empty_2q <= 1'b1;  // empty is 1 by default
      end 
      else begin 
        if(e_pop_1) 
        begin
          out_empty_1q <= scfifo_empty; 
        end 
        if(e_pop_2) 
        begin
          out_empty_2q <= out_empty_1q; 
        end 
      end 
    end 
    always_ff@(posedge rd_clk)
    begin
      if(e_pop_1) 
        out_data_1q  <= scfifo_data_out; 
      if(e_pop_2) 
        out_data_2q   <= out_data_1q;
    end 
dcfifo  dcfifo_component
    (
        .data      (in_data),
        .rdclk     (rd_clk),
        .rdreq     (e_pop_qual),
        .wrclk     (wr_clk),
        .wrreq     (push),
        .q         (scfifo_data_out),
        .rdempty   (scfifo_empty),
        .rdusedw   (scfifo_usedw),
        .wrfull    (scfifo_full),
        .wrusedw   (),
        .aclr      (1'b0),
        .eccstatus (),
        .rdfull    (),
        .wrempty   ()
    );
    defparam
        dcfifo_component.add_usedw_msb_bit       = "ON",
        dcfifo_component.enable_ecc              = "FALSE",
        dcfifo_component.intended_device_family  = "Stratix 10",
        dcfifo_component.lpm_hint                =  (RAM_TYPE == "MLAB") \
             ? "RAM_BLOCK_TYPE=MLAB" : ((RAM_TYPE == "M20K") \
             ? "RAM_BLOCK_TYPE=M20K" : ""),
        dcfifo_component.lpm_numwords            = FIFO_DEPTH,
        dcfifo_component.lpm_showahead           = SHOWAHEAD,
        dcfifo_component.lpm_type                = "dcfifo",
        dcfifo_component.lpm_width               = DATA_WIDTH,
        dcfifo_component.lpm_widthu              = ADDR_WIDTH+1,
        dcfifo_component.overflow_checking       = "ON",
        dcfifo_component.read_aclr_synch         = "ON",
        dcfifo_component.rdsync_delaypipe        = 5,
        dcfifo_component.underflow_checking      = "ON",
        dcfifo_component.write_aclr_synch        = "ON",
        dcfifo_component.use_eab                 = "ON",
        dcfifo_component.wrsync_delaypipe        = 5;



endmodule