toffee验证规范
toffee验证规范
来源:[万众一芯开放验证](https://open-verify.cc/mlvp/docs/mlvp/canonical_env/)
1. 概述
一个验证任务编写代码的主体工作可以大致分为两部分,验证环境的搭建 和 测试用例的编写。
toffe将DUT的行为职责拆分为多个Agent,使之得到一个规范的验证环境。下面是一个无法复用的验证代码的例子:
def exec_add(dut, a, b):
dut.io_a.value = a
dut.io_b.value = b
dut.Step(1)
return dut.io_sum.value
直接使用DUT接口信号进行交互使得一个驱动函数只能驱动特定DUT,若更改信号名则测试函数直接失效。简单来说,直接对 DUT 的接口信号进行操作,如下图所示,这种做法是不可取的。
+-----------+ +-----------+
| |-->| |
| Test Code | | DUT |
| |<--| |
+-----------+ +-----------+
2. 验证代码与 DUT 解耦
将验证代码与 DUT 解耦,使用一个中间层与DUT交互,toffee中定义为Bundle。我们可以定义一个 Bundle 结构,其中包含 a, b 和 sum 三个信号,并让测试代码与这个 Bundle 进行直接交互。
def exec_add(bundle, a, b):
bundle.a.value = a
bundle.b.value = b
bundle.Step(1)
return bundle.sum.value
Bundle中的信号接口可以容易的与DUT连接,如果DUT的信号名发生了变化,只需要修改这个连接过程。此时的验证代码与 DUT 的关系如下图所示:
+-----------+ +--------+ +-----------+
| |->| | | |
| Test Code | | Bundle |-- connect --| DUT |
| |<-| | | |
+-----------+ +--------+ +-----------+
3. DUT接口的分类驱动
面临一个新的问题:DUT 的接口信号过于复杂,可能导致只有与原来接口结构相同的DUT才能与这个bundle连接。简单来说,我们可以将一个DUT的端口分解为若干公共项的集合,为每一个公共项定义一个BUndle,验证代码与 DUT 的关系可以用如下图所示:
+-----------+ +--------+ +-----------+
| |->| | | |
| Test Code | | Bundle |-- connect --| |
| |<-| | | |
+-----------+ +--------+ | |
| |
... ... | DUT |
| |
+-----------+ +--------+ | |
| |->| | | |
| Test Code | | Bundle |-- connect --| |
| |<-| | | |
+-----------+ +--------+ +-----------+
4. Agent
我们对单个 Test Code + Bundle 的组合起一个名字叫Agent。此时,我们的验证代码与 DUT 的关系如下图所示:
+---------+ +-----------+
| | | |
| Agent |----| |
| | | |
+---------+ | |
| |
... | DUT |
| |
+---------+ | |
| | | |
| Agent |----| |
| | | |
+---------+ +-----------+
4.1 Agent编写规范
按照验证代码是否主动发起交互,与接口的方向性来划分为以下几类交互:
- 验证代码主动发起
- 验证代码主动读取输入/输出端口的值
- 验证代码主动给输入端口赋值
- 验证代码被动接收
- 验证代码被动接收输出/输出端口的值
4.1.1 验证代码主动发起的交互
对于验证代码主动发起的交互,要求 Agent 必须具备两种能力:
- 驱动发起者能够将上层语义信息转换为对接口信号的赋值操作
- 能够将接口信号转换为上层语义信息并返回给发起者
toffee中规定使用函数来完成这两类交互。toffee 此类用于验证代码主动发起交互的函数称之为驱动方法,使用 driver_method 装饰器来标记。
4.1.2 验证代码被动接收的交互
这类交互的呈现形式为,验证代码并不去主动发起对接口的输入输出,而是当满足特定的条件时,接口会将输出信号传递给验证代码。
toffee 中同样规范了使用 函数 为载体来完成这类交互,这个函数没有输入参数,并且不受验证代码的主动控制。当特定条件满足时,该函数会被调用,完成对接口信号的读取操作,并转换为上层语义信息。
toffee 将此类用于验证代码被动接收交互的函数称之为监测方法,使用 monitor_method 装饰器来标记此类函数。
4.2 规范的Agent结构编写
我们使用函数来完成Agent的所有交互,分为驱动方法和监测方法,编写Agent即是编写驱动方法和监测方法。一个Agent结构可以用以下图描述:
+--------------------+
| Agent |
| |
| @driver_method |
| @driver_method |
| ... |
| |
| @monitor_method |
| @monitor_method |
| ... |
| |
+--------------------+
5. DUT 功能正确性验证
一个DUT功能的正确性,即是通过驱动方法主动获取的信息以及通过检测方法收集到的信息是否符合预期。
此时我们需要编写一个与 DUT 功能相同的参考模型(RM, Reference Model),DUT与参考模型的输入完全相同,对比验证两者所需输出是否相同。
5.1 添加参考模型
参考模型只需要实现当驱动函数被调用时,如何做出反应即可。toffee框架完成了将调用信息传递给参考模型、每一次操作的返回值、监测方法的检测值比较等工作。
测试用例中只需要编写驱动 DUT 的逻辑,参考模型的同步与比对工作将会被框架自动完成。
toffee 中定义了一套参考模型的匹配规范,只需要按照此规范编写参考模型调用接口,便可实现参考模型的自动转发与比较。同时为了方便参考模型与整个验证环境相关联,toffee 中提供了 Env 的概念来打包整个验证环境,写好参考模型后,只需要将其与 Env 相关联,便可实现参考模型的自动同步。
6. 总结
最终验证环境如下所示:
+--------------------------------+
| Env |
| +-----------+ | +-----------+
| +---------+ | | | | |
| | Agent |----| | |->| Reference |
| +---------+ | DUT | | | Model |
| +---------+ | | |<-| |
| | Agent |----| | | | |
| +---------+ | | | +-----------+
| ... +-----------+ |
+--------------------------------

浙公网安备 33010602011771号