当前位置:网站首页>【数字IC验证快速入门】15、SystemVerilog学习之基本语法2(操作符、类型转换、循环、Task/Function...内含实践练习)
【数字IC验证快速入门】15、SystemVerilog学习之基本语法2(操作符、类型转换、循环、Task/Function...内含实践练习)
2022-07-07 04:43:00 【luoganttcc】
导读:作者有幸在中国电子信息领域的排头兵院校“电子科技大学”攻读研究生期间,接触到前沿的数字IC验证知识,旁听到诸如华为海思、清华紫光、联发科技等业界顶尖集成电路相关企业面授课程,对数字IC验证有了一些知识积累和学习心得。为帮助想入门前端IC验证的朋友,思忱一二后,特开此专栏,以期花最短的时间,走最少的弯路,学最多的IC验证技术知识。
文章目录
一、内容概述
- SystemVerilog 操作符
- SystemVerilog 过程语句
- SystemVerilog 变量类型转换
- SystemVerilog 循环控制语句
- SystemVerilog 增强case语句
- SystemVerilog 任务(task)和函数(function)
二、操作符(Operation)
- 全等于
===
还会去比较x/z
三、SystemVerilog 过程语句(Procedural Statements)
3.1、自增和自减操作符
- 类似C语言
- 先增/减后用和先用后增/减
注:SystemVerilog的自增和自减通常用在TB里,不会用在RTL代码中!
3.2、逻辑比较操作符
等于
==
,不等于!=
(用的比较多,一般有x
态有问题)- 逻辑真为1,逻辑假为0;
- 如果比较的值中存在x和z,则逻辑值为1’bx
- eg:
a=4'b000x
和b=4'b000x
两个比较结果为1'bx
,那这里就有坑了如果if(a == b)
,注意1'bx
是不为真!
- eg:
全等
===
,不全等!==
- 完全匹配四种状态值:
0,1,x,z
- eg:
a=4'b000x
和b=4'b000x
两个比较结果为1'b1
- eg:
- 完全匹配四种状态值:
通配符逻辑比较
- 匹配等
==?
和匹配不等!=?
- 按位比较,把
x
和z
值当做匹配值 - 仅仅把右侧操作数中的
x
和z
当做屏蔽符号- eg:
4‘b1010 ==? 4'b101x
匹配等返回1'b1
;4‘b1011 ==? 4'b101x
匹配等返回1'b1
- eg:
- 按位比较,把
- 匹配等
- 匹配符逻辑比较的示例
- 打印出第一个
$display
注:上述截图中的注释和
display
语法稍有问题。
3.3、inside 关键字
- inside可以匹配一组数据范围内的任何一个数值
四、变量类型转换(Type Casting)
4.1、变量类型转换符type' (expression)
- SystemVerilog 增加了变量类型转换符:
type' (expression)
- 变量类型转换符可以在任何时刻对表达式进行类型转换
- 而不像Verilog一样只能发生在赋值语句中
4.2、$cast
强制类型转换
$cast(fsm, 1+2)
:把3
赋值给fsm,并把整型强制类型转换为枚举类型,即此时fsm为DATA
4.3、变量位宽转换(Size Casting)
- SystemVerilog 增加了矢量位宽转换
size' (expression)
- 表达式转换成小位宽时,左侧的比特位被删除
- 表达式转换成大位宽时,左侧的比特位被扩充
4.4、变量符号位转换
- SystemVerilog 可以转换符号位
signed' (expression)
和unsigned' (expression)
- 操作数符号位转换
- 表达式结果符号位转换
五、SystemVerilog 循环控制语句
5.1、for循环语句
Verilog 中循环变量必须在for语句之外声明
- 当前循环与其他语句相互影响
SystemVerilog 可以在for循环内部声明循环变量
- 每个变量都为本地的唯一变量,所以外部使用的相同名字的变量不会相互影响
- 本地循环变量是自动化的(automatic)
- for循环内部声明的本地变量在循环语句之外就不存在了
- 在Verilog中描述组合逻辑和时序逻辑都是用
always
关键字,时序逻辑always @(posedge clk)
;组合逻辑always @(*)
- 在SystemVerilog中,描述时序逻辑用
always_ff @(posedge clk)
或者always @(posedge clk)
;组合逻辑always_comb @(*)
或always @(*)
continue
- 只能用于循环语句
- 结束本次循环,继续下一次循环
break
- 只能用于循环语句
- 破坏循环,跳出循环,不再执行本次循环语句
return
- 可以用于循环语句
- 结束循环
- 也可以用于task和function
- 结束task和function
- 可以用于循环语句
5.2、do...while
循环语句
- Verilog 中的while循环不一定执行
- 如果第一次循环表达式的值为假,则循环语句不会执行
- SystemVerilog 增加了
do...while
循环语句(类似C语言)- 至少执行一次循环语句
- 在循环语句的最后判断循环变量
5.3、SystemVerilog 增强case语句 - case/casex/casez
- default 是可选项,在一个case语句中不能使用多个default
- 首先计算case表达式的值,然后跟下面的实际分支进行匹配,匹配到就执行相应的语句
- case表达式的值是按位分配,可以处理
x和z
casez
- 不关心
z
- 不关心
注:问号表示通配符
casex
- 不关心
z
和x
- 不关心
- 当
field = 8'b01100110
时,casex选择分支statement2执行 field ^ mask = x1x0x1x0
六、SystemVerilog 任务(task)和函数(function)
6.1、Verilog task 和 function概述
function
- 函数执行的时候不消耗仿真时间
- 函数中不能有控制仿真时间的语句
- 不能有仿真时间延迟:#100 =(`timescale 1ns/10ps)
- 不能有阻塞语句:
@(posedge clock)
或者wait(ready)
- 不能调用task
void function
没有返回值- Verilog 的
function
必须有一个返回值(Verilog通过函数名返回!)
- Verilog 的
function int sum(input x, y);
sum = x + y;
return sum;
endfunction
- 1
- 2
- 3
- 4
- task
- task含有input、output和inout语句
- task消耗仿真时间
- 延迟:#20
- 时钟周期:@(posedge clock)
- 事件:event
6.2、SystemVerilog task
和 function
- tasks 和 function
- 不需要使用begin…end语句
- 增加了
return
语句- 返回值只有1个用return;返回
bit/logic
这种简单类型的变量
- 返回值只有1个用return;返回
void function
没有返回值function
可以有output
和inout
作为形式参数- 返回值大于1个时,用output返回比较方便;返回
array/queue/struct
复杂的用output
- 返回值大于1个时,用output返回比较方便;返回
可以这样类比,function不带时序信息,通常来讲描述组合逻辑;task可以带时序信息,既可以描述组合逻辑,也可以描述时序逻辑!
- return 语句
- SystemVerilog 增加了return语句
- return 语句执行时返回表达式的值,否则最后的返回数值赋值给函数名
- return 语句用于退出task和function
void function
- void function 没有返回值
output
和inout
形式参数为void function 提供了传递变量的途径void function
可以像task一样被调用,但必须跟函数的内容约束一致
- 通过名字传递task和function参数
- SystemVerilog 通过形式参数的名字传递参数
- 减少错误
- 参数的顺序不受限制
- 传递参数的语法与Verilog端口连接的方式相同
- SystemVerilog 通过形式参数的名字传递参数
SystemVerilog 增强函数形式参数
- 增加了input和output
形式参数的默认方向和类型
- 每一个形式参数都有一个默认的类型
- 调用task和function时,不必给具有默认参数值的参数传递参数
- 如果不传递参数值,就会使用默认值
eg:
always_ff @(posedge clock)
result = incrementer(data_bus);//没有显式传递的参数使用默认值,即result = data_bus + 1;
- 1
- 2
使用引用(reference
)替代复制的方式传递参数
- 常见的向任务(task)和函数(function)传递参数值的方法是复制
- 使用引用(reference)的方式显式的向任务(task)和函数(function)传递参数
- 关键字是:
ref
(取代了input, output 或者 inout) - 只有自动(
automatic
)任务和函数才可以使用ref
参数
- 关键字是:
(8*i)+:8
中的:
含义:把for循环展开,比如当i=0时,(8*0)+:8
表示0:0+8(0:8)
;当i的=1时,(8*1)+:8
表示8:16
,这样通过for循环,遍历了data[63:0]
- 表达一个向量可以有三种表示方法:
[MSB:LSB]
、[MSB-:WIDTH]
、[LSB+:WIDTH]
,如依次对应[7:0]
、[7-:8]
([7:0]
)、[0+:8]
([0:7]
)
使用引用(reference)替代复制的方式传递参数
- 通过引用传递的参数可以是只读(read-only)
- 允许 task/function 在调用的范围内引用信息
- 阻止 task/function 修改引用的信息
- 修改task ref参数是非常敏感的
- ref参数可以读取当前的值
- ref参数可以立即传递信息的变化
参数传递
- 参数类型默认情况下与左侧的参数类型保持一致
- input - 默认情况下,在开始时输入复制一份数值
- output - 在结束时输出复制一份数值
- inout - 在开始时输入,在结束时输出,一份复制的数值
- ref - 通过引用的方式传递,效果立即显现
- 当传递数组给task和function时,可以节省时间和内容
- const - 参数不允许修改
常见面试题:task和function区别?
- a. 消耗仿真时间与否,即task可以有消耗仿真时间的语句,function不能有消耗时间的语句,task不一定就消耗仿真时间。
- b. task可以调用function,function不能调用task。
- c. 在verilog中: task可以返回多个值(output),function只能返回一个值
- d. task是没有return的, void function也是没有return的
task和function是否可以被综合?
- 能否被综合,取决于使用者在里面的语句是RTL还是行为级描述
- 比如task或function中有
$display("xxx");
,那么这个task或function肯定是不能被综合的。wait/#10
等也是不能被综合的!
七、实践练习
7.1 逻辑操作符和运算操作符练习
7.1.1、比较运算符demo
sv_operation.sv
module SV_OPERATION();
bit sig_a;
bit sig_lgc_inv_a;
bit sig_bit_inv_a;
bit [2:0] sig_m_a;
bit [2:0] sig_m_lgc_inv_a;
bit [2:0] sig_m_bit_inv_a;
bit signed [7:0] sig_c;
bit signed [7:0] sig_lgc_lft_c;
bit signed [7:0] sig_lgc_rgt_c;
bit signed [7:0] sig_arth_lft_c;
bit signed [7:0] sig_arth_rgt_c;
int i;
logic [7:0] comp_a;
logic [7:0] comp_b;
logic [2:0] a;
logic comp1 [8];
logic comp2 [8];
initial begin
sig_a = 1'b0; sig_m_a = 3'b010;
sig_c = 8'sb1100_0111; sig_lgc_inv_a = !sig_a; sig_bit_inv_a = ~sig_a; sig_m_lgc_inv_a = !sig_m_a; sig_m_bit_inv_a = ~sig_m_a; comp_a = 8'b0100_1101;
comp_b = 8'b0100_1100; if(comp_a == comp_b) begin $display("******comp_a: %b == comp_b: %b", comp_a, comp_b); end else begin $display("******comp_a: %b != comp_b: %b", comp_a, comp_b); end if(comp_a === {comp_b[7:1], 1'bx}) begin
$display("******comp_a: %b === {comp_b[7:1], 1'bx}: %b", comp_a, {
comp_b[7:1], 1'bx}); end else begin $display("******comp_a: %b !== {comp_b[7:1], 1'bx}: %b", comp_a, {comp_b[7:1], 1'bx}); end if(comp_a ==? {comp_b[7:1], 1'bx}) begin $display("******comp_a: %b ==? {
comp_b[7:1], 1'bx}: %b", comp_a, {comp_b[7:1], 1'bx});
end
else begin
$display("******comp_a: %b !=? {comp_b[7:1], 1'bx}: %b", comp_a, {
comp_b[7:1], 1'bx});
end
end
endmodule
rslt.log
******comp_a: 01001101 != comp_b: 01001100
******comp_a: 01001101 !== {
comp_b[7:1], 1'bx}: 0100110x ******comp_a: 01001101 ==? {comp_b[7:1], 1'bx}: 0100110x
- 1
- 2
- 3
- Makefile 同第14篇博文,不过是
comp_file
参数变了:make comp_file=sv_operation.sv
sig_a
表示单比特,sig_m_a
表示多比特sig_c = 8'sb1100_0111;
中的s表示有符号- 单比特逻辑取反
!
和按位取反~
一样;但是多比特不一样! comp_xxx
表示比较用的变量
7.1.2、逻辑运算符!
和算术运算符~
的差异demo
sv_operation.sv
$display("******single bit logic invertor ! :sig_a is : %b, sig_lgc_inv_a is : %b", sig_a, sig_lgc_inv_a);
$display("******single bit bit invertor ~ :sig_a is : %b, sig_bit_inv_a is : %b", sig_a, sig_bit_inv_a);
$display("******multiple bit logic invertor ! :sig_m_a is : %b, sig_m_lgc_inv_a is : %b", sig_m_a, sig_m_lgc_inv_a);
$display("******multiple bit bit invertor ~ :sig_m_a is : %b, sig_m_bit_inv_a is : %b", sig_m_a, sig_m_bit_inv_a);
rslt.log
******single bit logic invertor ! :sig_a is : 0, sig_lgc_inv_a is : 1
******single bit bit invertor ~ :sig_a is : 0, sig_bit_inv_a is : 1
******multiple bit logic invertor ! :sig_m_a is : 010, sig_m_lgc_inv_a is : 000
******multiple bit bit invertor ~ :sig_m_a is : 010, sig_m_bit_inv_a is : 101
- 对于单比特逻辑取反
!
和按位取反~
无差别;而多比特是有差别的
7.1.3、移位操作demo
sv_operation.sv
sig_lgc_lft_c = sig_c << 5; sig_lgc_rgt_c = sig_c >> 5; sig_arth_lft_c = sig_c <<< 5; sig_arth_rgt_c = sig_c >>> 5; $display("******logical left shift << :sig_c is : %b, sig_lgc_lft_c is : %b", sig_c,sig_lgc_lft_c); $display("******logical right shift >> :sig_c is : %b, sig_lgc_rgt_c is : %b", sig_c,sig_lgc_rgt_c); $display("******arithmetic left shift <<< :sig_c is : %b, sig_arth_lft_c is : %b", sig_c,sig_arth_lft_c); $display("******arithmetic right shift >>> :sig_c is : %b, sig_arth_rgt_c is : %b", sig_c,sig_arth_rgt_c);
rslt.log
******logical left shift << :sig_c is : 11000111, sig_lgc_lft_c is : 11100000 ******logical right shift >> :sig_c is : 11000111, sig_lgc_rgt_c is : 00000110 ******arithmetic left shift <<< :sig_c is : 11000111, sig_arth_lft_c is : 11100000 ******arithmetic right shift >>> :sig_c is : 11000111, sig_arth_rgt_c is : 11111110
- 逻辑左移/右移,移完之后就用
0
来补 - 算数左移同逻辑左移;算数右移如果最高位为
1
,那么就补1
。同理如果最高位为0
,那么就补0
7.1.4、++i
和i++
区别demo
sv_operation.sv
i = 0;
while(i++ < 5) begin
$display("****** the i++ i %d", i);
end
i = 0;
while(++i < 5) begin
$display("****** the ++i i %d", i);
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
rslt.log
****** the i++ i 1
****** the i++ i 2
****** the i++ i 3
****** the i++ i 4
****** the i++ i 5
****** the ++i i 1
****** the ++i i 2
****** the ++i i 3
****** the ++i i 4
7.1.5、inside
关键字demo
sv_operation.sv
for(int i=0; i<8; i++) begin a = i[2:0]; if(a==3'b100 || a==3'b101 || a==3'b011) begin comp1[i] = 1'b1; end else begin comp1[i] = 1'b0; end if(a inside{3'b100, 3'b101, 3'b011}) begin comp2[i] = 1'b1; end else begin comp2[i] = 1'b0; end end if(comp1 == comp2) begin $display("******comp1 == comp2"); end else begin $display("******comp1 != comp2"); end
rslt.log
******comp1 == comp2
- 1
7.2、循环练习
7.2.1、不同的initial
块共用同一个全局变量demo
sv_loop_case.sv
module sv_loop_case();
int j;
int i;
initial begin : loop0
for(i=0; i<5; i++) begin
#1;
$display("******loop0 i = %0d", i);
end
end
initial begin : loop1
for(i=0; i<5; i++) begin
#1;
$display("******loop1 i = %0d", i);
end
end
endmodule
******loop0 i = 0
******loop1 i = 1
******loop0 i = 2
******loop1 i = 3
******loop0 i = 4
******loop1 i = 5
- 可以看到两个initial 块共用同一个全局变量i,for循环有影响!
7.2.2、不同的initial
块使用本地变量demo
sv_loop_case.sv
module sv_loop_case(); //int j; //int i; initial begin : loop0 for(int i=0; i<5; i++) begin //注意看这里面定义了int,此时称为本地变量! #1; $display("******loop0 i = %0d", i); end end initial begin : loop1 for(int i=0; i<5; i++) begin #1; $display("******loop1 i = %0d", i); end end endmodule
rslt.log
******loop0 i = 0 ******loop1 i = 0 ******loop0 i = 1 ******loop1 i = 1 ******loop0 i = 2 ******loop1 i = 2 ******loop0 i = 3 ******loop1 i = 3 ******loop0 i = 4 ******loop1 i = 4
- 可以看到两个intial块的for循环不影响!
7.2.3、不同的initial
块使用automatic
定义变量demo
sv_loop_case.sv
module sv_loop_case(); //int j; //int i; initial begin : loop0 automatic int i; for(i=0; i<5; i++) begin #1; $display("******loop0 i = %0d", i); end end initial begin : loop1 automatic int i; for(int i=0; i<5; i++) begin #1; $display("******loop1 i = %0d", i); end end endmodule
rslt.log
******loop0 i = 0 ******loop1 i = 0 ******loop0 i = 1 ******loop1 i = 1 ******loop0 i = 2 ******loop1 i = 2 ******loop0 i = 3 ******loop1 i = 3 ******loop0 i = 4 ******loop1 i = 4
- 可以看到使用automatic定义变量和使用本地变量的效果相同,两个initial块的for循环也是互不影响
7.2.4、while
和 do...while
执行过程demo
sv_loop_case.sv
initial begin j = 0; do begin $display("******%d th loop in do while loop", j); j++; end while(j<0); j=0; while(j<0) begin $display("******%d th loop in while loop", j); j++; end end
rslt.log
****** 0 th loop in do while loop
- 1
- 可以看到
do...while
会先执行一次,再进行判断
7.3、case/casez/casex分支区别练习
sv_loop_case.sv
logic [3:0] sel_z = 4'bz01z; logic [3:0] sel_x = 4'bx01x;
initial begin
case(sel_z)
4'b1??? : $display("****** sel_z(%0b) is 4'b1??? in case selection", sel_z); 4'b01?? : $display("****** sel_z(%0b) is 4'b01?? in case selection", sel_z); 4'b001? : $display("****** sel_z(%0b) is 4'b001? in case selection", sel_z);
4'b0001 : $display("****** sel_z(%0b) is 4'b0001 in case selection", sel_z); default : $display("****** sel_z(%0b) is in default branch in case selection", sel_z); endcase casez(sel_z) 4'b1??? : $display("****** sel_z(%0b) is 4'b1??? in casez selection", sel_z); 4'b01?? : $display("****** sel_z(%0b) is 4'b01?? in casez selection", sel_z);
4'b001? : $display("****** sel_z(%0b) is 4'b001? in casez selection", sel_z); 4'b0001 : $display("****** sel_z(%0b) is 4'b0001 in casez selection", sel_z); default : $display("****** sel_z(%0b) is in default branch in case selection", sel_z); endcase case(sel_x) 4'b1??? : $display("****** sel_x(%0b) is 4'b1??? in case selection", sel_x);
4'b01?? : $display("****** sel_x(%0b) is 4'b01?? in case selection", sel_x); 4'b001? : $display("****** sel_x(%0b) is 4'b001? in case selection", sel_x); 4'b0001 : $display("****** sel_x(%0b) is 4'b0001 in case selection", sel_x);
default : $display("****** sel_x(%0b) is in default branch in case selection", sel_x);
endcase
casex(sel_x)
4'b1??? : $display("****** sel_x(%0b) is 4'b1??? in casex selection", sel_x); 4'b01?? : $display("****** sel_x(%0b) is 4'b01?? in casex selection", sel_x); 4'b001? : $display("****** sel_x(%0b) is 4'b001? in casex selection", sel_x);
4'b0001 : $display("****** sel_x(%0b) is 4'b0001 in casex selection", sel_x); default : $display("****** sel_x(%0b) is in default branch in case selection", sel_x);
endcase
end
rslt.log
****** sel_z(z01z) is in default branch in case selection
****** sel_z(z01z) is 4'b1??? in casez selection ****** sel_x(x01x) is in default branch in case selection ****** sel_x(x01x) is 4'b1??? in casex selection
- 1
- 2
- 3
- 4
casez
不关心z
,即z
可以当做0或1。casex
不关心z
和x
,即x
和z
可以当做0或1。- 问号表示通配符,case里面的通配
?
,只代表0和1;casez里面的?
通配,可以代表0/1/z
;casex里面的?
通配,可以代表0/1/x/z
。 z01z
和001?
也是可以匹配上的,不过已经匹配了前面的1???
,所以后面的001?
就不再匹配了- 在case中,如果有个分支是
z01z
,那么sel_z是可以匹配上这个分支的,严格匹配!
7.4、task/function 练习
7.4.1、function 封装结构体demo
sv_function_task.sv
module sv_function_task();
typedef struct {
int height;
int weight;
logic [7:0] legs;
logic [1:0] hands;
logic [1:0] eyes;
logic noses;
}animal;
animal duck;
animal dog;
animal d;
logic [76:0] data_in;
string name;
initial begin
duck.height = 32'd132; duck.weight = 32'd200;
duck.legs = 8'd2; duck.hands = 2'd2;
duck.eyes = 2'd2; duck.noses = 1'd1;
$display("******@%0tns duck unpacked value ******", $time);
$display("******@%0tns duck height : %0d ****", $time, duck.height);
$display("******@%0tns duck weight : %0d ****", $time, duck.weight);
$display("******@%0tns duck legs : %0d ****", $time, duck.legs);
$display("******@%0tns duck hands : %0d ****", $time, duck.hands);
$display("******@%0tns duck eyes : %0d ****", $time, duck.eyes);
$display("******@%0tns duck noses : %0d ****", $time, duck.noses);
dog.height = 32'd232; dog.weight = 32'd100;
dog.legs = 8'd4; dog.hands = 2'd0;
dog.eyes = 2'd2; dog.noses = 1'd1;
$display("******@%0tns dog unpacked value ******", $time);
$display("******@%0tns dog height : %0d ****", $time, dog.height);
$display("******@%0tns dog weight : %0d ****", $time, dog.weight);
$display("******@%0tns dog legs : %0d ****", $time, dog.legs);
$display("******@%0tns dog hands : %0d ****", $time, dog.hands);
$display("******@%0tns dog eyes : %0d ****", $time, dog.eyes);
$display("******@%0tns dog noses : %0d ****", $time, dog.noses);
end
function void animal_assign (input [76:0] data_in, output animal animal_obj);
animal_obj.height = data_in[76 -: 32];
animal_obj.weight = data_in[76-32 -: 32];
animal_obj.legs = data_in[76-32-32 -: 8];
animal_obj.hands = data_in[76-32-32-8 -: 2];
animal_obj.eyes = data_in[76-32-32-8-2 -: 2];
animal_obj.noses = data_in[0];
endfunction
function void animal_display (input string name, input animal animal_obj);
$display("******@%0tns %s unpacked value animal_assign&animal_display******", $time, name);
$display("******@%0tns %s height : %0d ****",$time, name, animal_obj.height);
$display("******@%0tns %s weight : %0d ****",$time, name, animal_obj.weight);
$display("******@%0tns %s legs : %0d ****",$time, name, animal_obj.legs);
$display("******@%0tns %s hands : %0d ****",$time, name, animal_obj.hands);
$display("******@%0tns %s eyes : %0d ****",$time, name, animal_obj.eyes);
$display("******@%0tns %s noses : %0d ****",$time, name, animal_obj.noses);
endfunction
initial begin
data_in = {
32'd132, 32'd200, 8'd2, 2'd2, 2'd2, 1'd1};
animal_assign(data_in, duck);
name="duck";
animal_display(name, duck);
data_in = {
32'd132, 32'd100, 8'd2, 2'd0, 2'd2, 1'd1};
animal_assign(data_in, dog);
name="dog";
animal_display(name, dog);
end
endmodule
rslt.log
******@0ns duck unpacked value ******
******@0ns duck height : 132 ****
******@0ns duck weight : 200 ****
******@0ns duck legs : 2 ****
******@0ns duck hands : 2 ****
******@0ns duck eyes : 2 ****
******@0ns duck noses : 1 ****
******@0ns dog unpacked value ******
******@0ns dog height : 232 ****
******@0ns dog weight : 100 ****
******@0ns dog legs : 4 ****
******@0ns dog hands : 0 ****
******@0ns dog eyes : 2 ****
******@0ns dog noses : 1 ****
******@0ns duck unpacked value animal_assign&animal_display******
******@0ns duck height : 132 ****
******@0ns duck weight : 200 ****
******@0ns duck legs : 2 ****
******@0ns duck hands : 2 ****
******@0ns duck eyes : 2 ****
******@0ns duck noses : 1 ****
******@0ns dog unpacked value animal_assign&animal_display******
******@0ns dog height : 132 ****
******@0ns dog weight : 100 ****
******@0ns dog legs : 2 ****
******@0ns dog hands : 0 ****
******@0ns dog eyes : 2 ****
******@0ns dog noses : 1 ****
7.4.2、ref
参数demo
sv_function_task.sv
module sv_function_task();
typedef struct {
int height;
int weight;
logic [7:0] legs;
logic [1:0] hands;
logic [1:0] eyes;
logic noses;
}animal;
animal duck;
animal dog;
animal d;
logic [76:0] data_in;
string name;
/*initial begin
duck.height = 32'd132; duck.weight = 32'd200;
duck.legs = 8'd2; duck.hands = 2'd2;
duck.eyes = 2'd2; duck.noses = 1'd1;
$display("******@%0tns duck unpacked value ******", $time);
$display("******@%0tns duck height : %0d ****", $time, duck.height);
$display("******@%0tns duck weight : %0d ****", $time, duck.weight);
$display("******@%0tns duck legs : %0d ****", $time, duck.legs);
$display("******@%0tns duck hands : %0d ****", $time, duck.hands);
$display("******@%0tns duck eyes : %0d ****", $time, duck.eyes);
$display("******@%0tns duck noses : %0d ****", $time, duck.noses);
dog.height = 32'd232; dog.weight = 32'd100;
dog.legs = 8'd4; dog.hands = 2'd0;
dog.eyes = 2'd2; dog.noses = 1'd1;
$display("******@%0tns dog unpacked value ******", $time);
$display("******@%0tns dog height : %0d ****", $time, dog.height);
$display("******@%0tns dog weight : %0d ****", $time, dog.weight);
$display("******@%0tns dog legs : %0d ****", $time, dog.legs);
$display("******@%0tns dog hands : %0d ****", $time, dog.hands);
$display("******@%0tns dog eyes : %0d ****", $time, dog.eyes);
$display("******@%0tns dog noses : %0d ****", $time, dog.noses);
end
function void animal_assign (input [76:0] data_in, output animal animal_obj);
animal_obj.height = data_in[76 -: 32];
animal_obj.weight = data_in[76-32 -: 32];
animal_obj.legs = data_in[76-32-32 -: 8];
animal_obj.hands = data_in[76-32-32-8 -: 2];
animal_obj.eyes = data_in[76-32-32-8-2 -: 2];
animal_obj.noses = data_in[0];
endfunction
function void animal_display (input string name, input animal animal_obj);
$display("******@%0tns %s unpacked value animal_assign&animal_display******", $time, name);
$display("******@%0tns %s height : %0d ****",$time, name, animal_obj.height);
$display("******@%0tns %s weight : %0d ****",$time, name, animal_obj.weight);
$display("******@%0tns %s legs : %0d ****",$time, name, animal_obj.legs);
$display("******@%0tns %s hands : %0d ****",$time, name, animal_obj.hands);
$display("******@%0tns %s eyes : %0d ****",$time, name, animal_obj.eyes);
$display("******@%0tns %s noses : %0d ****",$time, name, animal_obj.noses);
endfunction
initial begin
data_in = {
32'd132, 32'd200, 8'd2, 2'd2, 2'd2, 1'd1};
animal_assign(data_in, duck);
name="duck";
animal_display(name, duck);
data_in = {
32'd132, 32'd100, 8'd2, 2'd0, 2'd2, 1'd1};
animal_assign(data_in, dog);
name="dog";
animal_display(name, dog);
end*/
task automatic animal_assign(ref [76:0] data_in, ref animal animal_obj);
animal_obj.height = data_in[76 -: 32];
animal_obj.weight = data_in[76-32 -: 32];
animal_obj.legs = data_in[76-32-32 -: 8];
animal_obj.hands = data_in[76-32-32-8 -: 2];
animal_obj.eyes = data_in[76-32-32-8-2 -: 2];
animal_obj.noses = data_in[0];
endtask
task automatic animal_display(ref string name, ref animal animal_obj);
$display("******@%0tns %s unpacked value automatic animal_assign&animal_display******", $time, name);
$display("******@%0tns %s height : %0d ****",$time, name, animal_obj.height);
$display("******@%0tns %s weight : %0d ****",$time, name, animal_obj.weight);
$display("******@%0tns %s legs : %0d ****",$time, name, animal_obj.legs);
$display("******@%0tns %s hands : %0d ****",$time, name, animal_obj.hands);
$display("******@%0tns %s eyes : %0d ****",$time, name, animal_obj.eyes);
$display("******@%0tns %s noses : %0d ****",$time, name, animal_obj.noses);
endtask
task automatic animal_assign_modified(ref [76:0] data_in, ref animal animal_obj);
animal_obj.height = data_in[76 -: 32];
animal_obj.weight = data_in[76-32 -: 32];
animal_obj.legs = data_in[76-32-32 -: 8];
animal_obj.hands = data_in[76-32-32-8 -: 2];
animal_obj.eyes = data_in[76-32-32-8-2 -: 2];
animal_obj.noses = data_in[0];
data_in = '0; endtask initial begin data_in = {32'd132, 32'd200, 8'd2, 2'd2, 2'd2, 1'd1}; animal_assign(data_in, duck); name = "duck"; animal_display(name, duck) data_in = {32'd132, 32'd100, 8'd2, 2'd0, 2'd2, 1'd1};
animal_assign(data_in, dog);
name = "dog";
animal_display(name, dog);
animal_assign_modified(data_in, dog);
animal_display(name, dog);
$display("******After data_in modified by dog structure");
animal_assign(data_in, duck);
name = "duck";
animal_display(name, duck);
end
endmodule
rslt.log
******@0ns duck unpacked value automatic animal_assign&animal_display******
******@0ns duck height : 132 ****
******@0ns duck weight : 200 ****
******@0ns duck legs : 2 ****
******@0ns duck hands : 2 ****
******@0ns duck eyes : 2 ****
******@0ns duck noses : 1 ****
******@0ns dog unpacked value automatic animal_assign&animal_display******
******@0ns dog height : 132 ****
******@0ns dog weight : 100 ****
******@0ns dog legs : 2 ****
******@0ns dog hands : 0 ****
******@0ns dog eyes : 2 ****
******@0ns dog noses : 1 ****
******@0ns dog unpacked value automatic animal_assign&animal_display******
******@0ns dog height : 132 ****
******@0ns dog weight : 100 ****
******@0ns dog legs : 2 ****
******@0ns dog hands : 0 ****
******@0ns dog eyes : 2 ****
******@0ns dog noses : 1 ****
******After data_in modified by dog structure
******@0ns duck unpacked value automatic animal_assign&animal_display******
******@0ns duck height : 0 ****
******@0ns duck weight : 0 ****
******@0ns duck legs : 0 ****
******@0ns duck hands : 0 ****
******@0ns duck eyes : 0 ****
******@0ns duck noses : 0 ****
- 可以看到更改
ref
引用的变量,那么再调用该变量,该变量就是更改后的值了。 ref
容易犯错误,实际使用并不推荐。
参考
边栏推荐
- numpy中dot函数使用与解析
- Open source ecosystem | create a vibrant open source community and jointly build a new open source ecosystem!
- Cnopendata American Golden Globe Award winning data
- Iterable、Collection、List 的常见方法签名以及含义
- padavan手动安装php
- MySQL multi column index (composite index) features and usage scenarios
- Figure out the working principle of gpt3
- 芯片 设计资料下载
- C语言队列
- 【p2p】本地抓包
猜你喜欢
即刻报名|飞桨黑客马拉松第三期等你挑战
Linux server development, redis source code storage principle and data model
Detailed explanation of uboot image generation process of Hisilicon chip (hi3516dv300)
[mathematical notes] radian
探索干货篇!Apifox 建设思路
Problem solving: unable to connect to redis
Use and analysis of dot function in numpy
[webrtc] m98 Screen and Window Collection
Most elements
Linux server development, MySQL index principle and optimization
随机推荐
[OBS] win capture requires winrt
padavan手动安装php
mysql多列索引(组合索引)特点和使用场景
Open source ecosystem | create a vibrant open source community and jointly build a new open source ecosystem!
Téléchargement des données de conception des puces
The configuration that needs to be modified when switching between high and low versions of MySQL 5-8 (take aicode as an example here)
Use and analysis of dot function in numpy
[UTCTF2020]file header
[advanced digital IC Verification] command query method and common command interpretation of VCs tool
You Li takes you to talk about C language 6 (common keywords)
即刻报名|飞桨黑客马拉松第三期等你挑战
Visualization Document Feb 12 16:42
What are the positions of communication equipment manufacturers?
Mysql高低版本切换需要修改的配置5-8(此处以aicode为例)
自定义类加载器加载网络Class
【斯坦福计网CS144项目】Lab3: TCPSender
芯片 设计资料下载
Pytest+allure+jenkins environment -- completion of pit filling
2022 tea master (intermediate) examination questions and mock examination
【Unity】物体做圆周运动的几个思路