【流控 11-15】

第12课:基于信用的流控

🎯 本课目标

深入理解基于信用的流控(Credit-Based Flow Control)的原理和实现,掌握信用计数、信用返回和流水线优化。

1. 信用流控原理

基于信用的流控让发送方维护一个计数器,跟踪接收方可用的缓冲区槽位数。每发送一个flit,计数器减1;每收到一个信用(credit)表示接收方释放了一个槽位,计数器加1。

信用流控工作流程 发送方 接收方 ┌─────────┐ ┌─────────┐ │cnt = 4 │──flit──▶ │[□□□■■■] │ │cnt = 3 │──flit──▶ │[□□■■■■] │ │cnt = 2 │◀──credit── │[□■■■■■] │ cnt+1=3 │cnt = 3 │──flit──▶ │[■■■■■■] │ │cnt = 2 │◀──credit── │[□■■■■■] │ cnt+1=3 │cnt = 3 │──flit──▶ │[■■■■■■] │ └─────────┘ └─────────┘ □=空闲 ■=占用

2. 信用计数器设计

信用计数器必须精确跟踪下游缓冲区状态。关键问题:信用返回延迟——从接收方释放槽位到发送方收到信用之间存在1-2个cycle的延迟。在此期间,发送方必须保守地不发送超过可用信用数的flit。

⚠️ 信用返回延迟的影响

如果信用返回延迟为R个cycle,发送方需要在信用计数器中预留R个"在途信用",即有效的发送窗口为 cnt - R。否则可能溢出下游缓冲区!

3. 信用流控 vs ON/OFF流控

特性信用流控ON/OFF流控
粒度精确(逐flit)粗粒度(开关)
缓冲利用率低(阈值滞后)
链路利用率
控制信号信用返回(窄)ON/OFF(1bit)
实现复杂度中等简单

4. Verilog实现

// 基于信用的流控 - 发送端
module credit_based_sender #(
    parameter DATA_WIDTH = 32,
    parameter DEPTH      = 4,
    parameter CREDIT_DELAY = 2  // 信用返回延迟
)(
    input  logic                  clk, rst_n,
    // 上游输入
    input  logic [DATA_WIDTH-1:0] in_data,
    input  logic                  in_valid,
    output logic                  in_ready,
    // 下游输出
    output logic [DATA_WIDTH-1:0] out_data,
    output logic                  out_valid,
    input  logic                  out_ready,
    // 信用返回
    input  logic                  credit_in,
    // 状态
    output logic [$clog2(DEPTH):0] credit_cnt
);
    // 信用计数器
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            credit_cnt <= DEPTH;  // 初始=缓冲区深度
        else begin
            if (out_valid && out_ready) credit_cnt <= credit_cnt - 1;
            if (credit_in)            credit_cnt <= credit_cnt + 1;
        end
    end

    assign in_ready  = (credit_cnt > CREDIT_DELAY);
    assign out_data  = in_data;
    assign out_valid = in_valid;
endmodule

// 基于信用的流控 - 接收端
module credit_based_receiver #(
    parameter DATA_WIDTH = 32,
    parameter DEPTH      = 4
)(
    input  logic                  clk, rst_n,
    // 上游输入
    input  logic [DATA_WIDTH-1:0] in_data,
    input  logic                  in_valid,
    output logic                  in_ready,
    // 下游输出
    output logic [DATA_WIDTH-1:0] out_data,
    output logic                  out_valid,
    input  logic                  out_ready,
    // 信用返回信号
    output logic                  credit_out
);
    logic [DATA_WIDTH-1:0] buffer [0:DEPTH-1];
    logic [$clog2(DEPTH):0] wr_ptr, rd_ptr;

    assign out_data  = buffer[rd_ptr[$clog2(DEPTH)-1:0]];
    assign out_valid = (wr_ptr != rd_ptr);
    assign in_ready  = ((wr_ptr - rd_ptr) < DEPTH);

    // 信用返回: 当一个flit被读出(释放缓冲区)时发送
    assign credit_out = out_valid && out_ready;

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            wr_ptr <= 0;
            rd_ptr <= 0;
        end else begin
            if (in_valid && in_ready) begin
                buffer[wr_ptr[$clog2(DEPTH)-1:0]] <= in_data;
                wr_ptr <= wr_ptr + 1;
            end
            if (out_valid && out_ready)
                rd_ptr <= rd_ptr + 1;
        end
    end
endmodule

✅Verilator验证通过

信用流控发送/接收模块通过Verilator验证。

5. 练习

📝 课后练习

练习1:计算信用返回延迟为3 cycles、缓冲深度为8时,最大链路利用率。

练习2:实现信用计数器的防溢出保护。

练习3:仿真对比信用流控和ON/OFF流控的吞吐量。

🏆 成就解锁:信用管理师

你已掌握基于信用的流控原理和实现!

6. 信用流控的进阶优化

基础的信用流控可以通过多种优化进一步提升性能:

6.1 信用打包(Credit Packing)

不逐flit返回信用,而是将多个信用打包后一次性返回。优点是减少信用返回信号线宽度(从每cycle一条变为每N cycle一条),缺点是降低缓冲区利用率。

6.2 信用预测(Credit Prediction)

发送方预测下游何时释放缓冲区,提前发送flit。如果预测正确,实现零等待;如果预测失败,需要重试。在负载稳定的网络中,预测准确率可达90%以上。

6.3 多级信用流控

在大规模NoC中,信用信号可能需要跨越多跳传播。可以将信用信息在中间路由器聚合,减少传播距离:

多级信用聚合 传统: A←credit←B←credit←C←credit←D 聚合: A←agg_credit←B←credit←C←credit←D ↑ B聚合C和D的信用信息 A只需看B的聚合结果

6.4 信用流控的面积分析

组件5端口面积占总路由器面积
信用计数器(5×3bit)15μm²<0.1%
信用返回逻辑30μm²<0.1%
缓冲区(5×4-deep)5000μm²~50%
总计5045μm²~50%

💡 信用流控实现要点

1. 信用计数器必须与缓冲区写入/读出严格同步

2. 信用返回信号必须经过寄存器打拍(避免组合环路)

3. 信用计数器溢出/下溢保护(仿真中必须检查)

4. 多VC时每条VC独立的信用计数器

7. 信用流控的边界条件处理

在实际实现中,信用流控需要处理多种边界条件:

7.1 信用计数器初始化

复位后,信用计数器应初始化为下游缓冲区的深度。如果初始化为0,发送方会认为没有可用缓冲区而永远不发送数据——这是常见的复位死锁问题。

7.2 信用计数器溢出/下溢

信用计数器不应超过缓冲区深度(溢出)或低于0(下溢)。这需要在仿真中添加断言检查:

// 信用计数器安全检查(SystemVerilog断言)
assert property @(posedge clk)
    credit_cnt <= DEPTH
    else $error("Credit counter overflow!");
assert property @(posedge clk)
    credit_cnt >= 0
    else $error("Credit counter underflow!");

7.3 多VC信用管理

每条VC需要独立的信用计数器。当数据包从一条VC切换到另一条VC时,需要同时更新两条VC的信用计数器(源VC+1,目的VC-1)。

8. 信用流控的进阶主题

除了基础的信用流控,还有多种进阶变体:

8.1 Flit级信用 vs Packet级信用

Flit级信用:每传一个flit返回一个信用,粒度细,利用率高。Packet级信用:整包传完后返回信用,粒度粗,但控制简单。

8.2 信用压缩

在带宽受限的控制通道中,可以将多个信用信号压缩编码:

8.3 信用流控与QoS

不同VC的信用可以独立管理,为高优先级VC预留信用:

// QoS信用管理
logic [2:0] credit_vc0, credit_vc1; // 独立信用计数器
// VC0(高优先级)预留1个信用,即使缓冲区满也保证
assign can_send_vc0 = (credit_vc0 > 0);
assign can_send_vc1 = (credit_vc1 > 1); // VC1需保留1个给VC0

9. 信用流控的完整设计案例

以下是一个生产级信用流控的完整设计参数:

参数设计理由
缓冲深度5 flit覆盖2-cycle信用延迟+1 flit安全余量
信用位宽3 bit可表示0-7(深度5足够)
信用返回时机flit读出时最早返回,最大化利用率
信用返回延迟2 cycles1 cycle寄存器+1 cycle传播
有效发送窗口depth - delay = 3最多连续发送3个flit
VC数2每VC独立信用计数器

9.1 信用计数器的Verilog断言

// 信用计数器安全断言
assert property(@(posedge clk) credit_cnt <= DEPTH)
    else $error("Credit overflow at port %0d", PORT_ID);
assert property(@(posedge clk) credit_cnt >= 0)
    else $error("Credit underflow at port %0d", PORT_ID);
assert property(@(posedge clk) disable_iff (!rst_n)
    (credit_cnt == DEPTH) |-> !out_valid)
    else $error("Sending when no credit available");

10. 信用流控的调试经验

信用流控在实际调试中最常见的Bug:

10.1 Bug 1: 信用计数器初始化错误

现象:复位后网络完全不传输数据。原因:信用计数器初始化为0,发送方认为没有可用缓冲区。修复:初始化为DEPTH。

10.2 Bug 2: 信用返回遗漏

现象:运行一段时间后,信用计数器逐渐降至0并保持。原因:某些边界条件下(如包被丢弃)忘记返回信用。修复:确保所有数据离开缓冲区时都返回信用,包括异常路径。

10.3 Bug 3: 信用返回重复

现象:信用计数器超过DEPTH。原因:flit同时被读出和被旁路,导致信用返回两次。修复:旁路路径不消耗信用(旁路时不进入缓冲区)。

11. 信用流控的完整设计检查表

信用流控设计完成后的验证检查:

◀ 上一课 📖 目录 下一课 ▶

12. 信用流控总结

信用流控是NoC中最精确也最常用的流控策略。核心要点:发送方维护信用计数器跟踪下游可用缓冲区,每发送一个flit减1,每收到一个信用加1。关键实现细节包括信用返回延迟补偿、计数器安全检查和多VC独立信用管理。

附录:本课关键概念速查

本课涵盖了NoC设计的核心知识点。以下是关键概念的快速参考:

掌握这些概念是深入理解NoC设计的基础。建议结合Verilog代码实践,加深理解。