3. 硬件循环基础

在深入NPU(神经网络处理单元)的微架构之前,我们必须先建立对“循环”这一核心概念的清晰认知。无论是CPU、GPU还是NPU,循环都是程序执行的基本骨架;但在NPU中,循环的形态、粒度与硬件耦合方式发生了根本性变化。本章将拆解硬件循环的本质、它在NPU数据流架构中的战略地位,以及它与指令流水线之间的协作关系,为后续学习脉动阵列、数据复用和存储层次打下基础。

NPU硬件循环与指令执行关系图 指令流 (标量/向量指令) 指令解码 (标量核/控制核) 循环配置 (循环边界/步长/嵌套) 写入循环缓冲寄存器 循环缓冲 (Loop Buffer) 硬件循环引擎 (Hardware Loop Engine) 循环计数器 (迭代计数) 边界比较器 (终止条件) 数据地址生成器 (DAG: 自动生成访存地址) 循环体指令 (Loop Body) 数据流执行单元 (MAC阵列/向量单元/累加器) 片上存储层次 (SRAM/寄存器文件/双缓冲) 数据流模式 (权重固定/输入固定/输出固定) 硬件循环引擎替代软件分支判断, 每周期自动完成计数、比较与跳转

3.1 核心原理:从软件循环到硬件循环的范式转移

在传统冯·诺依曼架构中,循环由软件实现:CPU读取指令、比较计数器、执行条件跳转、更新循环变量。每条指令都需要经过取指、译码、执行、访存、写回等流水级,循环开销(loop overhead)在每次迭代中都会消耗多个时钟周期。对于神经网络计算而言,卷积层、全连接层、池化层本质上都是嵌套循环——例如一个3×3卷积在特征图上的滑动,对应着输出通道、输入通道、行、列、卷积核行、卷积核列共六层循环。如果这些循环全部由软件指令驱动,指令带宽将成为不可逾越的性能瓶颈。

硬件循环(Hardware Loop)的核心思想是:将循环的控制逻辑(计数器、边界比较、跳转决策)从指令流中剥离,固化到专用的硬件状态机中。NPU在执行循环体时,不需要反复取指和译码循环控制指令,而是由硬件循环引擎直接驱动数据通路。循环的边界、步长、嵌套层级在循环开始前一次性配置到循环缓冲寄存器中,之后每个时钟周期硬件自动完成“计数+比较+跳转”的操作,零额外开销。

这种设计带来的直接收益是:指令带宽被释放。NPU的指令带宽是稀缺资源,通常只有几十到几百字节每周期。如果循环控制指令占据指令流的30%以上,那么真正用于描述计算操作的指令(如MAC指令、数据搬运指令)就会被挤占。硬件循环将这部分开销降为零,让指令流几乎全部用于描述“做什么计算”而非“如何控制循环”。

关键区别:软件循环是“指令驱动”的——每条循环指令都要经过完整的流水线;硬件循环是“配置驱动”的——循环参数配置完成后,硬件自动运行,无需额外指令。在NPU中,循环体内部的指令仍然由指令流提供,但循环的“骨架”由硬件承担。

3.2 循环在NPU中的作用:数据复用与计算效率的基石

NPU的性能公式可以简化为:实际算力 = 峰值算力 × 计算效率。计算效率取决于数据能否及时供给到MAC阵列。如果数据从DRAM搬运到片上SRAM的速度跟不上计算速度,MAC阵列就会空转等待,造成“数据饥饿”。循环结构直接决定了数据复用的机会。

以卷积计算为例,一个输入特征图的像素会被多个输出通道的卷积核复用。如果循环顺序设计为“输出通道在外层,输入通道在内层”,那么同一个输入像素可以被加载一次,供多个输出通道使用,从而将数据搬运量减少数倍。这就是数据复用(Data Reuse)的核心逻辑。NPU的循环架构通常支持三种数据流模式:

数据流模式 循环组织方式 复用对象 典型应用场景
权重固定(Weight Stationary) 权重加载到MAC阵列后保持不变,输入数据循环流动 权重复用 全连接层、小卷积核
输入固定(Input Stationary) 输入特征图驻留在寄存器中,权重循环加载 输入激活复用 大卷积核、深度可分离卷积
输出固定(Output Stationary) 部分和累加器驻留在MAC阵列中,输入和权重循环流入 部分和复用 残差网络、多通道累加

循环的嵌套顺序还决定了片上存储的容量需求。如果循环的“最内层”需要的数据量超过SRAM容量,就会发生数据溢出,被迫反复访问DRAM,性能急剧下降。因此,NPU的循环调度器(Loop Scheduler)需要根据SRAM容量、MAC阵列规模、数据依赖关系,自动选择最优的循环分块(Loop Tiling)策略。例如,将大循环拆分为多个小循环块,每个块的数据量恰好能放入片上SRAM,这就是“循环分块”技术。

3.3 循环与指令执行的关系:配置-执行-回写三阶段

在NPU中,循环与指令执行的关系可以概括为“一次配置,多次执行,硬件自循环”。具体流程如下:

  1. 配置阶段:标量核(Scalar Core)或控制核(Control Core)执行循环配置指令,将循环的起始值、终止值、步长、嵌套层级写入循环缓冲寄存器。这一阶段通常需要几十个周期,但只执行一次。
  2. 执行阶段:硬件循环引擎接管控制权。每个时钟周期,循环计数器自动递增,边界比较器判断是否达到终止条件。若未终止,则向数据通路发送“有效”信号,驱动MAC阵列或向量单元执行循环体中的计算指令。循环体指令本身仍然来自指令缓存,但指令地址由硬件循环引擎生成,而非程序计数器(PC)顺序递增。
  3. 回写阶段:当所有循环迭代完成后,硬件循环引擎发出“循环结束”信号,通知标量核继续执行后续指令。部分NPU还支持“循环级流水”,即前一个循环的尾部迭代与后一个循环的头部迭代重叠执行,进一步隐藏循环切换开销。

这种设计使得NPU的指令执行呈现出“粗粒度指令流,细粒度数据流”的特征。指令流中的每条指令描述的是一个完整的循环块(Loop Block),而非单次计算。例如,一条指令可能表示“执行3×3卷积,输出通道64,输入通道64,特征图尺寸32×32”,而硬件循环引擎负责将这个指令展开为成千上万次MAC操作。

经验提示:在阅读NPU汇编代码或调度日志时,注意区分“循环配置指令”和“循环体指令”。循环配置指令通常带有立即数(如循环边界),而循环体指令则是对计算单元的抽象描述。调试时,优先检查循环配置是否正确,因为配置错误会导致整个循环块执行异常。

3.4 案例拆解:一个3×3卷积的硬件循环实现

假设我们要在NPU上执行一个3×3卷积,输入特征图尺寸为32×32×64(高×宽×通道),输出通道数为128,步长为1,padding为1。这个计算在软件层面是六层嵌套循环,但在NPU中,它被组织为多个硬件循环块。

初始目标:在MAC阵列为16×16、片上SRAM为512KB的NPU上,实现该卷积层,要求计算效率不低于80%。

循环分块策略:

  • 输出通道分块:输出通道128个,MAC阵列一次可处理16个输出通道,因此分为8个块(128/16=8)。外层循环块数=8。
  • 输入通道分块:输入通道64个,每个输出通道需要累加64个输入通道的乘加结果。MAC阵列的输入带宽限制为每次加载16个输入通道,因此内层循环块数=4(64/16=4)。
  • 空间维度分块:特征图32×32,SRAM容量允许一次加载8行数据(包括padding),因此空间分块为4×4个块。

硬件循环配置示例:

// 伪代码:硬件循环配置
CONFIG_LOOP(loop_id=0, start=0, end=8, step=1);   // 输出通道块循环
CONFIG_LOOP(loop_id=1, start=0, end=4, step=1);   // 输入通道块循环
CONFIG_LOOP(loop_id=2, start=0, end=4, step=1);   // 行块循环
CONFIG_LOOP(loop_id=3, start=0, end=4, step=1);   // 列块循环
CONFIG_LOOP(loop_id=4, start=0, end=3, step=1);   // 卷积核行循环
CONFIG_LOOP(loop_id=5, start=0, end=3, step=1);   // 卷积核列循环
// 循环体指令:MAC操作
MAC_LOOP_BODY(src_a=SRAM_ADDR_1, src_b=SRAM_ADDR_2, dst=ACCUMULATOR);

执行过程分析:硬件循环引擎按照loop_id从外到内的顺序执行。最外层循环每迭代一次,加载一组输出通道对应的权重到MAC阵列;第二层循环每迭代一次,加载一组输入通道的特征图数据;空间循环控制特征图在SRAM中的滑动窗口。整个过程中,指令流只执行了一次循环配置指令和一次循环体指令,但硬件循环引擎自动完成了8×4×4×4×3×3=4608次迭代。

结果对比:如果采用纯软件循环,每次迭代需要至少3条指令(计数器更新、比较、跳转),总共需要约13824条额外指令。而硬件循环将这部分开销降为零。实际测试中,该卷积层的计算效率从软件循环的52%提升到硬件循环的87%,主要收益来自指令带宽释放和数据复用优化。

风险与代价:硬件循环的代价是灵活性降低。循环边界必须是编译期可确定的常数,无法支持动态循环(如循环次数依赖运行时数据)。此外,循环嵌套层级受硬件寄存器数量限制,通常最多支持8-16层嵌套。对于不规则循环(如稀疏卷积),需要软件进行预处理,将其转换为规则循环。

3.5 常见误区与总结复盘

误区一:认为硬件循环只是“循环展开”的硬件版本。循环展开(Loop Unrolling)是软件优化手段,通过复制循环体减少跳转次数;而硬件循环是控制机制的转移,循环体本身不复制,只是控制逻辑由硬件承担。两者可以结合使用,但本质不同。

误区二:忽视循环分块对性能的影响。很多初学者认为只要配置了硬件循环,性能就会自动提升。实际上,循环分块的大小直接决定了数据复用率。如果分块过大,数据溢出到DRAM;分块过小,复用率不足。需要根据SRAM容量和MAC阵列规模进行精确计算。

误区三:混淆循环配置指令与循环体指令的时序。循环配置指令必须在循环体指令之前执行,且配置完成后不能随意修改。在调试时,如果发现循环执行结果异常,首先检查配置指令的寄存器地址和立即数是否正确。

风险提醒:硬件循环引擎在遇到“循环体内包含数据依赖”时可能产生流水线停顿。例如,如果循环体中的计算需要用到上一次迭代的结果(循环携带依赖),硬件循环引擎必须插入等待周期。在设计循环结构时,应尽量将依赖放在循环体外,或使用双缓冲技术隐藏依赖延迟。