UVM(通用验证方法学)
假设你设计好了一个复杂的芯片模块,现在要证明它确实能工作。你可以为它手写一个一次性的测试程序——可问题是,下一个工程师在做下一个模块时又得从头来过,谁的测试都长得不一样,彼此之间也无法对话。UVM 就是业界对这团乱麻的回应:一个庞大的、预先搭好的 SystemVerilog 类库,把现成的零件——驱动器(driver)、监视器(monitor)、记分板(scoreboard)、序列发生器(sequencer)——直接交到你手上,让所有人都用同一套积木、以同样的方式搭建测试平台,并在一个个项目之间反复复用。
更准确地说,UVM(通用验证方法学)是一套标准化的框架——先是 Accellera 标准,后被采纳为 IEEE 1800.2——用来构建大型、分层的验证环境。它真正的威力在于结构加激励。结构是一棵由可复用组件构成的树:一个代理(agent)封装了驱动器(负责拨动被测设计的引脚)、监视器(负责观察这些引脚)和序列发生器(负责喂入激励);再往上,记分板检查输出是否与预期相符。激励这一侧则建立在约束随机序列之上——你不必再一个个手写测试向量,UVM 会生成海量合法但不可预测的事务,并通过功能覆盖率追踪设计的哪些角落已经被真正触及。
让 UVM 之所以“通用”的,是这些部件在设计上彼此解耦。事务级建模(TLM)通过抽象的端口连接各组件,于是监视器并不关心谁在收听;工厂(factory)让你能在运行时换入另一个驱动器或序列,而无需改动环境;配置数据库(configuration database)则把设置沿层级往下传递。回报是一块验证 IP——比如一个 UART 或 PCIe 代理——团队几乎只需重新接好它的接口,就能把它放进一颗完全不同的芯片里。代价则是陡峭的学习曲线:UVM 很重,连一个“hello world”级别的测试平台都得写上意外地多的样板代码。
class bus_txn extends uvm_sequence_item;
rand bit [31:0] addr;
rand bit [31:0] data;
rand bit write;
`uvm_object_utils(bus_txn)
function new(string name = "bus_txn");
super.new(name);
endfunction
// keep generated addresses word-aligned
constraint c_align { addr[1:0] == 2'b00; }
endclass最小的可复用单元是一个事务(transaction)——它是描述一项激励的普通对象,而非信号本身。一次总线写操作可以这样建模,其中带约束的随机字段供序列发生器稍后随机化。
“通用”二字带着几分愿景色彩。UVM 直接脱胎于 OVM(开放验证方法学,由 Cadence 与 Mentor Graphics 联合开发),Accellera 在 2011 年前后将其采纳并扩展为 UVM;Synopsys 也加入了进来——而 UVM 本意正是要取代它那套对手方法学 VMM。最终的成果,是把一片互不兼容、被各家厂商锁定的测试平台框架整合成了一套统一的标准。