[IC] Spill Register与axi_cut
in 默认分类 with 0 comment
[IC] Spill Register与axi_cut
in 默认分类 with 0 comment

背景

在现代数字系统设计中,流水线技术是提高处理器和其他硬件模块性能的关键技术。通过将复杂的操作分解成多个简单的阶段并行执行,流水线能够显著提高系统的吞吐量。然而,在实现这种技术时,数据流的管理成为一个重要的挑战。本文将介绍流水线机制及其相关信号控制,并深入探讨Spill Register的应用。

数字电路中的流水线

流水线是一种分阶段执行的设计方法,将一个复杂的操作划分为多个子操作,每个子操作由一个流水级来完成。通过让多个子操作同时进行,流水线能够在一个时钟周期内处理多个数据,从而提高运算速度。

流水线中的握手信号

在流水线设计中,valid和ready信号用于协调各个级之间的数据传输:

valid: 指示当前级的数据是否有效。
ready: 指示下一级是否准备好接收数据。
一个典型的握手协议中,当前级发出的ready_o信号可以用以下逻辑表达式表示:

ready_o = !valid_o | ready_i;

发出的valid_o信号则可以定义为:

valid_o = ready_o && valid_i;

反压机制

反压机制用于处理下游级无法接收数据的情况。当下游级未准备好时,通过将ready信号传递回上游级,通知其暂停发送数据。这一机制确保数据不会丢失,同时也防止系统溢出。

多级流水线中的信号传递

在多级流水线中,ready信号可能会形成一条长的组合逻辑路径,这会导致时序问题。为了改善时序,通常需要对ready信号进行打拍处理,使其在每一级之间有寄存器缓存。

Spill Register的引入

在设计复杂的数字系统时,常常需要处理数据流的管理,以确保在处理器或其他硬件模块中数据能够高效、可靠地传输和存储。为此,硬件设计中引入了一些特殊的模块和机制,如spill register、axi_cut、和skidbuffer,以满足高性能应用的需求。

在ara向量处理器中,给axi通路插入了多个axi_cut模块(vlsu和soc),以打断组合逻辑路径、提升总线的频率。而axi_cut模块就是给axi每个通道用了一个Spill Register。

而Spill Register中有2个寄存器,可以交替填充和排空,以处理短暂的数据流不匹配,以及减少数据传输过程中的气泡。

spill register的细节

工作机制

Spill Register由两个寄存器组成:a和b。其基本工作流程如下:

  1. 数据首先进入寄存器a。
  2. 如果下游无法接收数据,a中的数据转移至b,此时新数据可以继续进入a。
  3. 当下游恢复接收能力时,数据依次从b和a输出,恢复正常的数据流。
    这种机制确保了即使在下游突然不ready的情况下,数据也不会丢失。

    结构

信号

从信号可以看出,正常情况,数据会先进到a,然后再从a输出出去;
而当下游突然不能接收时,数据会从a放到b,新到的数据会放到a,然后a、b都满了,不能再接收新的数据,ready_o=0。也就是模块可以接收突然下游不ready时上游发出的那个数据;
而当下游恢复时,先发出b中的数据,再发出a中的数据,然后再恢复到正常模式

代码

module spill_register_flushable #(
  parameter type T           = logic,
  parameter bit  Bypass      = 1'b0   // make this spill register transparent
) (
  input  logic clk_i   ,
  input  logic rst_ni  ,
  input  logic valid_i ,
  input  logic flush_i ,
  output logic ready_o ,
  input  T     data_i  ,
  output logic valid_o ,
  input  logic ready_i ,
  output T     data_o
);

  if (Bypass) begin : gen_bypass
    assign valid_o = valid_i;
    assign ready_o = ready_i;
    assign data_o  = data_i;
  end else begin : gen_spill_reg
    // The A register.
    T a_data_q;
    logic a_full_q;
    logic a_fill, a_drain;

    always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_data
      if (!rst_ni)
        a_data_q <= '0;
      else if (a_fill)
        a_data_q <= data_i;
    end

    always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_full
      if (!rst_ni)
        a_full_q <= 0;
      else if (a_fill || a_drain)
        a_full_q <= a_fill;
    end

    // The B register.
    T b_data_q;
    logic b_full_q;
    logic b_fill, b_drain;

    always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_data
      if (!rst_ni)
        b_data_q <= '0;
      else if (b_fill)
        b_data_q <= a_data_q;
    end

    always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_full
      if (!rst_ni)
        b_full_q <= 0;
      else if (b_fill || b_drain)
        b_full_q <= b_fill;
    end

    // Fill the A register when the A or B register is empty. Drain the A register
    // whenever it is full and being filled, or if a flush is requested.
    assign a_fill = valid_i && ready_o && (!flush_i);
    assign a_drain = (a_full_q && !b_full_q) || flush_i;

    // Fill the B register whenever the A register is drained, but the downstream
    // circuit is not ready. Drain the B register whenever it is full and the
    // downstream circuit is ready, or if a flush is requested.
    assign b_fill = a_drain && (!ready_i) && (!flush_i);
    assign b_drain = (b_full_q && ready_i) || flush_i;

    // We can accept input as long as register B is not full.
    // Note: flush_i and valid_i must not be high at the same time,
    // otherwise an invalid handshake may occur
    assign ready_o = !a_full_q || !b_full_q;

    // The unit provides output as long as one of the registers is filled.
    assign valid_o = a_full_q | b_full_q;

    // We empty the spill register before the slice register.
    assign data_o = b_full_q ? b_data_q : a_data_q;

    `ifndef SYNTHESIS
    `ifndef COMMON_CELLS_ASSERTS_OFF
    flush_valid : assert property (
      @(posedge clk_i) disable iff (~rst_ni) (flush_i |-> ~valid_i)) else
      $warning("Trying to flush and feed the spill register simultaneously. You will lose data!");
   `endif
     `endif
  end
endmodule

仿真

未完待续……

Responses