当前位置:网站首页>【數字IC驗證快速入門】15、SystemVerilog學習之基本語法2(操作符、類型轉換、循環、Task/Function...內含實踐練習)
【數字IC驗證快速入門】15、SystemVerilog學習之基本語法2(操作符、類型轉換、循環、Task/Function...內含實踐練習)
2022-07-07 07:59: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
容易犯錯誤,實際使用並不推薦。
參考
边栏推荐
- Problem solving: unable to connect to redis
- 这5个摸鱼神器太火了!程序员:知道了快删!
- 2022 National latest fire-fighting facility operator (primary fire-fighting facility operator) simulation questions and answers
- Qt学习27 应用程序中的主窗口
- Rust versus go (which is my preferred language?)
- Chip information website Yite Chuangxin
- Rust Versus Go(哪种是我的首选语言?)
- 有 Docker 谁还在自己本地安装 Mysql ?
- Force buckle 145 Binary Tree Postorder Traversal
- Use and analysis of dot function in numpy
猜你喜欢
随机推荐
通信设备商,到底有哪些岗位?
解决问题:Unable to connect to Redis
【经验分享】如何为visio扩展云服务图标
Custom class loader loads network class
Most elements
Ansible
Linux server development, detailed explanation of redis related commands and their principles
[experience sharing] how to expand the cloud service icon for Visio
Force buckle 145 Binary Tree Postorder Traversal
Operation suggestions for today's spot Silver
[UVM practice] Chapter 1: configuring the UVM environment (taking VCs as an example), run through the examples in the book
[UTCTF2020]file header
Sign up now | oar hacker marathon phase III, waiting for your challenge
【VHDL 并行语句执行】
微信小程序基本组件使用介绍
C语言通信行程卡后台系统
misc ez_usb
Pytest+allure+jenkins installation problem: pytest: error: unrecognized arguments: --alluredir
C language queue
leetcode:105. Constructing binary trees from preorder and inorder traversal sequences