1. 为什么“AI芯片的软硬件设计”不是一句空话,而是三类人正在拼命抢滩的战场
“AI芯片的软硬件设计”这八个字,最近半年在半导体圈子、AI算法团队和系统集成商的会议纪要里出现频率翻了三倍。但很多人没意识到:它根本不是一门“技术”,而是一条分水岭式的工程能力断层线——站在左边的是传统芯片设计工程师,右边是真正能跑通大模型推理链路的系统级实践者。我去年带团队做一款边缘端视觉推理芯片时,被卡在同一个问题上整整47天:明明RTL综合通过、时序收敛、功耗达标,烧录进板子后YOLOv5s的吞吐量只有理论值的38%,且温度一过72℃就频繁丢帧。最后发现,问题既不在Verilog代码里,也不在PCB布线中,而在驱动层一个被忽略的DMA缓冲区对齐策略——这个策略需要同时满足ARM Cortex-A76的cache line边界(64字节)、NPU指令缓存的预取单元粒度(128字节),以及OpenCV图像内存分配器默认的16字节对齐。三者错位1个字节,就导致每帧图像处理多出2.3次cache miss,累计拖垮整个流水线。
这就是“软硬件设计”四个字的真实重量:它不是软件+硬件的简单叠加,而是在硅片物理极限与算法计算范式之间,用可执行代码搭建一座动态校准的桥。关键词里的“AI芯片”指向目标负载——稀疏矩阵乘、激活函数融合、量化张量调度;而“软硬件设计”则直指方法论核心:必须把编译器中间表示(MLIR)、SoC总线拓扑、内存控制器bank映射、甚至封装基板的信号完整性参数,全部纳入同一张约束求解图。这不是靠单点突破能解决的事。所以今天这篇内容,不讲概念,不列厂商,不堆参数表。我们只拆解三个真实场景:第一,如何让一个刚流片回来的NPU IP,在三天内跑通ResNet-50的INT8推理;第二,为什么你写的驱动在仿真环境100%正确,上真机却触发不可复现的DMA timeout;第三,当客户要求把模型从FP16切到INT4时,硬件团队和算法团队该在哪个坐标系里吵架——不是会议室,而是共享的SystemC事务级模型里。
这些事,教科书不写,Datasheet不提,FAE不会主动告诉你。因为它们发生在芯片手册的留白处、SDK文档的脚注里、以及凌晨三点debug日志的最后一行。而这篇文章,就是把这些留白填满。
2. 软硬件协同设计的第一道生死线:从RTL到可执行二进制的七层穿透验证
很多团队把“软硬件协同”理解成“硬件做完给软件联调”。这是致命误区。真正的协同起点,远在RTL代码敲下第一行之前。我们以一个典型AI加速核(比如类似Google Edge TPU的脉动阵列架构)为例,说明这七层穿透验证如何逐层锁定风险:
2.1 第一层:微架构行为建模(SystemC/TLM-2.0)
不是用Verilog写完模块就完事。必须先用SystemC构建事务级模型(TLM),重点模拟三件事:
- 数据搬运路径的延迟分布:比如从DDR4控制器读取1MB特征图,经AXI总线到NPU输入缓冲区,实际耗时不是理论带宽除以数据量,而是受burst length、outstanding request数、interconnect仲裁策略共同影响。我们在建模时发现,当outstanding request设为8时,实测延迟比理论值高42%,因为NoC在高负载下采用轮询仲裁,而非优先级抢占。
- 计算单元的资源竞争建模:脉动阵列中MAC单元的复用率不是静态值。当输入通道数(C_in)为32、卷积核3×3时,实际MAC利用率仅61%,因为权重广播网络成为瓶颈——这直接决定了后续编译器tiling策略的上限。
- 功耗状态切换的时序窗口:NPU从idle进入active状态需12个cycle,但clock gating controller的release信号与第一个有效指令到达MAC阵列之间存在3-cycle skew。若软件未插入足够nop,首条指令将丢失。
提示:这一层验证必须产出可量化的报告,例如“在ResNet-50第3个conv层,权重加载延迟占总cycle的23.7%,是性能瓶颈主因”。没有数字的建模等于没做。
2.2 第二层:编译器后端与硬件原语的语义对齐
AI编译器(如TVM、MLIR-based工具链)生成的codegen,本质是把高级算子映射到硬件原语(primitive)。但很多芯片团队犯的错是:把硬件原语定义成“能做什么”,而不是“在什么条件下高效做什么”。举个真实案例:某国产NPU定义了一个VADD原语,支持向量加法。TVM后端据此生成了大量VADD指令。但实测发现,当操作数地址未按256-bit对齐时,VADD执行周期从2cycle暴涨至17cycle——因为硬件内部触发了跨bank访问和额外的地址重定向逻辑。而TVM的cost model里,VADD永远标记为2cycle。
解决方案不是改硬件(成本太高),而是重构编译器的pattern matching规则:
# 原始TVM pattern(错误) def vadd_pattern(): return is_op("add")(wildcard(), wildcard()) # 修正后(强制地址对齐检查) def vadd_pattern_aligned(): lhs = wildcard() rhs = wildcard() # 插入地址对齐断言 assert_op = is_op("tir.assert")(is_expr("tir.call_extern('check_align', lhs, 32)")) return is_op("add")(lhs, rhs)同时,在硬件SDK里提供check_alignruntime函数,由驱动在启动时预检所有tensor buffer地址。这种软硬契约,必须在芯片tape-out前固化进编译器源码。
2.3 第三层:驱动框架的内存视图抽象
Linux kernel driver不能只管寄存器读写。它必须向上层(如Vulkan compute shader或ONNX Runtime)暴露正确的内存一致性模型。我们曾遇到一个经典问题:NPU DMA引擎写完结果buffer后,CPU直接读取,偶尔得到旧数据。Root cause是NPU使用Write-Back cache policy,而驱动未执行dma_sync_single_for_cpu()。但更深层的问题在于:硬件团队把cache coherency协议设计成“可选配置”,而软件团队默认启用ACE-Lite,实际SoC interconnect只支持AXI-Coherent。
最终解决方案是驱动层增加运行时探测:
// 在probe函数中 if (readl(npu_base + REG_COHERENCY_CTRL) & COHERENT_EN) { dev_info(dev, "Hardware supports ACE-Lite coherency"); dma_ops = &ace_dma_ops; // 使用full coherency ops } else { dev_warn(dev, "Falling back to manual cache maintenance"); dma_ops = &axi_dma_ops; // 插入explicit clean/invalidate }这个探测逻辑,必须基于硬件真实的寄存器定义,而非datasheet里的“typical configuration”。
2.4 第四层:用户态runtime的零拷贝通道打通
很多AI芯片SDK号称支持zero-copy,但实际测试发现,从camera sensor获取YUV数据,经ISP pipeline转RGB,再送入NPU推理,全程仍发生3次内存拷贝。问题出在内存分配器的隔离策略:ISP driver用CMA分配buffer,NPU driver用ION分配buffer,两者物理页不互通。解决方案是统一内存池管理:
- 在device tree中声明共享内存区域:
reserved-memory { npu_shared: npu-shared@80000000 { reg = <0x0 0x80000000 0x0 0x10000000>; // 256MB no-map; }; };- 用户态runtime(如libnpu.so)初始化时,从该region mmap并建立slab allocator:
int fd = open("/dev/mem", O_RDWR); void *base = mmap(NULL, SZ_256M, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x80000000); npu_mem_pool = slab_create(base, SZ_256M); // 自定义slab管理器- ISP driver和NPU driver均从该pool申请buffer,物理地址天然连续。
实测效果:端到端延迟降低31%,内存带宽占用下降44%。这个优化不需要改硬件,但依赖软硬件团队在早期就约定好内存拓扑。
2.5 第五层:量化感知训练(QAT)与硬件量化器的误差映射
INT8量化不是简单地把float32乘以scale。硬件量化器有其固有特性:
- 某NPU的INT8 multiplier支持范围[-127,127],但实际实现采用two's complement,-128无法表示,导致clip point偏移;
- 激活函数量化时,硬件采用asymmetric quantization,但PyTorch QAT默认symmetric,造成bias shift。
我们开发了一套硬件感知的QAT calibration流程:
- 在训练末期,用真实硬件量化器(RTL simulation model)替代PyTorch fake quant node;
- 收集各layer output tensor的min/max分布,拟合硬件clip point;
- 反向传播时,梯度经过hardware-aware quantizer backward pass(自定义torch.autograd.Function)。
关键代码片段:
class HardwareQuantizer(torch.autograd.Function): @staticmethod def forward(ctx, x, scale, zero_point): # 调用RTL仿真器获取量化结果(通过socket IPC) quantized = rtl_simulator.quantize(x.cpu().numpy(), scale, zero_point) ctx.save_for_backward(x, scale, zero_point) return torch.from_numpy(quantized).to(x.device) @staticmethod def backward(ctx, grad_output): x, scale, zero_point = ctx.saved_tensors # 硬件量化器的梯度近似:dx = dquantized * scale grad_input = grad_output * scale return grad_input, None, None这套流程使部署后accuracy drop从5.2%降至0.7%,且无需retrain。
2.6 第六层:调试基础设施的跨层trace贯通
当推理结果异常,传统做法是分别看:
- 软件层:gdb看tensor data
- 驱动层:dmesg看DMA status
- 硬件层:ILA抓waveform
但问题往往在层间缝隙。我们构建了统一trace框架:
- 在NPU RTL中插入AXI-lite debug port,输出每条指令的opcode、src/dst addr、cycle count;
- 驱动层通过sysfs暴露
/sys/class/npu/debug/trace_enable开关; - 用户态runtime调用
npu_trace_start(),触发硬件trace buffer dump; - Python分析脚本自动关联:
# 将硬件trace cycle与软件timestamp对齐 hw_cycle = trace_data['cycle'] sw_ts = get_sw_timestamp() # 通过rdtsc或clock_gettime(CLOCK_MONOTONIC) offset = hw_cycle - sw_ts_to_cycle(sw_ts) # 校准偏移
一次典型debug:发现某conv layer输出全零。trace显示DMA read transaction返回全0,但DDR controller status register显示no error。进一步查trace发现,DMA engine在读取weight buffer时,address LSB=1(奇地址),而硬件weight fetch unit只支持偶地址对齐。根源是编译器tiling策略未考虑硬件约束。这个bug在纯软件仿真中100%不可见。
2.7 第七层:量产固件的版本兼容性矩阵
芯片流片后,硬件版本(revision A/B/C)可能引入微小改动:
- Rev B修复了DMA descriptor parsing bug,但改变了descriptor format bit field;
- Rev C新增了INT4 mode,但requires firmware version >= 2.1.0。
如果固件不区分硬件revision,就会出现Rev A芯片加载Rev C固件后hang死。解决方案是固件启动时执行hardware ID check:
; firmware entry point mrs x0, midr_el1 ; read Main ID Register ubfx x1, x0, #20, #4 ; extract revision bits [23:20] cmp x1, #0x2 ; Rev B? b.eq rev_b_init cmp x1, #0x3 ; Rev C? b.eq rev_c_init b default_init同时,SDK提供npu_get_revision()API,让用户态应用根据revision选择算子实现路径。这个机制让同一份SDK binary支持三代硬件,降低客户迁移成本。
这七层穿透验证,每一层都要求软硬件团队坐在同一张桌子前,用同一套测试用例跑,用同一份failure report追因。它不是流程,而是肌肉记忆。
3. NPU驱动开发中最隐蔽的五个陷阱:来自三次流片失败的血泪笔记
驱动是软硬件协同的承重墙。但很多团队把驱动当成“寄存器操作说明书”的翻译工作,结果在量产阶段被反复打脸。以下是我在三款AI芯片驱动开发中踩过的坑,每个都导致至少一次tape-out延期:
3.1 陷阱一:中断服务程序(ISR)里的“伪原子操作”
NPU完成推理后触发中断,ISR中通常要:
- 读取status register确认完成;
- 清除interrupt pending bit;
- 唤醒等待的user process。
表面看是三行代码,但硬件实际行为是:
- status register读取后,硬件内部状态机立即进入idle;
- 但interrupt pending bit清除有1-cycle延迟;
- 若此时新任务到来,硬件可能再次assert interrupt,但pending bit已被清,导致丢失。
解决方案不是加spinlock(会阻塞整个CPU),而是用硬件atomic clear:
// 错误写法:分步读-清 val = readl(npu_base + REG_STATUS); writel(0x1, npu_base + REG_INT_CLEAR); // 可能丢失中断 // 正确写法:读-清原子操作(需硬件支持) writel(0x1, npu_base + REG_STATUS_CLEAR); // 写1清对应bit,读操作隐含这个功能必须在RTL设计阶段就定义好,否则驱动无解。我们第二颗芯片就因缺少此功能,被迫在ISR中加了500ns delay——这直接导致实时性指标超标。
3.2 陷阱二:DMA描述符的“隐式依赖链”
NPU常采用scatter-gather DMA,一个task包含多个descriptor。硬件按descriptor链顺序执行,但有个隐藏规则:descriptor N的completion signal,会触发descriptor N+1的prefetch。如果descriptor N+1尚未写入memory,硬件会stall。问题在于:driver通常用dma_map_single()分配descriptor memory,但该函数不保证cache clean。当CPU写完descriptor N+1,未执行dma_clean_range(),硬件prefetch到脏cache line,得到全0数据。
验证方法:在descriptor写入后强制clean:
struct npu_desc *desc = dma_alloc_coherent(dev, sizeof(*desc), &dma_addr, GFP_KERNEL); // ... fill desc fields ... dma_clean_range((unsigned long)desc, (unsigned long)desc + sizeof(*desc)); // 关键! writel(dma_addr, npu_base + REG_DESC_ADDR);这个clean操作,在ARM64平台需调用__clean_dcache_area_poc(),x86平台则无需——跨平台驱动必须条件编译。
3.3 陷阱三:时钟门控(Clock Gating)的“唤醒延迟黑洞”
为省电,NPU在idle时关闭部分clock。但唤醒延迟不等于datasheet写的“max 10ns”。实测发现:
- 当NPU从deep sleep唤醒,PLL relock需83个cycle;
- clock divider reconfigure需12 cycle;
- 最终clock稳定需额外7 cycle jitter。
而driver通常假设writel(0x1, npu_base + REG_CLK_EN)后下一个cycle clock就ready。结果是:第一个指令fetch到stale clock domain,opcode decode失败,NPU hang。
解决方案:硬件增加wake-up status register,driver轮询:
writel(0x1, npu_base + REG_CLK_EN); while (!(readl(npu_base + REG_WKUP_STATUS) & WKUP_READY)) cpu_relax(); // 不能用udelay,因cycle数不确定这个register必须在RTL中实现,且bit定义要精确到硬件实际行为。
3.4 陷阱四:内存屏障(Memory Barrier)的“层级错配”
NPU计算结果写入output buffer后,driver要通知CPU。常见写法:
writel(0x1, npu_base + REG_TASK_DONE); // 通知硬件task完成 smp_mb(); // CPU memory barrier wake_up(&wait_queue); // 唤醒等待进程但问题在于:NPU写output buffer和写REG_TASK_DONEregister,走的是不同AXI通道。smp_mb()只保证CPU cache一致性,不保证AXI interconnect的order。实际硬件中,REG_TASK_DONEwrite可能先于output buffer write到达DDR controller,导致CPU wake up后读到旧数据。
正确方案是使用硬件提供的memory barrier register:
writel(0x1, npu_base + REG_TASK_DONE); writel(0x1, npu_base + REG_MEM_BARRIER); // 硬件保证此前所有write完成 smp_mb(); wake_up(&wait_queue);这个barrier register必须由硬件团队设计,并在datasheet中明确定义其语义。
3.5 陷阱五:电源域(Power Domain)切换的“状态残留”
高端AI芯片常分多个power domain:core domain、memory domain、IO domain。切换时,硬件要求严格顺序:
- 先disable core domain clock;
- 再power down core domain LDO;
- 最后power down memory domain。
但driver若按相反顺序操作(先down memory domain),会导致core domain在无memory供电下尝试flush cache,引发undefined behavior。更隐蔽的是:某些LDO controller在power down后,其status register仍返回"powered on",因内部电容未完全放电。
解决方案:增加power state machine:
enum npu_power_state { POWER_OFF, POWER_ON_CORE, POWER_ON_MEM, POWER_FULL }; static int npu_set_power(enum npu_power_state target) { switch (target) { case POWER_FULL: enable_core_clock(); wait_for_core_stable(); // 硬件signal enable_mem_power(); wait_for_mem_stable(); // 硬件signal break; // ... other states } }这个state machine必须与硬件power controller的FSM严格同步,且每个transition需硬件提供status signal。
这些陷阱,每一个都源于“硬件行为”与“软件假设”之间的毫米级偏差。它们不会在仿真中暴露,只在真机压力测试下浮现。而修复成本,是流片费用的10倍。
4. 从ResNet到LLM:AI芯片软硬件设计范式的代际跃迁
当AI芯片从跑ResNet-50进化到跑Llama-3-8B,软硬件设计的底层逻辑发生了质变。不是简单地堆算力,而是重构整个协同范式:
4.1 计算范式:从固定流水线到动态指令调度
传统CNN加速器采用fixed pipeline:fetch → decode → execute → writeback。但LLM的attention计算具有强数据依赖:
- QKV矩阵乘结果决定next token位置;
- position embedding需根据生成长度动态索引;
- KV cache的读写地址随step变化。
硬件不再能预定义pipeline stage。我们采用micro-op dynamic scheduler:
- 编译器将LLM graph分解为micro-op序列(如
matmul_qk,softmax,matmul_pv); - 硬件scheduler在runtime根据data dependency graph动态dispatch micro-op到可用compute unit;
- 每个micro-op携带context id,scheduler据此管理register file bank switching。
关键创新是scheduler的latency:必须≤2 cycle,否则吞吐量崩溃。我们用定制ASIC实现,面积开销仅1.2mm²,但使7B模型token生成速度提升3.8倍。
4.2 内存架构:从HBM带宽竞赛到近存计算(PIM)重构
HBM2e带宽已达460GB/s,但LLM的weight数据访问仍是瓶颈。单纯堆带宽无效,因:
- weight matrix稀疏性达98%,但HBM仍按dense模式传输;
- attention计算中,QKV矩阵需多次访存,带宽利用率<30%。
我们转向3D-stacked PIM架构:
- 在HBM stack顶部集成compute die(28nm工艺);
- 每个bank内置MAC array,支持in-bank matrix-vector multiply;
- host CPU只发送compressed weight index和activation vector,PIM die完成计算后返回scalar result。
实测效果:Llama-3-8B的prefill阶段,memory bandwidth usage从92%降至18%,end-to-end latency降低57%。但软件栈必须重构:
- 编译器需生成PIM-aware IR,将
matmulop split为pim_dispatch+pim_wait; - 驱动需管理PIM die的firmware load和context switch;
- runtime需实现weight compression/decompression pipeline。
4.3 软件栈:从单点优化到全栈DSL(Domain Specific Language)
TensorRT、ONNX Runtime等通用runtime,在LLM场景下成为瓶颈。我们开发了NPU-native DSL:
// llama_attention.dsl def attention(q: Tensor[bs, seq, dim], k: Tensor[bs, kv_seq, dim], v: Tensor[bs, kv_seq, dim]) -> Tensor[bs, seq, dim]: qk = pim_matmul(q, k^T) // offload to PIM attn = softmax(qk / sqrt(dim)) out = pim_matmul(attn, v) // offload to PIM return out编译器(基于MLIR)将DSL直接映射到硬件原语,跳过ONNX中间表示。关键优势:
- 消除graph optimization overhead(ONNX runtime平均增加12% latency);
- 支持hardware-specific fusion(如
softmax+matmulin one PIM command); - 便于硬件团队迭代:新增PIM指令,只需扩展DSL grammar和compiler backend。
4.4 验证方法:从testbench到real-world workload replay
传统验证用random stimulus,但LLM workload有强时空局部性:
- KV cache access pattern呈power-law distribution;
- weight fetch burst size随layer depth变化;
- memory pressure在prefill和decode阶段差异巨大。
我们构建workload replay framework:
- 采集真实用户请求(anonymized),提取memory trace;
- 用SystemC model replay trace,统计bank conflict rate、row buffer hit rate;
- 发现某layer的weight access导致特定HBM bank over-subscription,触发refresh storm。
解决方案:硬件增加bank interleaving control register,软件runtime根据trace预测动态配置interleave pattern。这个优化使HBM efficiency从41%提升至79%。
4.5 交付形态:从chip to chiplet to system-in-package(SiP)
单颗AI芯片已到物理极限。下一代方案是SiP:
- Compute chiplet(3nm,NPU+CPU);
- Memory chiplet(HBM3,4stack);
- IO chiplet(PCIe 6.0, CXL 3.0);
- All connected by2.5D interposer。
但软硬件协同复杂度指数上升:
- 不同chiplet的工艺节点不同,thermal coupling效应需联合仿真;
- CXL memory sharing要求cache coherency protocol跨chiplet一致;
- firmware update需atomic across all chiplets。
我们的应对策略是unified firmware image:
- 所有chiplet firmware打包为single .bin;
- Boot ROM按chiplet ID dispatch firmware segment;
- runtime通过CXL mailbox通信,实现cross-chiplet task scheduling。
这个SiP方案使8B模型推理功耗降低44%,但驱动开发工作量增加300%——因为要管理chiplet topology discovery、fault isolation、load balancing。
从ResNet到LLM,不是算力升级,而是整个设计哲学的重写。它要求硬件工程师懂PyTorch autograd,软件工程师能看懂RTL waveform,而系统架构师必须同时是编译器专家和热力学专家。
5. 给正在设计AI芯片的团队一份务实清单:哪些事必须现在做,哪些可以延后
如果你正站在AI芯片设计的起点,面对海量技术选项,这份清单基于我们踩过的坑,帮你聚焦真正关键的决策点:
5.1 必须现在做的五件事(tape-out前6个月冻结)
定义硬件-软件契约接口(HSI)
不是写文档,而是产出可执行的IDL(Interface Definition Language):- 寄存器map:用Kaitai Struct语法描述,自动生成C header和Python parser;
- DMA descriptor format:用binary schema定义,驱动和firmware共用同一份schema;
- Error code semantics:每个error code必须对应具体硬件状态(如
ERR_DMA_TIMEOUT=REG_DMA_STATUS[TIMEOUT_BIT] == 1)。
这个IDL必须由硬件team和software team joint sign-off,任何变更需双签。
构建跨层trace infrastructure
- RTL中插入AXI-lite debug port,输出instruction trace、memory trace、interrupt trace;
- 驱动层提供sysfs interface导出trace buffer;
- 用户态提供Python analysis lib,自动关联软硬件事件。
没有这个,debug效率降低10倍。我们第三颗芯片因缺少此功能,debug周期长达89天。
固化量化感知流程
- 硬件团队提供RTL-level quantizer model(Verilog/VHDL);
- 软件团队将其集成到PyTorch QAT pipeline;
- 定义量化误差budget(如top-1 acc drop ≤0.5%)。
不要等tape-out后再做QAT,那只是“适配”,不是“协同”。
设计电源状态机(PSM)
- 明确每个power domain的entry/exit sequence;
- 定义每个state transition的hardware signal requirement;
- 驱动层实现state machine,禁止自由切换。
我们曾因PSM不一致,导致量产芯片在高温下随机reset。
确定内存一致性模型
- 明确是ACE、AXI-Coherent还是manual cache maintenance;
- 在device tree中用
coherency-modeproperty声明; - 驱动层根据此property选择dma_ops。
这个决策影响整个软件栈,无法后期更改。
5.2 可以延后的三件事(tape-out后迭代)
高级编译器优化(如auto-tiling)
初版SDK用hand-tuned tiling即可满足90%场景。auto-tiling需大量benchmark数据,可在v1.1 release加入。多芯片互联(如Chiplet interconnect)
单chiplet方案足够验证核心IP。CXL/UCIe互联可在第二代产品实现,避免初期复杂度爆炸。AI-native OS kernel extension
Linux kernel已有成熟driver framework。专用OS(如Zephyr for AI)可作为long-term project,不影响initial bring-up。
5.3 绝对禁止的三件事(红线)
禁止在RTL中使用“magic number”
所有参数(如DMA burst length、cache line size)必须定义为parameter,并在顶层module通过generic map传入。否则无法适配不同工艺节点。禁止驱动中hardcode memory address
所有寄存器base address、buffer address必须通过device tree或ACPI table获取。hardcode地址会使firmware无法支持不同board config。禁止在SDK中暴露未验证的API
每个API必须有对应的test case,覆盖boundary condition。未test的API等于bug source。我们曾因暴露一个未验证的npu_set_freq()API,导致客户系统在超频后出现不可复现的DMA corruption。
这张清单不是教条,而是用三次流片失败换来的经验。它不承诺成功,但能让你避开那些会让项目停摆的深坑。
我在最后一颗芯片的bring-up phase,每天早上第一件事是检查这五项是否100%落实。当所有checkbox打勾时,我知道,tape-out那天,我们可以笑着去庆祝,而不是在实验室熬通宵。