【路由器设计 16-20】

第18课:交叉开关

🎯 本课目标

理解NoC路由器中交叉开关(Crossbar)的设计原理,掌握全连接、多播和部分连接交叉开关的实现。

1. 交叉开关概述

交叉开关(Crossbar Switch)是路由器中连接输入端口到输出端口的核心互连结构。N×N交叉开关可以实现任意输入到任意输出的同时连接,是路由器面积和延迟的重要来源。

5×5交叉开关结构 Out0 Out1 Out2 Out3 Out4 │ │ │ │ │ In0 ────┼─────┼─────┼─────┼─────┼──── │ │ │ │ │ In1 ────┼─────┼─────┼─────┼─────┼──── │ │ │ │ │ In2 ────┼─────┼─────┼─────┼─────┼──── │ │ │ │ │ In3 ────┼─────┼─────┼─────┼─────┼──── │ │ │ │ │ In4 ────┼─────┼─────┼─────┼─────┼──── 每个交叉点 = 1个MUX选择器 总交叉点数 = N × N = 25

2. 交叉开关类型

2.1 全连接交叉开关

每个输出端口可以从任意输入端口接收数据。N×N交叉开关需要N²个交叉点,面积O(N²)。

2.2 部分连接交叉开关

限制每个输出端口只能从部分输入端口接收数据。减少交叉点数量,降低面积,但限制连接灵活性。

2.3 多播交叉开关

支持一个输入同时连接到多个输出。用于广播和多播操作,但面积更大。

3. 交叉开关面积与延迟

端口数N交叉点数面积(相对)关键路径
525
749
9813.5×

4. Verilog实现

// 5×5全连接交叉开关
module crossbar_5x5 #(
    parameter DATA_WIDTH = 32,
    parameter NUM_PORTS  = 5
)(
    // 输入端口
    input  logic [DATA_WIDTH-1:0] in_data  [0:NUM_PORTS-1],
    // 选择信号: 每个输出选择一个输入
    input  logic [$clog2(NUM_PORTS)-1:0] sel [0:NUM_PORTS-1],
    // 输出端口
    output logic [DATA_WIDTH-1:0] out_data [0:NUM_PORTS-1]
);
    // 每个输出端口一个MUX
    always_comb begin
        for (int o = 0; o < NUM_PORTS; o++) begin
            case (sel[o])
                3'd0: out_data[o] = in_data[0];
                3'd1: out_data[o] = in_data[1];
                3'd2: out_data[o] = in_data[2];
                3'd3: out_data[o] = in_data[3];
                3'd4: out_data[o] = in_data[4];
                default: out_data[o] = {DATA_WIDTH{1'b0}};
            endcase
        end
    end
endmodule

// 参数化N×N交叉开关
module crossbar_nxn #(
    parameter DATA_WIDTH = 32,
    parameter NUM_PORTS  = 5
)(
    input  logic [DATA_WIDTH-1:0]             in_data  [0:NUM_PORTS-1],
    input  logic [$clog2(NUM_PORTS)-1:0]      sel [0:NUM_PORTS-1],
    output logic [DATA_WIDTH-1:0]             out_data [0:NUM_PORTS-1]
);
    for (genvar o = 0; o < NUM_PORTS; o++) begin : gen_output
        always_comb begin
            out_data[o] = in_data[sel[o]];
        end
    end
endmodule

✅Verilator验证通过

交叉开关模块通过Verilator验证。

5. 练习

📝 课后练习

练习1:实现支持多播的交叉开关。

练习2:分析7端口路由器的交叉开关面积。

练习3:设计部分连接交叉开关,只允许相邻端口互连。

🏆 成就解锁:交叉开关匠

你已掌握交叉开关的设计与实现!

6. 交叉开关的详细设计空间

交叉开关的设计涉及多个维度,从简单到复杂:

6.1 全连接交叉开关的MUX实现

5×5交叉开关的每个输出端口是一个5选1 MUX。关键路径是MUX的选择延迟。

5选1 MUX的树形实现 ┌──────────────────────────────────┐ │ out_data[0] │ │ ┌──MUX──┐ │ │ ┌──MUX──┐ ┌──MUX──┐ │ │ in[0] in[1] in[2] ┌──MUX──┐ │ │ in[3] in[4] │ │ │ │ 延迟: 3级MUX = log₂5 ≈ 3 │ └──────────────────────────────────┘

6.2 多级交叉开关

当端口数N较大时(N>8),单级交叉开关面积和延迟过大。使用多级Clos网络:

一个3级Clos网络C(n,m,r)有r个入线组(每组n条)和r个出线组,中间级m个开关。

6.3 交叉开关的功耗优化

交叉开关的功耗主要来自数据线的翻转。优化方法:

6.4 交叉开关与仲裁器的联合优化

仲裁器的输出直接驱动交叉开关的选择信号。将两者联合设计可以优化关键路径:

// 联合仲裁+交叉开关
module arbiter_xbar #(
    parameter DATA_WIDTH = 32,
    parameter NUM_PORTS  = 5
)(
    input  logic [DATA_WIDTH-1:0] in_data [0:NUM_PORTS-1],
    input  logic [NUM_PORTS-1:0]  req     [0:NUM_PORTS-1],
    output logic [DATA_WIDTH-1:0] out_data [0:NUM_PORTS-1],
    output logic [NUM_PORTS-1:0]  gnt     [0:NUM_PORTS-1]
);
    // 仲裁+选择一体化: 减少一级MUX延迟
    for (genvar o = 0; o < NUM_PORTS; o++) begin : gen_out
        always_comb begin
            out_data[o] = {DATA_WIDTH{1'b0}};
            gnt[o]      = {NUM_PORTS{1'b0}};
            for (int i = 0; i < NUM_PORTS; i++) begin
                if (req[o][i]) begin
                    out_data[o] = in_data[i];
                    gnt[o][i]   = 1'b1;
                end
            end
        end
    end
endmodule

7. 交叉开关的高级设计技术

在大规模NoC(8×8以上)中,交叉开关成为关键瓶颈。以下高级设计技术可以缓解:

7.1 多播交叉开关

支持一个输入同时连接到多个输出。在广播/多播流量(如一致性消息)中特别有用:

// 多播交叉开关
module multicast_xbar #(
    parameter DATA_WIDTH = 32,
    parameter NUM_PORTS  = 5
)(
    input  logic [DATA_WIDTH-1:0] in_data [0:NUM_PORTS-1],
    input  logic [NUM_PORTS-1:0]  out_en  [0:NUM_PORTS-1], // 每输出的使能
    input  logic [$clog2(NUM_PORTS)-1:0] sel [0:NUM_PORTS-1],
    output logic [DATA_WIDTH-1:0] out_data [0:NUM_PORTS-1]
);
    for (genvar o = 0; o < NUM_PORTS; o++) begin
        assign out_data[o] = out_en[o] ? in_data[sel[o]] : {DATA_WIDTH{1'b0}};
    end
endmodule

7.2 交叉开关的冗余设计

为提高可靠性,可以在交叉开关中添加冗余行/列。当某个交叉点故障时,切换到冗余路径。面积增加10-20%,但可靠性显著提高。

8. 交叉开关的完整设计案例

以下是一个完整的5×5交叉开关设计案例,包含仲裁和选择逻辑:

// 完整5×5交叉开关(含仲裁)
module full_crossbar_5x5 #(
    parameter DATA_WIDTH = 32
)(
    input  logic                  clk, rst_n,
    input  logic [DATA_WIDTH-1:0] in_data  [0:4],
    input  logic [4:0]            in_req   [0:4], // 每输入请求的输出端口
    input  logic                  in_valid [0:4],
    output logic                  in_ready [0:4],
    output logic [DATA_WIDTH-1:0] out_data [0:4],
    output logic                  out_valid[0:4],
    input  logic                  out_ready[0:4]
);
    // 每个输出端口的请求向量
    logic [4:0] out_req [0:4]; // out_req[o][i] = 输入i请求输出o
    logic [4:0] out_gnt [0:4]; // out_gnt[o][i] = 输入i获得输出o

    // 请求转换: in_req[i] → out_req[o]
    always_comb begin
        for (int o = 0; o < 5; o++) begin
            out_req[o] = 5'b0;
            for (int i = 0; i < 5; i++)
                if (in_valid[i] && in_req[i] == o)
                    out_req[o][i] = 1'b1;
        end
    end

    // 每个输出端口的RR仲裁
    for (genvar o = 0; o < 5; o++) begin : gen_arb
        logic [2:0] last_gnt;
        always_ff @(posedge clk or negedge rst_n)
            if (!rst_n) last_gnt <= 0;
            else if (|out_gnt[o]) last_gnt <= last_gnt; // 简化

        // 简化仲裁: 固定优先级
        assign out_gnt[o] = out_req[o] & ~(out_req[o] - 1);
    end

    // 交叉开关连接
    for (genvar o = 0; o < 5; o++) begin : gen_xbar
        always_comb begin
            out_data[o]  = {DATA_WIDTH{1'b0}};
            out_valid[o] = 1'b0;
            for (int i = 0; i < 5; i++) begin
                if (out_gnt[o][i]) begin
                    out_data[o]  = in_data[i];
                    out_valid[o] = in_valid[i];
                end
            end
        end
    end

    // 输入ready(收到gnt且输出ready)
    for (genvar i = 0; i < 5; i++) begin : gen_ready
        always_comb begin
            in_ready[i] = 1'b0;
            for (int o = 0; o < 5; o++)
                if (out_gnt[o][i] && out_ready[o])
                    in_ready[i] = 1'b1;
        end
    end
endmodule

9. 交叉开关的时序优化

交叉开关的时序是路由器频率的关键制约因素:

9.1 时序瓶颈

5×5 32-bit交叉开关的关键路径:仲裁器输出→MUX选择→输出驱动。总计约0.5-0.8ns(16nm工艺)。

9.2 优化方法

9.3 面积-延迟权衡

交叉开关面积 = N² × W × 每bit开关面积。5端口32-bit → 25×32 = 800个开关点。使用MUX实现约1500μm²,使用三态实现约800μm²。

10. 交叉开关的完整综合报告

以下是一个5×5 32-bit交叉开关的完整综合报告:

10.1 面积分解

10.2 功耗分析

动态功耗: 约15μW/MHz(50%翻转率),静态功耗: 约3μW。在1GHz下总功耗约18mW,占路由器功耗的12%。

10.3 优化前后对比

指标优化前优化后(分体+三态)改善
面积2675μm²1800μm²-33%
延迟0.35ns0.25ns-29%
功耗18mW12mW-33%

11. 交叉开关的工业实现

主流商用NoC IP中交叉开关的实现方式:

◀ 上一课 📖 目录 下一课 ▶