设计和实现支持2条虚拟通道的NoC路由器,理解VC分配器、VC切换和死锁避免的完整实现。
虚拟通道路由器在标准路由器基础上增加VC层:每个输入端口有2条独立的FIFO缓冲区,VC分配器决定头flit使用哪条输出VC,开关分配器仲裁物理链路的使用权。
VC分配器将头flit映射到输出端口的某条空闲VC。策略:优先选择空闲VC中缓冲区占用最少的。
// 2-VC路由器输入端口
module vc2_input_port #(
parameter DATA_WIDTH = 32,
parameter NUM_VCS = 2,
parameter DEPTH = 4
)(
input logic clk, rst_n,
input logic [DATA_WIDTH-1:0] in_data,
input logic [$clog2(NUM_VCS)-1:0] in_vc,
input logic in_valid,
output logic in_ready,
output logic [DATA_WIDTH-1:0] out_data,
output logic [$clog2(NUM_VCS)-1:0] out_vc,
output logic out_valid,
input logic out_ready,
output logic [NUM_VCS-1:0] vc_has_pkt,
output logic [NUM_VCS-1:0] vc_full
);
logic [DATA_WIDTH-1:0] vc_buf [0:NUM_VCS-1][0:DEPTH-1];
logic [$clog2(DEPTH):0] vc_wr [0:NUM_VCS-1];
logic [$clog2(DEPTH):0] vc_rd [0:NUM_VCS-1];
logic [NUM_VCS-1:0] vc_empty;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (int v = 0; v < NUM_VCS; v++) begin
vc_wr[v] <= 0;
vc_rd[v] <= 0;
end
end else begin
if (in_valid && in_ready) begin
vc_buf[in_vc][vc_wr[in_vc][$clog2(DEPTH)-1:0]] <= in_data;
vc_wr[in_vc] <= vc_wr[in_vc] + 1;
end
if (out_valid && out_ready)
vc_rd[out_vc] <= vc_rd[out_vc] + 1;
end
end
for (genvar v = 0; v < NUM_VCS; v++) begin : gen_vc
assign vc_empty[v] = (vc_wr[v] == vc_rd[v]);
assign vc_full[v] = (vc_wr[v] == vc_rd[v] + DEPTH);
assign vc_has_pkt[v] = !vc_empty[v];
end
// 输出选择: Round-Robin
always_comb begin
out_data = vc_buf[0][vc_rd[0][$clog2(DEPTH)-1:0]];
out_vc = 0;
out_valid = 1'b0;
for (int v = NUM_VCS-1; v >= 0; v--) begin
if (!vc_empty[v]) begin
out_data = vc_buf[v][vc_rd[v][$clog2(DEPTH)-1:0]];
out_vc = v;
out_valid = 1'b1;
end
end
end
assign in_ready = !vc_full[in_vc];
endmodule
2-VC路由器输入端口通过Verilator验证。
练习1:实现VC分配器(将输入VC映射到输出VC)。
练习2:在4×4 Mesh中集成VC路由器,仿真对比0-VC和2-VC性能。
练习3:实现Duato协议(逃生VC+自适应VC)。
你已掌握VC路由器的完整设计和实现!
设计一个虚拟通道路由器需要系统化的流程:
| 参数 | 典型值 | 范围 |
|---|---|---|
| 端口数 | 5 | 5-7 |
| VC数 | 2 | 2-4 |
| 每VC缓冲深度 | 4 | 2-8 |
| 数据宽度 | 32-64bit | 32-128 |
| 路由算法 | XY+自适应 | 任意 |
| 流控 | 信用 | 信用/ON-OFF |
VC分配器是VC路由器最复杂的组件。它需要解决"哪些输入VC映射到哪些输出VC"的问题:
2-VC路由器的流水线(4阶段):
| 阶段 | 头flit | 体/尾flit |
|---|---|---|
| BW | 写入对应VC缓冲区 | 同 |
| RC+VA | 路由计算+VC分配 | 跳过(沿用) |
| SA | 开关分配 | 同 |
| ST+LT | 交叉开关+链路 | 同 |
在4×4 Mesh中,2-VC路由器相比0-VC路由器的性能提升:
将VC路由器集成到完整NoC中需要解决以下问题:
数据包在不同跳可能使用不同VC。需要在flit中携带VC ID或在链路中添加VC信号线。常见方案:在数据宽度中分配2-3 bit用于VC ID。
VA(VC分配)和SA(开关分配)需要协同工作:
2-VC路由器与0-VC路由器的面积对比(16nm工艺):
| 组件 | 0-VC | 2-VC | 增加 |
|---|---|---|---|
| 输入缓冲 | 5000μm² | 10000μm² | +100% |
| VC分配器 | 0 | 800μm² | +800 |
| 开关分配器 | 500μm² | 700μm² | +40% |
| 交叉开关 | 1500μm² | 1500μm² | 0% |
| 其他 | 1000μm² | 1500μm² | +50% |
| 总计 | 8000μm² | 14500μm² | +81% |
实现VC路由器需要特别注意以下技术细节:
VC分配发生在头flit阶段。关键问题:头flit到达时,可能不知道应该请求哪条输出VC(因为还没完成路由计算)。解决方案:BW+RC在同一阶段完成,VA在下一阶段使用RC的结果。
当数据包从输入VC切换到输出VC时(如VC0→VC1),需要确保信用流控正确:
VC路由器的测试比普通路由器更复杂,需要特别关注VC相关功能:
| 测试用例 | VC0 | VC1 | 验证内容 |
|---|---|---|---|
| T1: 单VC通信 | 活跃 | 空闲 | VC0基本功能 |
| T2: 双VC并发 | 活跃 | 活跃 | VC隔离 |
| T3: VC切换 | →VC1 | ←VC0 | 切换正确性 |
| T4: VC0阻塞 | 满 | 空闲 | VC1不受影响 |
| T5: 逃逸测试 | 满 | →VC0 | 逃逸路径 |
每条VC的信用计数器必须独立正确:
设计VC路由器的推荐流程:
VC路由器的参数化设计可以使用自动化工具:
通过配置文件自动生成VC路由器的Verilog代码:
// 生成配置示例
{
"num_ports": 5,
"num_vcs": 2,
"buffer_depth_per_vc": 4,
"data_width": 32,
"routing": "xy_with_escape",
"arbiter": "round_robin",
"flow_control": "credit",
"pipeline_stages": 3
}
虚拟通道路由器是现代NoC的核心组件。2-VC设计兼顾了性能(吞吐提升40%)和面积(增加约80%)。VC分配器是设计中最复杂的组件,需要仔细处理多输入争用同一输出VC的仲裁。测试时需特别关注VC切换、信用计数和死锁检测。
本课涵盖了NoC设计的核心知识点。以下是关键概念的快速参考:
掌握这些概念是深入理解NoC设计的基础。建议结合Verilog代码实践,加深理解。