这段时间我对“如何从零做出一个真实可用的自定义芯片”这件事特别好奇。以前总觉得 ASIC(专用集成电路)是半导体大厂才能碰的东西,要有流片渠道、大厂EDA工具、巨额预算和一群工程师。直到看到一位独立硬件创作者展示自己“第一次认真做的 ASIC 项目”,这种认知才被彻底打碎。它不是做一个教学用的模拟模块,而是完完整整走完从设计、仿真、综合、布局布线到流片、回片、测试和调试的全部流程,最终让一颗自定义芯片在桌面开发板上跑起来。
这件事真正的价值,不是“那颗芯片有多强”,而是它展示了普通人能不能用尽可能小的成本,把这个闭环跑通。如果真能做到,那么对很多做嵌入式、FPGA、处理器设计和软件底层的人来说,意义就不只是“看你做个东西挺好玩”,而是“我是不是也可以用类似的方法,亲手验证一个芯片设计想法”。
在这篇文章里,我尽量不把视角停在视频或资料的表层,也不会把“流片”两个字说得玄乎。我更想把这件事拆成几个真实的工作阶段:验证、综合、物理设计、回片调试、长期维护。这对没有接触过芯片设计流程的软件和嵌入式开发者来说,会更接近“原来这帮人干活时,脑子里想的是这些”的感觉。
1. 理解“第一次做 ASIC”这件事到底解决什么问题
“ASIC”这三个字母,看起来是个硬件名词。但对第一次认真做这种项目的人来说,它真正涉及的是一次“从抽象逻辑到物理事实”的认知跃迁。
1.1 不要把 ASIC 理解成“更小的 FPGA”
很多嵌入式工程师会掉进一个误区,觉得 FPGA 开发已经做得很熟了,用 Verilog 写了模块、仿真过了、上板能跑,那 ASIC 只是照同样的流程走一遍,最后把生成的文件交给工厂生产就行。
实际操作下来,会发现这条路远没那么顺。FPGA 本身就是一种“可重构”的芯片,开发中有一大堆免费或便宜的配套资源:可用的片上存储器、可配置的时钟网络、现成的 DSP 单元、各厂家的 IP 核。跑一个软核处理器,几分钟就能建立工程;就算布局布线出点问题,顶多在板上换个管脚约束,重跑一版 bitstream 就完事。
但 ASIC 设计没有“重新配置”这个选项。你的 RTL 代码最终会变成一条条真实的晶体管路径,这些路径一旦固化,就没有回头路。再加上第一版通常只有有限片数的回片机会——哪怕是 Open MPW 这类共享流片项目,也不可能像调试 FPGA 那样随意改一版再来。所以,第一次做 ASIC 时,最难的不是写 Verilog,而是“第一次就要尽量正确”这件事。
1.2 它真正训练的是完整闭环能力
在视频项目里,这个创作者走的是一条非常典型的“低成本 ASIC 全流程”:先确定想实现的功能模块,接着用 HDL 写出 RTL,做足够多的仿真,然后使用开源或教学级 EDA 工具完成综合、时序分析、布局布线和物理验证,最后把生成的 GDSII 文件交给共享流片渠道。
从视频中可以看到,实际项目最终做成了一颗能够运行自定义指令的处理器,并在拿到芯片后认真做了上电测试、调试接口测试和应用验证。这颗芯片的规格并不高,但它“完整地存在于现实中”。这比你只调到一百个模块仿真通过要有说服力得多。
对程序员来说,可以借用这个概念:第一次做 ASIC 项目,相当于第一次把一个足够小的软件从源码一路编译、链接、打包、部署到真正的物理设备上。中间任何一步配置错误、边界情况没处理、工具版本不一致,都会在最终物理载体上暴露出来。而前期每一个环节的妥协,最终都会换算成回片后的调试时间。
1.3 传统芯片设计流程里的几个环节,在哪一步会遇到强工程约束
下面是芯片设计大致会涉及的几个阶段,我给每个阶段加了一句“如果你第一次做,最容易在哪里翻车”:
| 阶段 | 核心动作 | 第一次做最容易出问题的地方 |
|---|---|---|
| 需求定义 | 说清楚芯片要跑什么程序、对外提供哪些接口、跑多快 | 以为接口越丰富越好,结果 pin 布局和测试复杂度爆表 |
| RTL 设计 | 用 Verilog 或 Chisel 写出寄存器传输级描述 | 写出的代码不是“可综合风格”,仿真能过、综合报错 |
| 功能仿真 | 验证逻辑行为是否符合预期 | 只测了 happy path,边界信号、复位序列、跨时钟域完全没覆盖 |
| 逻辑综合 | 把 RTL 映射到标准单元库 | 不读综合报告,关键路径、扇出、面积信息全部忽略 |
| 时序收敛 | 让所有路径满足时钟频率和约束要求 | 时钟约束太乐观,导致布局布线后时序大面积失败 |
| 布局布线 | 把标准单元摆到物理版图上并连线 | 对单元密度和绕线资源没有概念,版图密度过紧 |
| 物理验证 | 检查设计规则、天线效应、可靠性问题 | 只关心功能,不知道 DRC/LVS 不通过就无法流片 |
| 流片与封装 | 交给代工厂制造并封出引脚 | 前期没留测试 pad,导致芯片无法方便地引出时钟和 IO |
| 回片测试 | 上电、写测试程序、用逻辑分析仪验证功能 | 没有建立“最小可运行程序”,上电后手忙脚乱 |
这个表不是给你背的,而是为了说明一个判断:第一次做 ASIC 的本质是“完整地走一遍约束链”。越早意识到每个阶段都有物理和工具约束,越不会在后面补课。
2. 验证阶段为什么花的力气最大:电脑里仿真通过不等于芯片能工作
如果去观察那些第一次做芯片的人,会发现他们几乎所有时间都花在“验证”上。真正写 RTL 的时间不长,综合工具跑一个版本也许只要几十分钟,但验证阶段经常是“改一个 bug,重新跑一遍仿真,又发现一个边界问题,再补测试”。
这不是效率低,而是因为芯片设计里有一个铁律:你知道的 bug,到流片后再发现已经太晚了;只有你主动构造出来的测试,才能帮你提前发现大部分错误。
2.1 功能仿真、FPGA 原型验证、真实芯片验证的差异有多大
很多人容易把上面的概念混为一谈。它们确实都有“验证”两字,但能证明的事完全不同。
- 功能仿真:验证的是 RTL 代码在抽象时间模型下的逻辑行为。它速度快、便于调试,但不包含实际门延迟、布线延迟,也不包含成品芯片的物理特性。
- FPGA 原型验证:把 RTL 综合到 FPGA 上跑。它能验证大部分功能正确性,并且因为 FPGA 可以反复烧写,调试成本低。但它无法完全复制 ASIC 的时序行为、IO 特性和功耗特性。
- 真实芯片验证:一切在真正的硅片上跑。这是最终的“裁决”,但也是调试成本极高的一步,因为你很难直接观察芯片内部信号。
在第一次做 ASIC 的项目里,通常的策略是先用 FPGA 验证功能,再进入 ASIC 流程。不过真实工程里不能把 FPGA 验证当成“万无一失”。常见情况是:FPGA 上跑得好好的,换成 ASIC 后,因为异步复位释放时间、时钟偏斜、未初始化寄存器初值等问题,芯片行为出现细微差异。
这说明一个问题:功能仿真和 FPGA 验证解决的是“逻辑对不对”,而真实硅片还要面对“物理实现是否符合预期”。
2.2 第一次做芯片,测试基准里应该覆盖哪些内容
我的建议是,把验证分成四层,每一层都不能跳过。这套流程我在自己的硬件项目里也会用:
- 第一层:模块级测试。每个子模块单独写 testbench,验证输入输出、复位、忙等机制。
- 第二层:系统级仿真。把完整 SoC 或处理器跑起来,加载一段固定的测试程序,比如跑一段循环、读写一串存储器内容。
- 第三层:边界异常测试。包括异步复位、时钟缺失、总线长时间无响应、无效指令、水位不足等情况。
- 第四层:硬件原型验证。在 FPGA 上跑真实应用,最好串口回传测试结果,或通过 LED、逻辑分析仪确认关键信号。
如果我不打算做成大型项目,只做一颗很小的处理器,那我至少也会写一个“最小测试程序集合”:从简单的寄存器读写开始,再到加法、分支跳转、存储器访问、最后直接运行一个完整的小应用。这个顺序不能反,因为你在回片之后也需要用同样的路径来逐步点亮芯片。
2.3 仿真波形是回片调试时最重要的“参考地图”
很多第一次做硬件项目的小伙伴容易忽略“记录波形”的长期价值。跑完一次仿真,看到输出正确,就急着改下一版。其实波形文件是之后回片调试时的金标准。
比如:芯片上电后,你从外部引脚看不到内部寄存器状态。你只能通过某个调试引脚或串口等接口抓取部分信息。如果手头有仿真的波形,你能预判某个信号在第十个时钟周期应该是什么值;如果真实芯片读回来的值对不上,你就知道在哪一步出了问题。
这个方案听起来不算复杂,但在真实项目里,只要你漏掉了波形保存和对照,回片调试时基本只能靠“猜”。
注意:不要因为仿真很顺利就直接 jump 到流片。功能完全没有验证过的芯片,大概率拿回来是废片。第一次做,多花时间在 testbench 上不会亏。
3. 从 FPGA 到 ASIC 的关键跨越:综合、时序约束与物理设计
如果芯片设计要挑一个“工程味最重”的环节,我会选综合与物理设计。因为在这里,你的代码第一次开始受限于“真实硅片能不能实现它”。
3.1 可综合 RTL 与仿真友好型 RTL
做 FPGA 开发时,很多写法即使质量一般也能综合。比如大量使用initial块给寄存器赋初值,在 FPGA 上也许能工作,但 ASIC 标准单元库并不保证每个触发器都有确定的初值。再加上复位策略、跨时钟域处理、内部三态总线等,每一类写法都可能变成流片后的隐患。
所以,我在写 RTL 时至少会遵守几个原则:
- 所有内部寄存器必须有明确复位逻辑,不要依赖上电初值。
- 所有跨时钟域信号必须同步处理,简单的可以用两级触发器同步。
- 不使用
initial来给寄存器赋初值。 - 不写仿真专用的
#delay语法到可综合代码里。 - 内部模块尽量只用同步时序,组合逻辑全部通过 always 块清晰表达。
这些不是“高级技巧”,而是 ASIC 流程的基本门槛。你在 FPGA 上可以绕过一部分,但做真正的 ASIC 时绕不过。
在 bitluni 这类独立项目里,你可能会看到开发者刻意把设计规模控制在很有限的处理器指令集内,就是为了让 RTL 足够简单,从而降低综合和后端出现意外问题的概率。这不是能力不足,而是第一次做芯片时“设计得足够简单”本身就是一种正确策略。
3.2 综合工具与标准单元库:开源生态给了普通人一个入口
过去要做逻辑综合,多半依赖大型商业 EDA 工具和工艺厂商提供的标准单元库,普通人很难接触。近几年开源工具链逐渐成熟,再加上共享流片通道的出现,个人开发者才有机会用较低成本从 RTL 一路做到 GDSII。
但这里要冷静一点:开源工具链是能跑通流程,不代表它可以替代商业工具在所有场景下的能力。第一次做芯片,应该把目标设定为“验证完整流程、做出功能正确的小芯片”,而不是挑战高速接口或复杂 SoC。工具链的成熟度、标准单元库的可用性、脚本配置这几方面,都需要提前确认版本和兼容性。
如果你也想尝试,我的建议是从开源处理器核或自己写的一个极小 CPU 开始,先用开源综合工具跑一遍流程,确认能生成门级网表,再往后端走。如果在这个阶段遇到工具报错,不要怀疑是自己代码的问题,先去查工具的版本兼容和工艺库路径配置。
3.3 时序约束为什么不能随便填
“你希望芯片跑多快”不是靠 RTL 代码体现的,而是靠约束文件告知后端工具。如果约束写得太乐观,比如想让时钟跑到 100MHz,但设计实际实现下来只能收敛在 50MHz,那么工具就会在布局布线阶段疯狂尝试修复时序,可能强行插入 buffer,或改变布线策略,最终可能仍然修复不了。
对第一次做 ASIC 的人来说,看综合报告里的关键路径时序裕量非常重要。时序收敛的目标是让所有路径的建立时间和保持时间都满足约束,而不是“看起来差不多就行”。
从工程经验看,第一次做芯片时不要追求过高的时钟频率。设定一个保守频率,比如 25MHz 甚至 12MHz,优先保证流程跑通、时序收敛、IO 接口稳定。视频里的项目其实也印证了这一点:设计的重点在处理器功能和外围接口验证,而不是极限性能。
这里有一个普遍适用的工作原则:先保证正确性,再把性能提升当作后话。
3.4 物理设计阶段:面积、布线资源和 pad 规划
物理设计阶段离大多数软件工程师最远,但正是这个阶段决定你的 GDSII 能不能真的流片。简单来说,你需要把门级网表映射到物理空间:标准单元要放置,信号线要连接,电源网络要铺设,还要把芯片引脚 pad 规划好。
对于第一次做芯片,最常见的坑是 pad 数太少,导致回片后无法方便地接出时钟、复位和调试信号,或者测试程序根本没地方加载。所以我会在项目初期就列一个“信号清单”,不仅包括功能接口,还包括测试接口,比如:
- 外部时钟输入引脚。
- 手动复位引脚。
- 至少一组 UART 或 SPI 调试接口。
- 一组 GPIO,用于指示运行状态和外部输入。
- 电源和地引脚的多余预留。
这些 pad 布局如果在综合前没想清楚,到后端阶段会发现“功能逻辑没问题,但外面接不出来”。这个阶段可能没有太多直观的可视化结果,但它是区分“学会写 RTL”和“能做出芯片”的分水岭。
4. 真正麻烦的关卡在“拿到芯片之后”:回片测试与调试
很多课程和文章讲芯片设计只讲到“GDSII 交出去”就结束了,好像流片成功就是大结局。实际上对第一次做芯片的人来说,收到回片后的几天才是最紧张、最考验工程能力的阶段。因为从这一刻起,你不能再改动 RTL,也不能重新跑一遍布局布线;你只能像考古一样,在真实硅片上用测试手段一点点确认它是否和你写代码时的假设一致。
4.1 第一次上电之前,先写一份测试计划
不少硬件爱好者的习惯是:芯片一到手上,马上焊接到转接板,插上电源,第一时间看它能不能跑。多数情况下,这个操作会导致一个结果:芯片悄悄发烫,或者IO电平异常,但你还不知道问题出在哪里。
正确做法是先给自己列一份“上电测试计划”,内容不需要多专业,但至少要包括:
- 检查供电:不同电源域电压是否正确,有没有短路。
- 检查时钟:外部晶振或时钟发生器输出是否正常到达芯片时钟引脚。
- 检查复位:手动复位信号拉高或拉低后,内部状态是否回到预期初值。
- 检查静态电流:上电但不运行时,功耗是否在合理范围。
- 检查程序加载路径:能否通过调试接口把测试程序写入芯片内部 RAM,或从 Boot ROM 执行。
- 逐步运行测试:从最简单功能开始验证,而不是上来就运行完整应用。
如果在任何一步出现异常,先记录现象,再对照仿真波形推断可能原因。这时你手头最有效的工具通常是逻辑分析仪和示波器。没有它们,你基本只能靠芯片赱没发热来猜测内部状态。
注意:第一次给手工焊接的芯片上电前,一定要用万用表先确认电源引脚之间没有短路。成本再低的芯片,也经不起一次性怼坏几颗。
4.2 芯片调试和软件调试最大的不同:你只有尽可能少的观测点
软件调试时,你可以打日志、用断点、看堆栈。但在芯片调试中,观测点极其有限。除非你在设计阶段专门留了调试引脚,否则内部总线、ALU 状态、指令指针这些信号无法被外部直接读取。
这也是为什么我在前面反复强调“设计和验证阶段要尽早定义测试接口”。比如,你可以借助串口把处理器内某个寄存器的值打印出来,或者用 GPIO 连续翻转来指示程序运行到哪一行。回片调试阶段,很多时候是通过“外部可观测行为的组合”来推断内部状态的,而不是直接看到 CPU 内部发生了什么。
如果你的芯片是软核或自定义指令集处理器,那更要准备一套测试程序渐进式验证:
- 先运行一条空操作指令,确认取指和执行管道能走通。
- 再运行一条立即数加载指令,确认寄存器能正确写入。
- 运行算术逻辑运算,用 GPIO 或调试接口输出结果。
- 再加一个循环,确认跳转指令和条件判断有效。
- 最后加载一段完整小应用,比如跑一个 LED 闪烁或简易计算器。
这套思路对第一次做 ASIC 项目的人特别实用。因为每打通一个层级,你就能更准确地区分“是 RTL 逻辑设计错误”还是“时序或物理实现问题”。
4.3 回片调试常见的现象与可能的排查方向
下面这张表,是常见的回片异常现象和排查路径。它不是官方资料,更适合作为你拿到芯片后的“第一反应菜单”:
| 看到的现象 | 优先排查方向 |
|---|---|
| 上电后芯片发烫或电流异常 | 电源引脚接反、内部短路、IO 绑定冲突 |
| 时钟引脚有波形,但复位后无任何输出 | 全局复位未释放、时钟门控未打开、供电状态位不对 |
| 串口无响应 | 波特率配置、时钟分频系数、IO 方向寄存器、引脚绑定 |
| GPIO 不翻转 | pad 方向寄存器未配置、输出使能引脚未接 |
| 运行测试程序时行为不稳定 | 电源纹波过大、未加去耦电容、时钟抖动、时序裕量不足 |
| 程序加载接口能够握手,但数据校验失败 | SPI/I2C 时钟相位极性不匹配、IO 电平不兼容 |
这些现象背后没有灵丹妙药,只能像剥洋葱一样逐层排查。更重要的是:在回片前把测试环境、测试程序、观测工具都准备好,不要让芯片到货后再开始写测试代码。
4.4 回片测试的“最小启动程序”可以这样设计
一个非常理想的最小测试程序可以这样规划(以演示为目的):
- 在 GPIO 上产生一个固定频率方波,比如 1Hz 翻转,用 LED 确认时钟和复位正常。
- 通过串口发送一个固定字符串,确认基本 IO 通路工作。
- 读取拨码开关状态,并通过另一组 LED 显示出来,确认输入输出都能用。
- 运行一段寄存器回环测试:写入不同值到寄存器,再读取校验,通过串口输出结果。
- 完成后,再进入完整测试程序集合。
这套“最小启动程序”不需要很复杂,但它能在十分钟内告诉你:芯片能取指、能读写寄存器、能做 IO 访问、能和外部通信。如果这些基础能力都不成立,再运行复杂程序毫无意义。
5. 第一次做 ASIC 项目,对普通开发者的长期参考价值在哪里
到这里,可能有人会觉得,自己既没有流片渠道,也没有深学过 IC 设计,看这类内容是不是只是看个热闹。我觉得不至于。即使不打算真的流片,这种项目的思考框架也可以被带进日常嵌入式开发和 FPGA 工程中。
5.1 从“写代码”切换到“设计系统”:你才会真正敬畏边界条件
平时写嵌入式 C 代码,编译器会帮你处理很多底层细节,芯片跑不动时顶多是性能问题。写 Verilog 并走上 ASIC 流程时,所有“边界条件”都变成物理设计的一部分。你为每一根信号、每一个时钟边沿、每一个未初始化的寄存器都付出了真金白银和时间成本。
这种“边界感”一旦建立,回到普通开发队列中,你会更愿意花时间做输入校验、状态机保护、异常恢复和弱网重试,因为你见过那些步骤被跳过的代价。
5.2 想尝试的话,可以先走一条“低成本闭环路径”
我自己更建议用下面这条路径,逐步建立“从 RTL 到真硅片”的完整认知:
- 先写一个自己完全掌握功能的极小 CPU 或专用模块,不用追新,重点是能从头到尾理解每一个信号。
- 为它写一套完整 testbench,覆盖基本指令、边界条件和中断/异常场景。
- 在一款便宜的 FPGA 开发板上跑通,通过串口或 JTAG 验证实际运行结果。
- 再学习开源综合工具链,尝试把同一个 RTL 综合到标准单元库,生成门级网表。
- 有机会再参与共享流片项目,亲自体验 GDSII 提交和回片测试。
这个路径的关键是:每一步都确保自己彻底理解前一步,再过渡到下一步。也许到最后你也不会设计一颗复杂的商用芯片,但你会清楚地知道“芯片设计到底是怎样一个过程”。
5.3 这个项目的适用边界:谁适合做,谁暂时不适合
适合的人包括:
- 已经写了多年 RTL,却始终停留在 FPGA 层面,想知道真实硅片流程差异的开发者。
- 从事处理器设计、编译器、操作系统底层相关工作,想纵向理解“一条指令从源码到晶体管”路径的人。
- 想尝试开源 EDA 工具链、共享流片社区和更开放芯片生态的学生或独立开发者。
- 对低成本硬件极客项目有兴趣,能接受“项目最终不一定成功”的人。
不太适合的情况包括:
- 目标是快速获得一颗高主频、高集成度、功能复杂的芯片,这样的项目不是个人第一次能轻松完成的。
- 希望流片成功率接近 100%,对失败和调试没有耐心,因为第一次做芯片本质上就是大概率要经历反复调试的过程。
- 不愿意花时间写测试和测试计划的开发者,因为做 ASIC 不强调“顺手调通”,而强调“提前把所有可能路径都想好”。
这类项目的长期价值不在于把你变成“芯片设计专家”,而在于让你亲眼看到:一个用代码描述的抽象系统,怎样跨越工具链、物理约束、制造流程,一步步变成桌面上一颗会跑程序的芯片。这个过程会让你同时建立三样东西:对工具链的敬畏、对测试计划的重视、对底层原理的直观感受。这三样东西,无论以后是做嵌入式、做 FPGA、做芯片,还是继续做上层软件,都不会白费。
如果要说一句最直接的行动建议,我会说:不要只停留在看完一个项目、收藏一份流程。去找一个极小但真实的 RTL 设计目标,比如一个 8 位 CPU、一个串口控制器、一个自定义外设模块,按照“仿真 → 原型验证 → 综合 → 回片测试”的顺序走一遍。你不需要第一次就成功制造一颗复杂芯片,但你一定会第一次真正理解:什么叫做把一个想法落到物理世界,并且为它负责。