Hyperflex® Architecture High-Performance Design Handbook

ID 683353
Date 12/06/2024
Public
Document Table of Contents

2.4.2.5. Flow Control with Skid Buffers

You can use skid buffers to pipeline a FIFO. If necessary, you can cascade skid buffers. When you insert skid buffers, they unroll the loop that includes the FIFO control signals. The skid buffers do not eliminate the loop in the flow control logic, but the loop transforms into a series of shorter loops. In general, switch to almost empty and almost full signals instead of using skid buffers when possible.
Figure 71.  FIFO Flow Control Loop with Two Skid Buffers in a Read Control Loop

If you have loops involving FIFO control signals, and they are broadcast to many destinations for flow control, consider whether you can eliminate the broadcast signals. Pipeline broadcast control signals, and use almost full and almost empty status bits from FIFOs.

Skid Buffer Example (Single Clock)

/ 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 Example (Dual Clock)

// 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