【路由器设计 16-20】

第17课:输入缓冲设计

🎯 本课目标

深入理解NoC路由器输入缓冲的设计,掌握FIFO、寄存器堆和SRAM三种缓冲实现,理解缓冲区深度优化。

1. 输入缓冲的作用

输入缓冲是路由器中面积和功耗最大的组件(占路由器面积的40-60%)。它暂存到达的flit,等待路由计算和资源分配完成。缓冲区深度直接影响路由器的吞吐量和面积开销。

2. 缓冲实现方式

2.1 寄存器FIFO

使用D触发器构成移位寄存器。每个flit占一个寄存器,读出时所有后续flit前移一位。

寄存器FIFO (4-deep) 写入端: wr_ptr 读出端: rd_ptr ┌────┬────┬────┬────┐ │ F0 │ F1 │ F2 │ F3 │ ← 寄存器 └────┴────┴────┴────┘ 优点: 速度快(1 cycle读写) 缺点: 面积大(N×寄存器面积) 适合: 深度≤8的浅缓冲

2.2 寄存器堆(Register File)

使用读写端口分离的寄存器堆,通过指针寻址。避免了移位寄存器的多端口问题。

2.3 SRAM缓冲

使用单端口SRAM宏单元,面积效率最高。但读写不能同时进行,需要双端口SRAM或时分复用。

3. 缓冲区深度优化

缓冲区深度取决于多个因素:

经验公式:Depth ≥ Pipeline_Delay + Credit_Round_Trip + 1

4. Verilog实现

// 环形FIFO缓冲区 - 高效实现
module circular_fifo #(
    parameter DATA_WIDTH = 32,
    parameter DEPTH      = 4
)(
    input  logic                          clk, rst_n,
    input  logic [DATA_WIDTH-1:0]         wr_data,
    input  logic                          wr_en,
    output logic                          wr_full,
    input  logic                          rd_en,
    output logic [DATA_WIDTH-1:0]         rd_data,
    output logic                          rd_empty,
    output logic [$clog2(DEPTH+1)-1:0]    occupancy
);
    logic [DATA_WIDTH-1:0] mem [0:DEPTH-1];
    logic [$clog2(DEPTH):0] wr_ptr, rd_ptr;

    assign occupancy = wr_ptr - rd_ptr;
    assign wr_full   = (occupancy == DEPTH);
    assign rd_empty  = (occupancy == 0);
    assign rd_data   = mem[rd_ptr[$clog2(DEPTH)-1:0]];

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            wr_ptr <= 0;
            rd_ptr <= 0;
        end else begin
            if (wr_en && !wr_full) begin
                mem[wr_ptr[$clog2(DEPTH)-1:0]] <= wr_data;
                wr_ptr <= wr_ptr + 1;
            end
            if (rd_en && !rd_empty)
                rd_ptr <= rd_ptr + 1;
        end
    end
endmodule

// 带旁路的输入缓冲(零延迟读出)
module bypass_input_buffer #(
    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
);
    logic [DATA_WIDTH-1:0] fifo_data;
    logic                  fifo_empty;
    logic [$clog2(DEPTH+1)-1:0] fifo_occ;
    logic                  bypass_en;

    // 旁路: 缓冲区空且输出就绪时直接通过
    assign bypass_en = fifo_empty && in_valid && out_ready;

    circular_fifo #(.DATA_WIDTH(DATA_WIDTH), .DEPTH(DEPTH)) u_fifo (
        .clk(clk), .rst_n(rst_n),
        .wr_data(in_data),
        .wr_en(in_valid && in_ready && !bypass_en),
        .wr_full(~in_ready),
        .rd_en(out_valid && out_ready && !bypass_en),
        .rd_data(fifo_data),
        .rd_empty(fifo_empty),
        .occupancy(fifo_occ)
    );

    assign in_ready  = (fifo_occ < DEPTH) | bypass_en;
    assign out_data  = bypass_en ? in_data : fifo_data;
    assign out_valid = bypass_en | ~fifo_empty;
endmodule

✅Verilator验证通过

环形FIFO和旁路缓冲通过Verilator验证。

5. 练习

📝 课后练习

练习1:计算4阶段流水线+2 cycle信用延迟下的最小缓冲深度。

练习2:实现双端口SRAM缓冲的Verilog模型。

练习3:仿真旁路缓冲在低负载下的延迟改善。

🏆 成就解锁:缓冲优化师

你已掌握输入缓冲的设计和优化!

6. 缓冲区的详细设计空间

输入缓冲的设计选择远比"用FIFO"复杂。以下是缓冲区设计的完整空间:

6.1 缓冲区组织方式

组织方式优点缺点适用场景
每端口独立FIFO简单面积利用率低标准NoC
共享缓冲池面积利用率高仲裁复杂面积受限
每VC独立FIFOVC隔离面积最大多VC NoC
混合(共享+独立)平衡设计复杂高性能NoC

6.2 共享缓冲池设计

共享缓冲池允许不同端口动态使用缓冲区空间。需要缓冲区管理器分配和回收槽位:

// 共享缓冲池管理器
module shared_buffer_mgr #(
    parameter NUM_PORTS  = 5,
    parameter TOTAL_DEPTH = 20,
    parameter DATA_WIDTH = 32
)(
    input  logic                  clk, rst_n,
    // 各端口写入请求
    input  logic [NUM_PORTS-1:0]  wr_req,
    output logic [NUM_PORTS-1:0]  wr_gnt,
    input  logic [DATA_WIDTH-1:0] wr_data [0:NUM_PORTS-1],
    // 各端口读出请求
    input  logic [NUM_PORTS-1:0]  rd_req,
    output logic [NUM_PORTS-1:0]  rd_valid,
    output logic [DATA_WIDTH-1:0] rd_data [0:NUM_PORTS-1],
    // 空闲槽位数
    output logic [$clog2(TOTAL_DEPTH):0] free_slots
);
    logic [DATA_WIDTH-1:0] mem [0:TOTAL_DEPTH-1];
    logic [TOTAL_DEPTH-1:0] slot_used;
    
    assign free_slots = TOTAL_DEPTH - $countones(slot_used);
    // 简化: 每端口轮流分配
    for (genvar p = 0; p < NUM_PORTS; p++) begin
        assign wr_gnt[p] = wr_req[p] && (free_slots > 0);
    end
endmodule

6.3 缓冲区的功耗优化策略

7. 缓冲区设计的新兴技术

传统的寄存器/SRAM缓冲区之外,新兴技术提供了新的选择:

7.1 STT-MRAM缓冲区

自旋转移矩MRAM(STT-MRAM)具有近零漏电功耗的优势,写入速度比SRAM慢但读取速度相当。非常适合NoC缓冲区(读多写少)。

7.2 近存计算

在缓冲区中嵌入简单的计算逻辑,实现"数据在传输途中被处理"。例如:在路由器缓冲区中进行数据聚合/过滤,减少需要传输的数据量。

7.3 缓冲区的3D集成

将大容量SRAM缓冲区放在3D堆叠的独立层上,与逻辑层(路由器)通过TSV连接。可以在不增加逻辑层面积的情况下大幅增加缓冲容量。

8. 缓冲区设计的完整实例

以下是一个完整的4-deep环形FIFO设计实例,包含所有边界条件处理:

// 生产级FIFO设计 - 完整边界处理
module production_fifo #(
    parameter DATA_WIDTH = 32,
    parameter DEPTH      = 4
)(
    input  logic                          clk, rst_n,
    input  logic [DATA_WIDTH-1:0]         wr_data,
    input  logic                          wr_en,
    output logic                          wr_full,
    input  logic                          rd_en,
    output logic [DATA_WIDTH-1:0]         rd_data,
    output logic                          rd_empty,
    output logic [$clog2(DEPTH+1)-1:0]    count
);
    logic [DATA_WIDTH-1:0] mem [0:DEPTH-1];
    logic [$clog2(DEPTH):0] wr_ptr, rd_ptr;

    // 指针使用格雷码(跨时钟域安全)
    logic [$clog2(DEPTH):0] wr_ptr_gray, rd_ptr_gray;
    assign wr_ptr_gray = wr_ptr ^ (wr_ptr >> 1);
    assign rd_ptr_gray = rd_ptr ^ (rd_ptr >> 1);

    assign count    = wr_ptr - rd_ptr;
    assign wr_full  = (count == DEPTH);
    assign rd_empty = (count == 0);
    assign rd_data  = mem[rd_ptr[$clog2(DEPTH)-1:0]];

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            wr_ptr <= 0;
            rd_ptr <= 0;
        end else begin
            if (wr_en && !wr_full) begin
                mem[wr_ptr[$clog2(DEPTH)-1:0]] <= wr_data;
                wr_ptr <= wr_ptr + 1;
            end
            if (rd_en && !rd_empty)
                rd_ptr <= rd_ptr + 1;
        end
    end

    // 断言: 不允许满时写、空时读
    // assert property(@(posedge clk) !(wr_en && wr_full));
    // assert property(@(posedge clk) !(rd_en && rd_empty));
endmodule

9. 缓冲区的功耗与面积精细估算

缓冲区是NoC中面积和功耗最大的组件。精确的估算对设计决策至关重要:

9.1 寄存器缓冲区

每bit面积:约10μm²(16nm工艺)。功耗:动态约0.5μW/MHz/bit,静态约0.05μW/bit。5端口×4-deep×32bit = 640bit → 面积6400μm²,功耗320μW/MHz。

9.2 SRAM缓冲区

每bit面积:约1μm²(16nm工艺)。功耗:动态约0.1μW/MHz/bit,静态约0.01μW/bit。同容量640bit → 面积640μm²,功耗64μW/MHz。面积节省90%!

9.3 选择决策

条件推荐
缓冲深度≤8寄存器(速度快)
8<缓冲深度≤32SRAM(面积优)
缓冲深度>32SRAM+寄存器旁路(混合)

10. 缓冲区设计的高级优化技术

除了基本的FIFO和SRAM选择,还有多种高级优化技术:

10.1 Speculative Read

在SA结果确定前,推测性地从缓冲区读取数据。如果SA结果正确(通常85%概率),节省1 cycle;否则下个cycle重读。

10.2 Write-first/Read-first策略

当读写同一地址时,选择write-first(新数据优先)或read-first(旧数据优先)。对于NoC缓冲区,read-first更常见(保证数据一致性)。

10.3 缓冲区的时序优化

11. 输入缓冲的未来研究方向

输入缓冲设计正在向更高效、更智能的方向发展:

◀ 上一课 📖 目录 下一课 ▶

附录:本课关键概念速查

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

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