句柄可以作为形式参数通过方法来完成对象指针的传递, 从外部传入方法内部
句柄也可以在方法内部首先完成修改, 而后再由外部完成使用。
- function void create(Transaction tr); // Bug, missing ref
- tr = new();
- tr.addr = 100; //initialize other fields
- ...
- endfunction
-
- Transaction t; //此时默认句柄悬空为null
- initial
- begin
- create(t);
- t.addr = 10;
- $display(t.addr);
- end
最后显示的t.addr的值为多少?(报错)
function函数没有声明方向默认为输入,调用create()函数是不返回值的,所以句柄悬空,报错。可以通过在create()函数中添加output/ref 来实现代码功能。
在程序执行时, 可以在任何时刻为句柄创建新的对象, 并将新的指针赋值给句柄。
- task generate_trans();
- Transaction t;
- Transaction fifo[$];
- t = new();
- for(int i=O; i<3; i++)
- begin
- t.addr = i << 2;
- fifo.push_back(t);
- end
- t=fifo.pop_front();
- endtask
t.addr的值为?8
使用包的好处在于将—簇相关的类组织在了单—的命名空间(namespace)下,使得分属于不同模块验证环境的类来自于不同的package,这样便可以通过package来解决类的归属问题。
- package regs_pkg;
- `include"s七imula七or.sv"
- `include"moni七or.sv"
- `include"chker.sv"
- `include"env.sv"
- endpackage
-
- package arb_pkg;
- `include "stimulator.sv"
- `include"monitor.sv"
- `include"chker.sv"
- `include"env.sv"
- endpackage
• 两位verifier在各自的package regs_pkg和arb_pkg中都定义了4个与模块验证相关的类即stimulator、monitor、checker 和env。而这两个package中同名的类,它们的内容是不相同的, 实现的也是不同的功能。
• 如果我们将这些重名的类归属到不同的package中编译,有没有问题呢?会不会发生重名的编译冲突?不需要为此担心, package是将命名空间分隔开来,这样如果要使用不同
package中的同名类,他们只需要注明要使用哪一个package中的。
- module mcdf_tb;
- regs_pkg::monitor monl = new ();
- arb_pkg:::monitor mon2 =new();
- endmodule
库和类的区分:
尽管在regs_pkg和arb_pkg中都存在着—个名字为monitor的类,我们可以在引用类名的时候通过域名索引“::”操作符的方式来显式指出所引用的monitor类具体来自于哪一个package, 这样便能很好地通过不同名的package来管理同名的类。从这个简单的例子来看, package这个容器可以对类名做一个隔离的作用。
package更多的意义在于将软件(类、类型、方法等)封装在不同的命名空间中,以此来与全局的命名空间进行隔离。package需要额外定义,容纳各种数据、方法和类。
library是编译的产物,在没有介绍软件之前,硬件(module、interface、program)都会编译到库中,如果不指定编译库的话,会被编译进入默认的库中。从容纳的类型来看,库既可以容纳硬件类型,也可以容纳软件类型,例如类和方法,也包括package。
• 使用 'include的关键词完成类在包中的封装,要注意编译的前后顺序来放置各个 'include的类文件。
• 编译—个包的背后实际是将各个类文件“平铺”在包中, 按照顺序完成包和各个类的有序编译。
• 使用类的可以通过'import'完成包中所有类或者某一个类的导入, 使得新的环境可以识别出该类, 否则类会躺在包这个盒子里不被外部识别。