1.总共分三个部分,test.sv router_io.sv router_test_top.sv , router.v是DUT部分
1.1 test.sv部分是给出一个复位信号
代码如下:
program的作用:
1)验证程序执行的主要结构和入口
2)它提供了一个封装验证程序数据,函数,任务的结构
3)它提供了一个语法来指定在Reactive区域中的调度执行
使用方法和目的:
1)在程序块中,要采用非阻塞赋值语句(<=)对时钟块(clocking block)中的信号做驱动
2)在程序块中的本地变量进行赋值要采用阻塞赋值语句(=)
3)程序块中可以有任务,函数,类,initial块,但是不能有always块
4)对封装验证程序的程序块采用 automatic 来定义
其中,给出了一个复位的 task 模块,分别对 reset_n frame_n valid_n 进行复位,可以看到的是,9行是阻塞赋值,剩下的 10-12行中的信号都是非阻塞赋值可以得到cb(时钟块)中的信号必须使用非阻塞赋值。
而且可以在9行,12行,知道 异步复位,同步释放(为了防止亚稳态)
波形图:
可以看到reset_n信号在 51ns 被拉高了
同样的frame_n 和 valid_n 也在51ns 被置为了高位,可代码中,明明写的是#2 复位信号才被置高,为什么它和下面两个信号在同一时间出现呢?
解答:可以看到复位信号被置为高时,是cb.reset_n 也就是属于时钟模块,那么就是非阻塞赋值,同步释放,等到cb模块被驱动才触发,时钟在50ns上升沿的时候,时钟模块里面也规定了,输入输出都是要延时1ns。
故整个复位代码执行顺序如下:
- 0ns进入,先执行reset_n = 0 ,因为是阻塞赋值
- 10行-12行都是非阻塞,故挂起,等待,要等到时钟模块被触发才顺序执行
- 执行13行 cb 时钟模块执行一次,50ns,
- 进而,因为cb模块第一次被触发,10行-12行可以顺序执行了,故开始时间是51ns,reset_n的2ns相在等待时钟模块的50ns已经消耗完了
- 整个过程是15次时钟触发,故总时间是50ns+14*100ns = 1450ns,
- 第十五次的时钟为什么没有完整呈现,只有上升沿?
整个的波形如下:
1.2. router_io.sv 是interface(接口)部分
代码如下:
接口部分作用:是为了连接router_test_top和test的
其中 modport TB(clocking cb, output reset_n),作用是
interface中的 modport优缺点:
优点:
1、接口便于重用
2、接口可以用来代替原来需要反复声明并且位于代码内部的一系列信号,减少了连接错误的可能
3、要增加一个新的信号时,在接口中只需要声明一次,而不需要在更高层的模块声明
4、modport允许一个模块很方便的将接口中的一系列信号捆绑到一起,也可以为信号指定方向一方便工具自动检查。
缺点:
1)必须同时使用信号名与接口名、可能会使得模块变得更加冗长
2)连接两个不同的接口很困难。一个新的接口可能包含了现有的所有信号并新增了信号。你需要拆分出独立的信号并且正确地驱动。
1.3 router_test_top.sv 是顶层部分
代码如下:
$timeformat(-9, 1, "ns", 10) 表示:10^(-9)单位是 ns
顶层模块的作用:对Program 和 DUT 实例化并连接,并实现 router_io test 的实例化,
连接代码如下:
router_io top_io(SystemClock);
test t(top_io);
连接图: