Verilog系列:不要随意new对象
`timescale 1 ns / 1 ps class cobj; int data; function new(int data); this.data = data; endfunction task void disp(); $display(“The cobj data is %h”,data); endtask endclass // cobj class cobj1; int data = 1; cobj pt = new(data); task void disp(); pt.disp; endtask endclass // cobj1 module top_tb; cobj1 ptr; initial begin ptr = new; ptr.disp; end endmodule // top_tb
【仿真结果】
The cobj data is 00000001!
在cobj1实例化时,首先会初始化其中的属性成员,14行"cobj pt"在声明的同时进行了实例化操作,其中调用构造函数时传递的参数在13行已经声明并且赋值,所以此时传递给new的参数数值为"1".所以在23行实例化cobj1后在24行通过cobj1的disp调用cobj的disp后的输出结果如上述的仿真结果.虽然这个结果可能时期望的,但是这种用法存在一种潜在问题,如下例.
【示例】
`timescale 1 ns / 1 ps class cobj; int data; function new(int data); this.data = data; endfunction task void disp(); $display(“The cobj data is %h”,data); endtask endclass // cobj class cobj1; cobj pt = new(data); int data = 2; task void disp(); pt.disp; endtask endclass // cobj1 module top_tb; cobj1 ptr; initial begin ptr = new; ptr.disp; end endmodule // top_tb
【仿真结果】
The cobj data is 00000000!
此例相对于上例仅仅是交换了13行和14行执行语句的顺序,但是仿真结果已经完全不一样了.主要是因为13行执行时,data此时还没有被初始化,所以此时传递给new的data的值为data数值类型的默认值,即0.等到14行执行时,"cobj pt"已经完成实例化,其中的值已经不能再被改变(除非通过cobj中相关的方法进行修改).同时,这样的coding方式,有些编译器会认为是错误的.这里需要注意,虽然很多语言存在所谓的并行语句结构(例如fork...join等),但是实际上其中语句的执行是按照一种"微观"的顺序依次执行(可使用仿真器的调试功能观测到具体语句的执行顺序),所以在这个件的结构中语句的执行顺序对于对象的实例化都会产生巨大的影响,可以想象在复杂设计中产生的影响可能更加复杂.为此,为了确保对象实例化后能够获得期望的数值,建议任何成员的初始化在new函数中进行,同时一定要秉持先定义后使用的原则,不要让仿真器去"猜测"语句的执行顺序.
【示例】
`timescale 1 ns / 1 ps class cobj; int data; function new(int data); this.data = data; endfunction task void disp(); $display(“The cobj data is %h”,data); endtask endclass // cobj class cobj1; int data; cobj pt; function new(); data = 3; pt = new(data); endfunction task void disp(); pt.disp; endtask endclass // cobj1 module top_tb; cobj1 ptr; initial begin ptr = new; ptr.disp; end endmodule // top_tb
【仿真结果】
此例中将所有成员的初始化都在构造函数中进行,并且确保各种变量的使用秉持"先定义后使用"的原则,这样可以确保程序执行的结果时期望的,并且可以确保任何成员在使用时具有确定的属性。