oop面向对象特点:封装 继承 多态
将变量i的地址存放到指针变量p中,p就指向i
sv对象的引用是采用对象句柄(object handle),它与C指针概念接近,但又不完全相同
静态数组,动态数组或队列,是一样处理的
传递数组这种大片内存的值一般只有两种规则:
- 地址传递,函数内部修改可以改变函数调用的值。
- 值传递,将整片空间复制一份,函数内部修改不会改变函数调用的值。
// 函数f传入静态数组
function void run();
int r[2]; // 静态数组
r[0]=1;
r[1]=2;
f(r); // 函数f传入静态数组
$display("%0x %0x",r[0],r[1]);
endfunction
input是标准的值传递。 值传递,将整片空间复制一份,函数内部修改不会改变函数调用的值
// 函数f的定义
function void f(input int a[2]); // 传入数组类型为 input int
a[0]=3;
endfunction
输出结果:1 2
output 采用的是地址传递,确切的说是反向地址传递。 用新建的数组地址,替换原数组地址
// 函数f的定义
function void f(output int a[2]); // 数组类型为 input int
a[0]=3;
endfunction
输出结果是:3 0
ref采用的是标准的地址传递,只有一份数组,函数内部和调用出都是访问该空间
// 函数f的定义
function void f(ref int a[2]); // 数组类型为 ref int
a[0]=3;
endfunction
输出结果是: 3 2
- input 是将函数外面的值传递到函数里面,调用之后,函数里面的值就被丢弃
- output 是将函数里面的值传递到函数外面来,调用之后,函数外面的值就被丢弃
- ref 是函数内部和外部看到的是同一份值,哪里都会被修改
- 采用 ref 关键字,占用的空间内存是最小的,因为只有一份数组,这样能提高效率
SystemVerilog ref的使用:
ref 只能用于动态方法中: task automatic , 不加动态关键字 automatic 编译错误
ref使用时实参类型和形参类型必须完全匹配,eg:不能方法外是bit,方法内引用是int,编译错误:
class c;
int v0;
int v1;
endclass
function void run();
c c0; // 声明变量类型是c类
c0 = new(); // 实例化
c0.v0 = 1;
c0.v1 = 2;
f(c0);
$display(" %0x %0x ", c0.v0 ,c0.v1);
endfunction
function voidf(input/output/ref c c0);
c0.v0 =3;
endfunction
输出结果是:
input : 3 2
output :报null point 错误
ref: 3 2
class class_A;
int a;
function new(int a);
this.a = a;
endfunctionfunction void getA_ref(ref int a);
a = this.a;
endfunctionfunction void getA_value(int a);
a = this.a;
endfunctionfunction void setA(int a);
this.a = a;
endfunctionfunctionint getA();
return a;
endfunctionfunction void copy(class_A ca);
this.a = ca.a;
endfunction
endclassclass class_B;
class_A ca;
function new(class_A ca);
this.ca = ca;
endfunctionfunctionint setA(int a);
ca.setA(a);
endfunction
endclass
program automatic test;
initialbegin
class_A ca1;
class_A ca2;
class_B cb1;
int a = 1;
int b;
b = a; // 值拷贝
b = 2;
$display(a); // 因为b是值拷贝,修改b不影响a,所以输出1
ca1 = new(10);
ca1.getA_value(a); // 通过值传递方式获取函数内部值(且没有加output和inout)
$display(a); // 输出1,应为函数内部的a是a的一个值拷贝,函数修改不影响函数外的值。
ca1.getA_ref(a); // 同ref方式获取返回值。
$display(a); // a传递给函数内部的是引用,所以函数内部的修改,等效于修改了函数外的值。所以输出10
ca2 = ca1; // ca1为句柄变量,句柄拷贝
ca2.setA(20); // 通过句柄ca2修改内部的域。
$display(ca1.getA());// 因为ca2是ca1的句柄拷贝,所以ca2修改内部与,相当于修改了ca1的内部域,ca1和ca2指向相同空间。
cb1 = new(ca1);
cb1.setA(30);
$display(ca1.getA());// 输出30,通过非ref的参数传递ca1其实也是传递的是ca1的句柄,所以在函数内修改ca1能够体现到函数外。
ca2 = new(40); // 分配一块新的空间,让ca2指向,这个时候ca1和ca2指向了不同的空间。
$display(ca1.getA());// 输出30
$display(ca2.getA()); // 输出40end
endprogram
systemverilog 中的变量可以分为两种,一种普通变量类型,一种是句柄变量类型
- 内置类型,比如 int,bit,这些类型定义的变量都是普通变量
- 自定义的 class 通过 new 的方式定义的变量都是句柄变量
变量赋值
- 普通变量赋值,直接是拷贝值
- 句柄变量赋值,只是拷贝了句柄,使得两个句柄指向同一个空间
- system verilog 没有拷贝构造函数,所以句柄变量拷贝的时候只是进行了句柄的拷贝,没有进行指向空间的拷贝。为了完成指向空间的拷贝,一般实现的方式是先 new 一块空间,让后调用 copy 函数,copy 函数实现了拷贝构造函数的功能。
class_A ca1 = new(10);
class_A ca2 = new(12); // ca2要先new好,分配空间。
ca2.copy(ca1); // ca2拷贝ca1的数据