Function void create(ref transaction tr) Endfunction
方法的参数是句柄,句柄前有ref 和没ref的差别:
没ref,在方法中不能new()该句柄的对象,因为没ref,句柄是不能传递到主程序的; 有ref,可以在方法中new()该句柄的对象。
原因:没ref传递的是句柄,不能修改句柄,有ref,传递的是句柄的地址,可以修改句柄。
例子:
Function void create( Transcation tr) tr = new(); 不正确 tr.addr = 42; Endfunction
Transcation t; Initial begin Create(t); $diasplay (t.addr); End
l 程序中修改对象 背景:
应该在循环中,new()多个对象,而不是先new()对象再循环发送事物。 作用: 创建多个对象
正确产生器,创建多个对象: Task generator (int n); Transaction t; Repeat(n) begin t=new();
t.addr =$random(); transmit(t); endtask
将new()放在循环内,这样创建了许多对象。
l 对象的复制
目的:防止对象的方法修改原始对象的值。或在一个发生器中保留约束。 分两种情况,类中不包含其他类的句柄和包含 方法:
1) 使用new复制一个对象——简易复制(shallow copy) Transaction src,dst; Src = new() // dst = new src //复制 局限:
如果类中包含一个指向另外一个类的句柄,那么只有最高一级的对象被new复制,下层的对象都不会被复制。
会出现意想不到的错误。
当前类中变量和句柄被复制,这样两个对象,都有指向另外一个类的对象statistic(会带来意想不到的错误),但是statistic没有被复制。如果其中一个transaction对象,修改了statistic对象值,会影响到另一个transaction看到static的值。
2) 简单的复制函数 如何实现:
Copy函数一般放在类内部,函数名为该类的一个句柄,copy函数中new()对象。 局限:
类中不包含其他类。
3) 深层的复制函数 ——深层copy
目的:解决类中包含另外一个类,copy带来的问题。 实现:
在copy函数中,将调用另一个类的copy函数,赋值给该句柄;同时需要为statistic类和层次结构中每一个类增加一个copy()方法;copy函数的ID域也要保持一致,copy函数,copy本类,所以ID也要++.
Copy.stats = stats.copy();
Id =count++; 约束
l 约束块中,只能包含表达式,不能赋值。 1)dist权重分布
dist带有一个值的列表及相应的权重,中间用:= 或 :/分开。值或权重可以是常量或变量。权重的和不必是100.
:= 表示范围内,每一个值的权重是相同的; :/ 表示范围内,权重要均匀分布 2)Inside
产生一个值的集合,在值的集合中取随机值时,机会相等。 3)在集合中使用数组 l 条件约束
Systemverilog支持两种关系操作 –>和if—else
—>可产生和case效果类似的语句块,可以用于枚举类型的表达式。 l 双向约束 l 控制多个约束块
作用:可以打开或关闭某个约束
可以使用内建的Handle.constraint.constraint_mode()打开或关闭。 l 内嵌约束
背景:很多测试只会在代码的一个地方随机化对象,但是约束越来越复杂时, Systemverilog可以使用randomized with 来增加额外的约束,这和在类里增加的约束是等效的。
l Pre_randomize 和post_randomize函数
有时候需要再调用randomize()之前或之后立即执行一些操作。 随机化前:设置类里的一些非随机变量(如上下限、权重), 随机化后:计算数据的误差矫正值。 l 约束的技巧 1) 约束中使用变量 2) 使用非随机值
如果一套约束在已产生了几乎所有想要的激励向量,但还缺少几种。 可以使用rand_mode把这些变量设置为非随机变量。 l 数组约束
Systemverilog可以用foreach对数组中的每一个元素进行约束。
线程及线程间的通信
l 测试平台使用许多并发执行的线程。测试平台隶属于程序块。
Systemverilog引入两种新的创建线程的方法—fork…join_none和fork…join_any 1) 使用fork…join_none来产生线程 在调度其内部语句时,父线程继续执行。 2) 使用fork…join_any实现线程同步
在调度块内语句,当第一个语句执行完,父线程才继续执行。
l 动态线程
Systemverilog中可以动态创建线程。 用法:
fork…join_none放在了任务中,而不是包含两个线程。 原因:
主程序中有连个线程:发送和检测线程。但是不能同时启动,发送事物后,才能检测,否则还未产生数据,就开始检测;但是检测又不能阻塞下一次发送事物的线程。所以fork…join_none 放在了检测task 任务(后作用的线程中)中,
例:测试平台产生随机事物并发送到DUT中,DUT把事物返回到测试平台。测试平台必须等到事物完成,但同时不希望停止随机事物的发送。
Program automatic test(bus_ifc.Tbbus); Task check_trans(Transaction tr); Fork Begin
Wait(bus.cb.addr == tr.addr); End Join_noe Endtask
Initial begin Repreat(10) begin Tr= new();
Assert.(tr.randomize()); //把事物发送到DUT中 Transmit(tr); //等待DUT的回复 Check_trans(tr); End #100; End endprogram
l 并发线程中务必使用自动变量来保持数值。
l #0 延迟,使得当前线程必须等到fork…join_none语句中产生的线程执行完后,才得以运行。
l 停止线程 1) 停止单个线程
使用fork ..join_any 后加disable。 3) 停止多个线程
Disable fork 能停止从当前线程中衍生出来得所有子线程。
应该使用fork ..join 把目标代码包含起来,以限制Disable fork的作用范围。
l 事件 背景:
Verilog中当一个线程在一个事件上发生阻塞的同时,正好另一个线程触发了这个事件,则竞争就出现了。如果触发线程先于阻塞线程,则触发无效(触发是一个零宽度的脉冲)。
解决方法: