
1. 从项目名说起为什么 AI 芯片的设计绕不开“软硬件一起做”这两年只要聊到 AI 算力基本绕不开芯片。但很多人一听到“AI 芯片软硬件设计”这个标题脑子里第一反应可能是“不就是设计一颗芯片吗”实际上远没这么简单。真正把一颗 AI 芯片从概念推到量产软件和硬件的耦合程度高到超乎想象——这不是简单的“硬件造出来、软件去适配”而是从架构定义的第一天开始两边的人就得坐在一起把算法、编译器、驱动、硬件流水线全部对齐。我参与过几款边缘侧 AI 芯片的完整设计流程坦白讲最难的从来不是某个加速器模块本身而是“这颗芯片到底要跑什么样的模型、以什么样的精度跑、软件栈能不能把硬件吃透”。换句话说硬件只是骨架真正让芯片有灵魂的是软件工具链。这个项目标题里的“软硬件设计”五个字本质上点出了一种协同设计的思路HW/SW Co-Design。展开之前先说明一下这篇文章覆盖的主要内容包括AI 芯片设计的前期需求拆解搞清楚要服务的模型类型、算子构成、精度需求、功耗约束硬件架构的关键模块MAC 阵列、片上存储、数据通路、低功耗策略这些模块为什么长这样软件栈的核心构成编译器、算子库、运行时 runtime、量化工具、仿真器软硬件协同的具体工作流从模型到仿真的完整设计链条怎么打通真实工程中容易踩的坑性能仿真误差、精度回调、总线瓶颈、验证遗漏等。适合的读者芯片设计工程师、AI 算法工程师、做边缘计算平台的同学以及想入门 AI 芯片方向的在校研究生。有算法背景但不懂硬件的人也能读我会尽量把复杂概念讲得像搭积木一样清楚。2. 软硬件协同设计核心思路与设计空间探索2.1 为什么纯硬件思维做不出好 AI 芯片先讲一个我自己观察到的现象很多团队做 AI 芯片一上来就喜欢堆算力把 MAC乘累加阵列做得巨大无比INT8 可以跑到几十 TOPS数字上很漂亮。但等芯片回片以后跑一个 MobileNet 或 YOLO 系列模型帧率死活达不到预期。问题出在哪访存瓶颈。AI 推理有个很核心的特点算力密度高但数据复用性差异大。卷积操作虽然可以在行、列方向上做输入或权重复用但每一次从 DRAM 搬运大量数据都要消耗能量和时间。业界有个经常引用的数据一次 DRAM 访问的能量开销可能是 MAC 运算的几个数量级。如果片上 SRAM 容量不足、存调策略不合理哪怕算力再强也会被“喂不饱数据”卡住。所以真正的设计起点不是“我要做一颗 100 TOPS 的芯片”而是先问这个芯片的典型工作负载是什么面向边缘侧还是数据中心要跑多少路视频流模型更新的频率是什么样子语言模型、卷积模型还是 Transformer 结构占主导这些问题决定了 MAC 阵列的规模、片上存储的层次、甚至外部存储接口的带宽。顺带提一句现在很多设计团队开始在主控 CPU 之外加入专用的 AI 加速子系统比如常见的CPU NPU或CPU DSP NPU的异构架构。NPU 承担重计算任务CPU 负责调度和通用逻辑控制两边通过共享内存或高速总线通信。这既保证了灵活性又能在能效比上拉开差距。2.2 架构定义不是拍脑袋设计空间探索怎么做软硬件协同设计的第一步是把算法模型的算子级特征梳理出来。常规做法是这样的跑一组代表性的模型打开 profiler比如 PyTorch 的性能分析工具统计各算子的耗时占比、访存量、内存占用、并行度。得到一张算子分布表比如卷积/全连接类算子可能占 70% 左右的计算量激活函数、池化、Normalization 等元素级算子计算量不大但数量多Transformer 结构中还会有大量的矩阵乘、Softmax、LayerNorm、多头注意力里的 reshape / transpose 变换。得到这些数据后团队会做一轮架构探索通常用一个高层的性能模型performance model来做。它的核心逻辑是把硬件参数如 MAC 数量、频率、SRAM 容量、DMA 带宽和算法特征算子类型、张量形状、重复调用次数建模估计每一层的耗时和能效。通过改参数、跑反馈、再调整的方式架构师才能确定具体实现规模。这个性能模型有点像“搭积木之前先画堆叠图”——不用等 RTL 写出来就知道哪些配置可能合理。常见架构探索维度包括MAC 阵列的规模和排布方式通常有1D、2D脉动阵列、N*N二维栅格数据精度组合FP32、FP16、BF16、INT8、混合精度片上存储容量分配是偏向输入激活缓存还是偏向权重复用数据流方式权值固定Weight Stationary、输入固定Input Stationary、输出固定Output Stationary。这些名词看起来有点多实际理解也不复杂。权值固定类似“把一摞菜谱放在案板上反复翻看”输入固定则是“一块肉反复换不同工具处理”它们影响的是在计算过程中把数据放在哪里、什么数据被复用从而决定访存开销。选哪种数据流跟模型算子的 shape 有很大关系。2.3 一个可行的“软硬件接口”分层软硬件设计的另一个核心工作是定义“软硬件切分点”。切分点太高硬件能做加速的范围小软件负担重切分点太低硬件灵活性差模型迭代受限。目前业界主流做法是把指令分成三级任务级指令面向整个网络层的最小调度粒度软件把某一层的执行参数装进寄存器微码/微指令控制 MAC 阵列内部的数据搬移和运算节奏DMA 配置管理数据在 DRAM 和 SRAM 之间的搬运。从软件侧看编译器负责把模型转换成一个“指令流”驱动与 runtime 负责管理硬件资源、提交任务、同步中断和轮询状态。这种分级方式的好处是底层保持高效调度上层仍保留灵活性——增加新算子时不需要改动底层数据通路只需要在编译器、运行时和算子库层面添加支持。提示软硬件接口一旦冻结后续改动成本极高。架构阶段多花一两个月去打磨指令集和内存模型比后期 RTL freeze 后打补丁要划算得多。3. 硬件核心模块拆解从算子到底层电路中间隔了多少层3.1 算力核心MAC 阵列是怎么组织的先说最核心的 MAC乘加运算阵列。一个 MAC 单元完成一次乘法和一次加法对应卷积神经网络的乘累加操作。INT8 精度下一个 MAC 单元不算复杂但阵列一扩大数据排布、连接方式、计算调度的复杂度会成倍增长。具体到实际硬件阵列的组织通常围绕脉动阵列Systolic Array或二维卷积核对齐架构。脉动阵列的特点是数据在阵列里“像水流一样”逐级流动每个 PE 只和相邻 PE 通信局部性极好但也对数据进入阵列的时序有严格要求。以 TPU 为代表的脉动阵列权重预载到 PE 内部寄存器输入激活一个 cycle 一个 cycle 地从左侧流入然后部分和向下累加最后在底部输出。这种结构让“数据的移动消耗”降到最低代价是数据排布需要编译器精心处理。相比之下更灵活的二维 MAC 阵列会把多个输入数据广播到多行 PE每个 PE 的权重存储在自己局部的 SRAM 里。这样一来不同的 kernel 大小、stride 都可以直接映射但控制逻辑更复杂。设计 MAC 阵列的关键指标之一是算子映射效率。假设芯片理论算力是20 TOPS跑 3x3 卷积时如果能跑到 80% 利用率就是 16 TOPS 的实际算力但如果某个算子因为 padding 或 stride 导致很多 PE 空转算力可能会掉到 50% 以下。所以主频和 MAC 数量固然重要调度器的好坏才是决定真实性能的分水岭。3.2 数据搬运DMA 与片上存储层次的设计原则AI 芯片的片上存储一般会按层次组织类似电脑里L1 Cache → L2 Cache → 主存的概念但更强调“可预测”——AI 任务不能动不动 cache miss因为一次 miss 就会导致计算阵列暂停。常见做法紧贴 MAC 阵列的是 PE 内部的寄存器文件用于保存权重和部分和上一层是共享 SRAM / TCMTightly Coupled Memory通常几百 KB 到几 MB再往上是 L2 或直接接 DRAM / LPDDR。DMA 引擎负责在 DRAM 和 SRAM 之间做数据搬运设计时主要考虑连续传输效率、二维/三维搬运模式比如一次搬一个完整 feature map 的某个 tile、以及多通道并行的 QoS 控制。好的 DMA 设计可以做到“计算和数据搬运完全重叠”也就是后台搬运下一层数据的同时当前层还在计算让几乎 100% 的时间都在干活。在跑大分辨率输入比如 4K 视频帧检测时单层网络可能要处理非常大的 feature map片上内存根本放不下这时就得做 tiling把一张大图切块分批送入计算阵列。这个切块策略也是编译器要解决的问题需要根据存储容量、算子类型、输出对齐要求选出一个较优的块尺寸。硬件侧如果能支持任意尺寸的 tile编译器就灵活得多但地址生成逻辑和维护复杂度都会上升。3.3 低功耗设计AI 芯片掉电速度比你想得快边缘场景对功耗极度敏感。像智能摄像头、穿戴设备、机器人动不动就是“5W、2W、甚至 mW 级”的限制。AI 芯片一旦长时间满负荷跑热点和功耗墙立刻就会出现。所以在架构设计阶段就要考虑动态电压频率调节DVFS、时钟门控Clock Gating、算力单元的电源域划分。一个很实用的做法是把不同深度学习任务的“算力需求档位”量化然后设计多个计算集群或功能岛。比如一个芯片可以同时支持小算力的背景任务和大算力的主任务小任务只用低功耗小核大任务时才唤醒大核。另一个常规操作是精度模式的动态切换——处理简单场景时用 INT8低光/复杂场景自动切成 FP16能效比能差出一倍以上。这类低功耗策略在实际落地时非常依赖软件配合。runtime 需要根据当前负载动态配置硬件状态驱动要能支持运行时的算子切换。所以低功耗设计问题绝不是 IC 后端工程师单独收尾的事而是软硬件协同层面必须提前约定的协议。4. 软件栈设计与编译优化真正决定“用不用得起来”的部分4.1 AI 芯片的软件栈到底长什么样在我接触过的不少项目中芯片流片后最大的风险其实是软件工具链的成熟度。一颗新的 AI 芯片如果给算法工程师的只有一份非常简陋的算子库他们根本没法把自己的模型迁移过来。软件栈一般可以分成五层上层对接 PyTorch / ONNX / TensorFlow 等模型格式的解析协议中间层图优化与算子融合负责计算图重写、内存布局转换、算子拆并编译层把优化后的图转为硬件后端指令/文件运行时层任务提交、调度、内存管理、与驱动交互驱动层直接管理硬件寄存器、中断、DMA、电源状态。每一层之间都有严格的 API 约定。比如通常的做法是 ONNX 作为模型中间表示后端编译器读入 ONNX 后做一遍graph optimization包括算子融合比如把Conv BN ReLU合并成一个融合算子把多个小 GEMM 合并成大矩阵乘把连续的 reshape、transpose 在数据排布层面吃掉避免真实搬运。融合之后才是“指令生成”阶段。编译器要把每个算子的逻辑展开成硬件的指令流决定数据放在哪一级存储、什么时候发起 DMA、MAC 阵列如何被编程。这个环节做得好不好直接影响算力利用率。4.2 算子映射与调度从一张计算图到可执行指令算法工程师看到的是计算图硬件工程师看到的是资源调度表。编译器在其中扮演“翻译官”。以一次3x3 卷积为例硬件执行时重点要解决三件事Input tile如何从 DRAM 载入 SRAM如何做 paddingWeight tile如何预装载到 PE 阵列Partial sum如何累加、输出。编译器会生成一个详细的loop nest把卷积层的循环结构映射到三个维度MMA 指令内部的循环、PE 阵列的空间维度、时间轴上的分块调度。这还不是最难的更难的是处理像Transformer里的Softmax和LayerNorm这类算子——它们不依赖大算力却对精确度和内存访问模式有特殊要求。很多芯片对这些算子没有专门的硬件加速单元软件只能把它们拆成通用计算指令来执行这时就要尽量让它们和其他算子流水重叠避免拖慢关键路径。实操中常用cost model来做调度决策。每个算子在硬件上的执行时间被建模成“计算时间、访存时间、指令发射时间”的函数调度器通过贪心策略或动态规划尽量使前一个算子的尾和后一个算子的头在时间轴上重叠起来利用率自然就提上去了。注意在评估编译器优化效果时不要只看单个算子的耗时要看端到端end-to-end性能。单纯追求某个卷积算子跑得极快却让后面的数据搬运堵死整体性能并不会好。4.3 量化工具链模型压缩与精度校准的实战经验现在绝大多数边缘 AI 芯片都支持 INT8 计算个别支持 INT4。量化工具链的任务是把浮点模型转换成定点模型同时损失尽量少的精度。常用的量化方案有训练后量化PTQ简单粗暴不用重训练适合快速部署量化感知训练QAT在训练过程里模拟量化误差精度更好但要改动训练流程。PTQ 又分为两种一种是不需要标定数据的盲量化直接用 min/max 统计范围另一种是带标定集的最小化 KL 散度或均方误差校准。工程上绝大多数情况都会用带几百张到几千张图片的标定集来做校准目的是找到每个张量的最大绝对值范围然后算出 scale 和 zero point。量化最大的坑是不同 channel 之间数据范围差异极大。某些卷积层的权重分布很集中但个别 channel 稀疏或数值很小如果做 per-tensor 量化很小的数值会被彻底“压没”精度大幅恶化。所以现在的工具链基本都支持 per-channel 或 per-group 量化让每个输出通道都拥有独立的 scale。在我目前的工作流程里一般会准备三套测试集来验证量化后的精度一组纯干净数据比如 ImageNet 验证集子集、一组含噪声/对抗样本的数据、一组实际场景采集的脏数据。三组结果对比以后才决定这个量化配置能上车。5. 实测拆解从模型到芯片仿真的完整设计链路5.1 硬件开发流程中的 RTL 与性能验证从架构定稿到可以写代码硬件团队通常要经历SystemC或高级综合HLS层做快速性能仿真写 RTL用定向测试和随机测试在仿真器里验证功能搭建 FPGA 原型平台跑真实模型验证软件栈和硬件的配合正式流片前做门级仿真检查时序约束和功耗。这个流程中最耗时的往往是“性能仿真”和“RTL 仿真”之间的迭代。芯片计算阵列的一个 cycle 行为在系统级仿真里可能被简化但 RTL 一旦做出来整个信号细节都定了许多之前被忽略的pipeline stall流水线停顿问题会浮现出来。比如 DMA 和计算单元争用同一块 SRAM 的端口导致每搬运几十行数据就停顿几个 cycle端到端性能直接掉 15%。这类问题在上层性能模型里很难提前看清大多数靠经验提前规避。所以现在很多团队在架构探索阶段会直接构建cycle approximate的仿真模型——不做完整 RTL 但又能较精确地估算流水线冲突。这类模型虽然开发起来也费人力但相比“流片了才发现慢”性价比高出天际。5.2 一个“最小可行性”的软硬件协同开发实例假设手头要设计一颗只跑 YOLO 系列目标检测模型的芯片硬件团队和软件团队的工作可以编排成这样需求对齐期约 2 周确定支持的模型YOLOv5s、YOLOv8n确定输入分辨率640x640 或 1280x1280帧率目标比如 30 FPS功耗约束边缘盒子场景 10W 以下精度要求INT8 量化后 mAP 掉点不超过 2%。架构探索期约 1 个月性能模型里试各种 MAC 阵列尺寸和频率组合。假设使用4K MAC、主频1 GHz理论算力就是4K * 2 * 1G 8 TOPS。然后用性能模型跑 YOLO 的计算图发现实际利用率只能到 55% 左右也就是大约 4.4 TOPS帧率大约是 25 FPS。离 30 FPS 差一点于是把 MAC 加到5.6K或者把部分大层切成 INT8 和 INT4 混合精度最终达标。软件工具链开发期与 RTL 并行编译器先基于指令集模拟器开发确保能生成指令并跑通算法。这一步非常关键——等 RTL 仿真环境好了再开发编译器整个项目至少晚三个月。硬件验证与软件联调期FPGA 原型上加载编译器和 runtime跑实际 YOLO 模型。大概率第一次跑通时会有精度问题或性能偏差但因为有仿真层和工具链层可调试定位起来相对快。从这份清单可以看到软硬件协同不是一个线性过程而是并行的、多角色深度咬合的流程。架构师的沟通能力甚至比某项专门技术能力更重要。5.3 指令集模拟器的搭建迭代方法指令集模拟器ISSInstruction Set Simulator是埋在软件工具链里最不起眼但最关键的一块。它负责在拿到 RTL 之前先让编译器团队有地方跑指令。模拟器的抽象层次可以设计成三种仅功能不关心 cycle只验证指令语义是否正确周期估算每个指令给个粗略 cycle 数快速跑性能趋势周期精确完整模拟流水线和存储冲突结果可以当作 RTL 参考。工程上比较合理的是同时保留前两个第三个视时间为可选项。因为周期精确模拟的运行速度可能比真实硬件慢几个数量级YOLO 这种模型跑一遍要很久不适合日常迭代。日常用功能模拟验证正确性性能都用性能模型解决。我在工具链实现里很看重一件事——日志的可追溯性。给每条指令分配一个instruction trace ID硬件仿真和 ISS 的 log 能做逐条对比。这样一旦联调时出现指令对不上立刻可以通过 diff 脚本定位到是哪一层编译引入的偏差而不是拿 OLED 显示的几个数字在那边干瞪眼。6. 软硬件联调的常见问题和排查技巧6.1 精度不对到底是算法问题还是硬件问题AI 芯片回片或上 FPGA 平台后最容易出现的问题就是“输出结果和预期不一致”。我总结的经验是先按下面顺序排查跑一个最简单的算子比如单一卷积层输入固定随机数和 PyTorch / CPU 参考结果比对。这一步判断硬件计算本身有没有 bug跑完整模型在几个中间层插入 dump 点拿到每一层的数值输出逐层对比定位是哪一层开始“歪”的检查量化配置是不是某个 scale 溢出某个 per-channel 配置没生效检查算子融合后的算法等价性比如BN 层融合进卷积的公式变换是否准确浮点到定点的近似是否引入误差。绝大多数精度问题都是量化配置错误或编译器模式匹配错误真正纯硬件 bug 导致的反而比较少。6.2 性能比预期慢先分清是“算力没吃满”还是“访存卡顿”我遇到很多性能达不到预期的情况往往只有一个大写的原因——计算和搬运在互相等待。判别方法也容易在硬件上统计计数器寄存器的值例如busy_cycleMAC 阵列处于计算状态的循环数stall_cycleMAC 阵列等待数据的循环数dma_idle_cycleDMA 无任务可做的循环数。如果busy_cycle / total_cycle已经接近 80%那问题很可能出在算子映射效率上比如某些层的维度没法填充整个 MAC 阵列需要对编译器里的 shape 拆分规则做调整。如果只有 50%但stall_cycle很高那就要看是 SRAM 容量不足导致 tile 切得太碎还是总线带宽不够导致 DMA 传不过来。访存类瓶颈在工程上有个快速见效的解法把连续层的 feature map 存在片上不要频繁写回 DRAM。很多编译器默认每算完一层就写回其实可以支持“多级保留”让数据直接在片上从一个算子的输出成为下一个算子的输入。6.3 部署现场偶发卡死稳定性问题排查思路芯片在实验室跑得好好的到了客户现场偶发卡死这类问题最磨人。常见原因有几类时钟或复位的问题、内存访问越界、驱动中断处理漏掉某种边界条件、电源供电在大负载切换时出现压降。经验做法是在 runtime 里加入看门狗机制超时自动复位把每次任务的配置寄存器或配置的 hash记录下来复现时能精确回放当时场景优先排查“长时间运行后才会浮现”的问题多半是内存碎片化或静态 RAM 内容残留。注意如果能回放问题就先把功耗切换和 DVFS 状态变化的变量全部关掉再做 A/B 对比。很多偶发卡顿都跟电压/频率切换时的时序有关系。6.4 实战速查表软硬件联调排障清单现象优先排查方向常用手段单个算子输出不符硬件逻辑、量化配置固定随机数比对逐层 dump整体精度掉点多量化策略、算子融合等价性校准集扫描、per-channel 检查性能差且利用率低算子映射、指令流水计算/暂停周期统计调整调度性能差但利用率还行访存带宽、tile 切分检查 DMA 配置、增大片上复用偶发死机或卡死复位/时钟/电源/DVFS看门狗、配置回放、关闭动态调频这类表格放团队里当文档参考比口头传承要稳得多。我有一个习惯每次排查到问题都会把根因和修复方式补到一张持续更新的“坑位文档”里。这既方便团队协作也是后续做下一代芯片架构决策时最宝贵的素材。7. 个人实操体会如果重新做一遍项目我会怎么调整软硬件协同设计听起来很“正统”但真正的行业经验往往是在混乱中积累出来的。我最大的体会是别把软硬件协同当成一个阶段而应该把它当成一种日常工作方式。架构阶段就让编译器团队参与哪怕只是提前看看哪些算子不好映射算法团队在做模型选型时也应该拿到硬件性能模型的反馈——有些看起来网络结构很精妙的模型硬件加速器根本跑不出效率倒不如选一个结构规整但精度稍逊的模型实际效果反而好。还有一个容易忽视的问题是文档和接口版本的控制。指令集、寄存器映射、编译器的 IR 格式任何一处变更都要同步到所有团队否则就会出现“编译器已经生成新指令但驱动还按旧寄存器表配置硬件”的低级问题。建议从项目第一天就维护一份软硬件接口规格书把它当合同一样管理变更必须走评审流程。另外性能仿真的精度不用追求“绝对准确”但一定要能捕捉“趋势”。如果在架构探索阶段连“加大 MAC 数量是否带来收益”都判断不了那后续所有决策都是空中楼阁。一个好用的性能模型不一定很复杂但要足够反映真实的调度行为和访存冲突。这个项目做到后期我越来越意识到技术能力往往是团队里最容易补齐的部分最难的是架构决策时各团队能不能放弃局部最优、去争取全局最优。硬件团队不坚持多堆一堆算力软件团队不执着于让某个算子的效率刷到极致算法团队愿意为硬件姿势调整模型结构这种平衡才是 AI 芯片软硬件设计真正值得花时间琢磨的地方。