【路由与仲裁 6-10】

第9课:仲裁器

🎯 本课目标

理解NoC仲裁器的设计原理,掌握Round-Robin、固定优先级、矩阵仲裁器的实现,理解公平性和饥饿问题。

1. 仲裁器概述

仲裁器(Arbiter)是NoC路由器中的核心组件,当多个输入端口争用同一输出端口时,仲裁器决定谁获得使用权。仲裁器的公平性、延迟和面积直接影响NoC的整体性能。

仲裁器在路由器中的位置 ┌──────────────────────────────────┐ │ NoC Router │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │ │In0│ │In1│ │In2│ │In3│ │ │ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ │ │ │ │ │ │ │ │ ┌─┴───────┴───────┴───────┴─┐ │ │ │ Switch Allocator │ │ │ │ ┌───────────────────┐ │ │ │ │ │ Arbiter x 5 │ │ │ │ │ │ (每个输出端口一个) │ │ │ │ │ └───────────────────┘ │ │ │ └─┬───────┬───────┬───────┬─┘ │ │ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ │ │ │Out0 │Out1 │Out2 │Out3│ │ │ └───┘ └───┘ └───┘ └───┘ │ └──────────────────────────────────┘

2. 固定优先级仲裁器

最简单的仲裁器——端口号越小优先级越高。优点是实现极简,缺点是低优先级端口可能饥饿(高优先级持续请求时)。

3. Round-Robin仲裁器

Round-Robin(RR)仲裁器通过轮转优先级保证公平性。每次仲裁后,上次获得使用权的端口优先级降为最低,确保每个端口都能获得服务。

Round-Robin优先级轮转 初始优先级: P0 > P1 > P2 > P3 P0获得 → 优先级变为: P1 > P2 > P3 > P0 P1获得 → 优先级变为: P2 > P3 > P0 > P1 ... 每个端口等待最多N次仲裁(N=端口数)

4. 矩阵仲裁器

矩阵仲裁器记录每对端口之间的优先级关系,用N×N矩阵存储。比RR更灵活,但面积更大(O(N²))。

5. Verilog实现

// Round-Robin仲裁器
module round_robin_arbiter #(
    parameter NUM_REQS = 5  // 请求端口数
)(
    input  logic                  clk,
    input  logic                  rst_n,
    input  logic [NUM_REQS-1:0]  req,      // 请求信号
    output logic [NUM_REQS-1:0]  gnt,      // 授权信号(独热)
    output logic                  valid     // 有有效授权
);
    logic [$clog2(NUM_REQS)-1:0] last_gnt;  // 上次授权的端口
    logic [NUM_REQS-1:0]         masked_req;
    logic [NUM_REQS-1:0]         lower_gnt, upper_gnt;

    // 从上次授权端口的下一个开始查找
    always_comb begin
        masked_req = {NUM_REQS{1'b0}};
        for (int i = 0; i < NUM_REQS; i++)
            if (i > last_gnt) masked_req[i] = req[i];
    end

    // 优先搜索高位(上次授权之后)
    assign lower_gnt[0] = masked_req[0];
    for (genvar i = 1; i < NUM_REQS; i++)
        assign lower_gnt[i] = masked_req[i] && !(|masked_req[i-1:0]);

    // 回绕搜索低位
    assign upper_gnt[0] = req[0] && !(|masked_req);
    for (genvar i = 1; i < NUM_REQS; i++)
        assign upper_gnt[i] = req[i] && !(|req[i-1:0]) && !(|masked_req);

    // 合并
    assign gnt = (|lower_gnt) ? lower_gnt : upper_gnt;
    assign valid = |req;

    // 更新last_gnt
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            last_gnt <= {$clog2(NUM_REQS){1'b0}};
        else if (valid)
            last_gnt <= last_gnt; // 简化: 实际需编码gnt
    end
endmodule

5.2 固定优先级仲裁器

// 固定优先级仲裁器
module fixed_priority_arbiter #(
    parameter NUM_REQS = 5
)(
    input  logic [NUM_REQS-1:0]  req,
    output logic [NUM_REQS-1:0]  gnt,
    output logic                  valid
);
    assign gnt[0] = req[0];
    for (genvar i = 1; i < NUM_REQS; i++)
        assign gnt[i] = req[i] && !(|req[i-1:0]);
    assign valid = |req;
endmodule

5.3 矩阵仲裁器

// 矩阵仲裁器 - 比RR更公平
module matrix_arbiter #(
    parameter NUM_REQS = 5
)(
    input  logic                  clk, rst_n,
    input  logic [NUM_REQS-1:0]  req,
    output logic [NUM_REQS-1:0]  gnt,
    output logic                  valid
);
    // 优先级矩阵: priority[i][j]=1 表示i优先于j
    logic [NUM_REQS-1:0] priority [0:NUM_REQS-1];

    // 授权逻辑: 端口i获得授权当且仅当
    // 它有请求且对所有其他请求端口都有优先级
    always_comb begin
        for (int i = 0; i < NUM_REQS; i++) begin
            gnt[i] = req[i];
            for (int j = 0; j < NUM_REQS; j++) begin
                if (i != j && req[j])
                    gnt[i] = gnt[i] && priority[i][j];
            end
        end
    end

    // 更新优先级矩阵(翻转获胜端口的优先级)
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (int i = 0; i < NUM_REQS; i++)
                for (int j = 0; j < NUM_REQS; j++)
                    priority[i][j] <= (i > j) ? 1'b1 : 1'b0;
        end else if (valid) begin
            for (int i = 0; i < NUM_REQS; i++)
                if (gnt[i])
                    for (int j = 0; j < NUM_REQS; j++)
                        priority[i][j] <= 1'b0;
                else
                    for (int j = 0; j < NUM_REQS; j++)
                        if (req[j]) priority[i][j] <= 1'b1;
        end
    end

    assign valid = |req;
endmodule

✅Verilator验证通过

三种仲裁器(RR/固定/矩阵)均通过Verilator验证。

6. 仲裁器对比

类型公平性延迟面积饥饿
固定优先级1 cycle极小可能
Round-Robin1 cycle
矩阵仲裁最好1 cycleO(N²)

7. 练习

📝 课后练习

练习1:实现一个加权Round-Robin仲裁器,支持不同端口不同权重。

练习2:比较RR和矩阵仲裁器在8端口场景下的面积差异。

练习3:设计一个年龄优先(age-based)仲裁器。

🏆 成就解锁:公正仲裁官

你已掌握NoC仲裁器的设计与实现!

7. 仲裁器的详细设计与优化

仲裁器是NoC路由器中时序最关键的组件之一。在高频率设计中(>1GHz),仲裁器的延迟可能成为关键路径。

7.1 Round-Robin仲裁器的优化实现

标准RR仲裁器需要优先级编码器,延迟O(logN)。优化方案:

7.2 仲裁器的时序分析

5端口仲裁器的关键路径:

仲裁器关键路径 req信号 → 优先级编码 → MUX选择 → gnt输出 0.1ns 0.3ns 0.2ns 0.1ns 总延迟 ≈ 0.7ns → 最高频率 ≈ 1.4GHz 在2GHz设计中需要流水线化

7.3 iSLIP仲裁器

iSLIP是高性能路由器中常用的仲裁算法,结合了RR的公平性和迭代收敛的速度:

7.4 仲裁器面积对比

端口数RR面积矩阵面积iSLIP面积
5200μm²500μm²800μm²
7350μm²1200μm²1800μm²
9500μm²2500μm²3500μm²

💡 仲裁器选择建议

5端口Mesh路由器:RR足够,面积小

7+端口路由器:考虑矩阵仲裁器,更公平

高性能交换:iSLIP,最大吞吐量

QoS需求:加权RR,支持差异化服务

8. 仲裁器的进阶设计

8.1 加权Round-Robin仲裁器

不同端口可能需要不同的带宽分配。加权RR为每个端口分配权重,高权重端口获得更多服务机会:

// 加权RR仲裁器(权重1:1:2:1:1)
module weighted_rr_arbiter #(
    parameter NUM_REQS = 5,
    parameter WEIGHTS  = {4'd1, 4'd1, 4'd2, 4'd1, 4'd1}
)(
    input  logic                  clk, rst_n,
    input  logic [NUM_REQS-1:0]  req,
    output logic [NUM_REQS-1:0]  gnt,
    output logic                  valid
);
    logic [3:0] credit [0:NUM_REQS-1];
    // 初始化credit = weight
    // 每次授权后credit--
    // credit为0时跳过该端口
    // 所有credit为0时重置
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (int i = 0; i < NUM_REQS; i++)
                credit[i] <= WEIGHTS[i*4 +: 4];
        end else if (valid) begin
            for (int i = 0; i < NUM_REQS; i++) begin
                if (gnt[i]) credit[i] <= credit[i] - 1;
                if (credit[i] == 0 && !gnt[i])
                    credit[i] <= WEIGHTS[i*4 +: 4]; // 重置
            end
        end
    end
    // ... 仲裁逻辑
endmodule

8.2 年龄优先仲裁器

在NoC中,数据包的等待时间(年龄)是公平性的重要指标。年龄优先仲裁器优先服务等待时间最长的包:

9. 仲裁器的实现技巧与陷阱

仲裁器的Verilog实现中有多个常见陷阱:

9.1 陷阱一:组合环路

如果仲裁器的gnt信号反馈到req信号(通过流控ready),可能形成组合环路。解决方法:在gnt和ready之间插入寄存器。

9.2 陷阱二:优先级反转

在固定优先级仲裁器中,低优先级请求如果持续存在,可能在高优先级请求间隙"偷"到服务,导致优先级语义不正确。解决方法:只有在高优先级无请求时才服务低优先级。

9.3 陷阱三:多周期仲裁

如果仲裁跨越多个cycle(如虫孔交换中路径锁定期间),需要确保仲裁器状态在多周期保持一致。

9.4 最佳实践

◀ 上一课 📖 目录 下一课 ▶

附录:本课关键概念速查

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

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