片上网络(NoC)深入:拓扑、路由、QoS、死锁与物理实现
更新时间:2026-10-01。当一颗芯片上有十几甚至上百个 CPU 核、GPU 子核、DMA 和 LLC bank(末级缓存分片)时,谁和谁连、按什么规矩传数据,就从「挂条总线」变成了一个独立的工程问题。片上网络(NoC, Network on Chip)把计算机网络的分组交换思想搬到硅片上:数据打成包、逐跳存储转发、路由器分布式仲裁。这一篇把 NoC 片上网络从拓扑、router(路由器)微架构、流控、死锁避免到 QoS(Quality of Service,服务质量)完整讲透。总线时代的背景可先看 片上总线:AMBA AXI/AHB/APB,NoC 正是在它不可扩展之后接棒的。
本文要回答的问题
- mesh、ring、torus 这些拓扑差在哪?为什么多数众核芯片选 mesh?
- 一个 router 内部到底有哪几块电路,一个包穿过它要过几关?
- wormhole(虫洞)交换和 credit(信用)流控怎么配合,虚通道解决什么问题?
- 死锁的四个必要条件是什么,turn model(转向模型)和独立虚网络分别怎么破?
- QoS 怎么在「尽力而为」的网络里给实时和一致性流量留出确定性?
一、从总线到 NoC:共享介质的两次扩展失败
单核时代用总线就够了:AXI 总线一组 master 共享一组线,靠仲裁器决定谁占用,协议简单、延迟低。但总线的吞吐上限是固定的——无论挂几个核,同一时刻只有一对通信方在用线,16 个核时人均带宽只剩 1/16。第一次扩展是交叉开关(crossbar):M 个输入、N 个输出之间各放一个开关点,仲裁器选出互不冲突的配对,可以多对并行通信。可 crossbar 的面积随 M×N 增长,16×16 已很可观,64×64 时开关矩阵和布线占 die 面积超过它连接的核,且所有输入到所有输出的长线让时序根本收不住。
NoC 的做法是放弃「任意两方直连」,改成多跳(multi-hop)分组交换:每个核挂在一个 router 上,router 之间只连邻近的几个,包像城里的快递一样经若干跳到达目的地。线的总数只随节点数线性增长,却靠多条链路并行传输获得聚合带宽。
| 维度 | 共享总线 | 交叉开关 | NoC(mesh 为例) |
|---|---|---|---|
| 链路/开关规模 | O(1) 共享线 | O(M×N) | O(N) 条短链路 |
| 可并行通信对数 | 1 | min(M,N) | 多条链路复用,近似 N |
| 单次通信延迟 | 最低,1 跳仲裁 | 低,1 跳 | 与路径跳数成正比 |
| 适合规模 | 几主几从 | 8–16 端口 | 几十到上百节点 |
| 设计复杂度 | 协议简单 | 仲裁器复杂 | 路由、流控、死锁全套 |
| 典型载体 | MCU、小 SoC | 中规模交换单元 | 众核 CPU/GPU、AI 芯片 |
代价同样明确:远节点要走多跳,每跳引入一拍或多拍延迟;网络开始有拥塞、队头阻塞、死锁这些「真网络」才有的毛病。后面所有节,本质上都在为「用多跳换可扩展性」付这笔利息。
二、拓扑:mesh、ring、torus 与两个性能尺度
拓扑(topology)规定谁和谁物理相连,直接决定两件事:直径(diameter,最远两节点的跳数,影响延迟)和对分带宽(bisection bandwidth,把网络切成对等两半要切断的链路总带宽,影响全网吞吐上限)。
- ring(环):节点首尾相连成环,结构极规整、布线简单,每个节点只有两个口。直径随 N 线性增长,适合十几个以内节点。Intel 不少 QPI/UPI 多槽系统和片上 LLC 环用它,环上还可做 spatial reuse(空间复用):距离足够远的两段环同时传不同包。
- mesh(网格):2D 网格,每个内部 router 有东、南、西、北四个网口加一个本地口。n×n mesh 的直径是 2(n−1),节点数到 64、100 仍可接受,是众核芯片的事实标准。布局天然与 tile(瓦片)化 floorplan 对齐,链路全等长短线。
- torus(环面):mesh 每行每列首尾绕回相连,直径减半,但绕回线很长(从芯片一边跨到另一边),物理实现上要么走线绕远、要么折叠(folded torus),片上用得少,在机柜级互连里更常见。
- 其他:tree/fat-tree(带宽向根部汇聚)、蝴蝶网、以及为 AI 芯片定制的专用拓扑,追求的都是直径与对分带宽在具体流量下的平衡。
这张 3×3 mesh 是理解全篇的底座:每个方块是一个 router,附带一个本地节点(核或 cache bank),线是双向链路。从 R00 发往 R22 的包,按 XY 路由(先 X 后 Y,即先走水平再走竖直)经 R01、R02、R12、R22 共 4 跳;任何包在 mesh 中都不会走回头路,路径长度只由坐标差决定——这是延迟可分析的前提,也是后面死锁证明能用得上的性质。
| 拓扑 | 度数(网口数) | 直径 | 对分链路数 | 物理布线 |
|---|---|---|---|---|
| ring | 2 | N/2 | 2 | 最规整 |
| 2D mesh | 4(加本地口 5) | 2(n−1) | n | 全短线,tile 友好 |
| 2D torus | 4 | 2⌊n/2⌋ | 2n | 绕回长线,代价大 |
| fat-tree | 随层上升 | 2log N | 随层加倍 | 层级布线,片上拥挤 |
三、router 微架构:一个包穿过的四道关
单个 router 是 NoC 全部复杂度的承载体。经典输入排队(input-queued)router 有四组部件,包在一个时钟周期内依次穿过:
- input buffer(输入缓冲):每个网口一组 FIFO,且按虚通道再分成几条独立队列,暂存因下游忙而走不了的 flit(flow control digit,流控 digit,包被切片后的最小传输单位)。
- route computation(路由计算,RC):头 flit 根据目的地址查路由算法,算出输出口,XY 路由下就是两次坐标比较。
- VC allocator(虚通道分配,VA)+ switch allocator(开关分配,SA):两级仲裁——先为头 flit 在输出口抢一条虚通道,再为所有就绪 flit 抢本拍的 crossbar 时段。这是 router 里最难做时序的逻辑。
- crossbar(交叉开关矩阵):把赢得仲裁的输入口连通到输出口,每拍一组配对。
读图时抓住「缓冲—决策—开关」三段:缓冲只在输入侧(输出排队型 router 面积大,片上少用);决策分路由计算和两级仲裁,头 flit 做完全套、后续 flit 沿已建立的「虚电路」只参与 SA;crossbar 本身是纯开关、不存状态。四级流水让 header(头)、body(体)、tail(尾)flit 在不同 router 中重叠前行,这正是虫洞名字的由来。虚通道(virtual channel, VC)是给同一条物理链路配多套独立缓冲和状态位:一个包占住 VC0 等下游时,别的包可以走 VC1,链路不被一个堵点独占——它治的是队头阻塞(HoL blocking),不是物理冲突,同一拍 crossbar 仍只过一个 flit。
四、wormhole 交换与 credit 流控
三种交换方式的差别在「缓冲多大、何时放行」。存储转发(store-and-forward)要求收完整个包才向下游发,缓冲要装下整包,延迟 = 跳数 × 包长;虚切通(virtual cut-through)允许整包转发但途中可缓存整包;wormhole 把包切成 flit,头 flit 建好路径后 body 紧跟,每跳只需缓存几个 flit,无阻塞时延迟近似「跳数 + 包长」拍而非两者相乘——代价是头被堵住时整条「虫」瘫在沿途多个 router 的缓冲里,这正是死锁的温床。
下游用什么方式告诉上游「还能收」?credit 流控:接收方每释放一个 flit 缓冲,就回送一个 credit;发送方为每条 VC 维护信用计数器,发一个 flit 减一、收一个 credit 加一,计数器为零就停发。相比 on/off 水位线,credit 粒度细、缓冲利用率高,代价是反向 credit 线和计数器。
a: "Router A\nVC0 credit=3"
link: "链路"
b: "Router B\nVC0 空闲槽=3"
f1: "flit1 发出\ncredit 3→2"
f2: "B 取走 flit1\n释放 1 槽"
f3: "credit 回送\nA credit 2→3"
note3: "信用为零即停发,绝不溢出\n反向 credit 环也是链路的一部分\n断 credit 等于断网"
a -> link
link -> b
a -> f1: {style.stroke-dash: 4}
f1 -> f2: {style.stroke-dash: 4}
f2 -> f3: {style.stroke-dash: 4}
f3 -> a: {style.stroke-dash: 4}
b -> note3: {style.stroke-dash: 4}
note3.style: {stroke-dash: 4}这张图展示的闭环每个周期都在每条 VC 上发生:正向 flit、反向 credit,缓冲槽位的所有权在两端之间精确流转。FIFO 深度与水位设计方法可参考 FIFO 深度设计,NoC 的不同在于深度要按「下游反压时延 × 注入速率」逐 VC 算,配少了吞吐塌陷,配多了面积浪费。
五、死锁:四个必要条件与两条破解路线
虫洞网络里死锁(deadlock)的剧本很经典:四个包各占一个 router 的缓冲、又各自申请下一个,申请关系首尾成环,谁都动不了。它对应操作系统里的 Coffman 四条件:互斥占用、不可抢占、持有并等待、循环等待。缓冲被独占、不能强抢、包持有槽位等新槽位——前三个条件在 wormhole 网络里天然成立,所以设计只能从第四条「循环等待」下手,让通道资源的占用图里根本不存在环。
路线一是路由限制,即 turn model:把路由允许的转向(东→北、西→南等八类转向)禁掉至少一类,使通道依赖图无环。XY 路由禁掉一切「先竖后横」,最死板也最易证明;west-first 禁止所有向西相关的转向后允许一定自适应;odd-even 按列奇偶限制转向,路径选择更多。它们的共同点是:无死锁是数学性质,靠证明而非仿真兜底。
路线二是虚网络(virtual network)/逃逸通道(escape VC):把 VC 划成互不混占的资源类,请求包和响应包、不同协议通道各自走独立虚网络,依赖关系跨不成环;或保留一条按无环路由转发的 escape VC,任何被自适应路由堵住的包都能退到它上面排空,环中一旦有包能走,整个死锁就解开了。CHI 等缓存一致性协议的 request/response/snoop 三类消息天然要求分开的虚网络,否则协议层就可能构造出环。
还要区分活锁(livelock):包没被堵死,却因自适应路由反复改道、绕着目的地打转永远到不了。自适应路由只要保证「已用过的输出口不再选」或让偏转的包优先级递增即可破除;最小路由(只走缩短距离的口)则天然无活锁。
| 问题 | 现象 | 根因 | 标准解法 |
|---|---|---|---|
| 队头阻塞 | 一个包堵口,后面无关包全等 | 单队列共享 | 多条虚通道 |
| 死锁 | 包群永久停滞、缓冲环满 | 通道依赖成环 | turn model / 逃逸 VC |
| 活锁 | 包在动但永不到达 | 偏转路由不收敛 | 最小路由或偏转计数 |
| 饥饿 | 某口长期抢不到 crossbar | 仲裁器偏心 | round-robin 分配器 |
六、QoS:在尽力而为网络里造确定性
默认 NoC 是尽力而为的:延迟随拥塞浮动。但片上有三类流量等不起——实时音视频 DMA 要延迟上界,缓存一致性 snoop(侦听)要低延迟否则所有核停等,中断和 Q-Channel 这类控制消息丢不得。QoS 靠三个层次叠加实现:
- 优先级(priority):flit 带 class/优先级字段,SA 仲裁时高优先级先赢。实现最简单,但纯固定优先级会饿死低优先级,实际多与 aging(等待越久优先级越高)结合。
- 带宽保证:为某类流量预留 VC 并在分配器里做加权轮询(WRR)或时分槽位,保证长期份额,如给显示 DMA 保底每毫秒 N 拍。
- 延迟/时延上界:最硬的保证要靠独立虚网络加专属缓冲和连接建立(接近电路交换),成本高,只给真正关键的流。
这张图点破一个设计巧合:QoS 用的虚网络和死锁避免用的 VC 是同一套硬件,区别只在划分规则。因此 VC 数量是架构早期就要锁死的参数——每加一类服务或一个协议消息类,缓冲面积就涨一截,事后补 VC 等于重做 router。仲裁器本身的公平性验证可对照 仲裁器验证:round-robin 与优先级仲裁器的公平性、无饥饿端到端验法,NoC 的 SA 本质上就是多口版的同类电路。
七、性能尺度与物理实现:延迟、吞吐、热点、GALS
评估 NoC 看两组数。零负载延迟(zero-load latency):无竞争时单程 = 每跳流水线级数 × 跳数加序列化拍数,mesh 上对角路径最重。饱和吞吐(saturation throughput):注入率逐步抬高,平均延迟在某个注入率(约 0.3–0.6 flit/节点/拍,取决于流量模式)开始发散,该拐点就是容量。均匀随机流量下数字漂亮没用,真实 SoC 几乎都是非均匀的:所有核都频繁访问某几个 LLC bank,热点(hotspot)router 先饱和,而相邻链路被它牵连反压,拥塞成片蔓延。
工程上三招:地址交织(interleave)把 cache bank 访问打散,思路同 memory banking 与 interleaving;架构早期用流量模型(每类 master 的注入率、目的分布)做 NoC 仿真找热点,而不是等 RTL 就绪;对已知热点局部加链路或加宽通道。
物理侧的约束同样硬。router 必须落在 tile 内、与所连核一起 floorplan,链路长度才能保持等长短线;跨 die 尺寸的「逻辑相邻」(torus 绕回)直接被否决。大规模设计常用 GALS(Globally Asynchronous Locally Synchronous,全局异步局部同步):每个 tile 或一片区域跑自己的时钟,router 网口处放异步 FIFO 跨时钟域,省掉全局时钟树功耗也避开频率互相牵制,CDC 处理方法见 时钟与复位架构、异步与跨时钟域。
| 权衡维度 | 往「性能」端推 | 往「成本」端推 |
|---|---|---|
| 拓扑 | torus/高维、对分带宽大 | ring、mesh 基础型 |
| VC 数 | 类多、HoL 轻、QoS 细 | 2–4 条,省缓冲面积 |
| buffer 深度 | 深、抗突发 | 浅、按 credit 环精算 |
| 流水分级 | 多级、主频高 | 少级、单跳延迟低 |
| 时钟 | 全局同步、简单 | GALS、省电易收敛 |
八、常见坑
- VC 划分与路由算法不匹配:逃逸 VC 自身也允许了成环转向,死锁避免形同虚设——逃逸路径必须单独按无环证明。
- 只验均匀流量:均匀随机注入下拐点很好看,LLC 热点流量实际一跑提前 30% 饱和,流量模型必须带地址分布。
- credit 环复位不同步:上下游复位释放错开导致信用计数初值不一致,表现为随机丢 flit 或缓冲虚假占满。
- 低优先级被静默饿死:纯优先级仲裁长期压死背景流量,aging 或 WRR 保底缺一不可。
- 忽视在途「虫」的跨 router 占用:反压突发时一条长包瘫在四五个 router 里,级联占满多片缓冲,分析拥塞要按路径而非单节点。
- 逻辑拓扑脱离 floorplan:架构定了 torus/长绕回,物理阶段才发现线跨 die,被迫返工拓扑。
- 把活锁当死锁排查:缓冲没环、包一直在转发却不到达,根因在偏转策略不收敛,破环解法无效。
这一篇在知识体系里的位置
- 向上承接:片上总线:AMBA AXI/AHB/APB 说明 NoC 取代的共享介质前辈,RISC-V 多核 SoC 集成 给出 NoC 在真实 SoC 中的集成语境。
- 电路细节:时钟与复位架构、异步与跨时钟域 支撑 GALS/CDC,FIFO 深度设计 支撑 credit 与缓冲深度计算。
- 验证方法:仲裁器验证:round-robin 与优先级仲裁器的公平性、无饥饿端到端验法 适用于 VA/SA 两级分配器。
- 向后延伸:NoC 跨出 die 边界就是 die-to-die 互连,见 Chiplet/UCIe 2.5D 互连;AI 芯片的专用互连见 AI 加速器与脉动阵列。
总结
NoC 片上网络用多跳分组交换换掉不可扩展的总线与交叉开关:性能由拓扑(mesh 的直径与对分带宽)、router 微架构(输入缓冲、两级分配器、crossbar)、wormhole 加 credit 流控共同决定,正确性靠虚通道破队头阻塞、turn model 与逃逸虚网络斩断通道依赖环、最小路由消除活锁,QoS 则复用同一套 VC 机制以优先级、带宽份额和预留槽位给实时与一致性流量提供确定性——再与 floorplan、GALS 和热点流量模型协同,才算一颗大芯片的互连真正落地。