逻辑仿真(logic simulation)
在芯片还没变成硅片之前,你照样可以"运行"它——把它当成一段程序来跑。逻辑仿真接收你用硬件描述语言写的设计描述,再配上一个负责拨动输入的测试平台,然后随着一个虚拟时钟一拍一拍向前走,逐时刻算出每一根连线、每一个寄存器在做什么。你并不是把设计跑在硬件上,而是在自己的笔记本上跑它的一个模型,盯着结果看。
具体来说,仿真器会推进一个"仿真时间"的概念,并且只在有东西发生变化的地方才重新求值。把一个输入拉高,它就让这个跳变沿在逻辑中传播开来,安排下游的门电路和触发器按各自的延迟去更新,把这一时刻的一切都稳定下来,然后再处理下一个事件。正是这种事件驱动的循环,使得哪怕是一小段真实芯片行为,仿真起来也要慢上许多——每一次信号翻转,都是工具必须显式记录的一笔账。回报则是彻底的可见性:你可以把每一个节点都导出成波形,沿时间轴来回拖动,看清某个信号究竟是在什么时刻、为什么出了错。
同一套流程可以在不同的精细程度上运行。前期你仿真寄存器传输级——又快,又专注于一件事:逻辑功能对不对。到后期,经过逻辑综合之后,你可以拿反标了单元延迟的门级网表来仿真,确认网表的行为依然正确——抓出诸如复位和未知值(X)这类 RTL 容易掩盖的问题。但仿真并不是用来证明时序达标的,那是静态时序分析的活儿。仿真回答的只是一个问题——它做的事对不对?——这也正是为什么早在流片之前,它就是设计验证的中流砥柱。
`timescale 1ns/1ps initial begin clk = 0; forever #5 clk = ~clk; // toggle every 5 time units -> 10 ns period -> 100 MHz end
在 `1ns` 时间单位下,每隔 `#5` 翻转一次得到 10 ns 的周期——也就是一个仿真出来的 100 MHz 时钟。但 `#5` 的意思是"等 5 个时间单位",并不是任何芯片上真实的 5 纳秒;频率到底是多少,取决于时间刻度(timescale)怎么定。
"仿真通过"只意味着:对于你恰好施加的那组激励,设计做对了——这是证据,而非证明。覆盖率指标和形式验证之所以存在,正是因为任何现实可行的测试平台,都不可能把每一种可能的输入序列都跑一遍。