1. 程式人生 > >System Verilog基礎(二)

System Verilog基礎(二)

參考 com 不能 ask 信號 eve art verilog nic

這一篇筆記主要記錄Procedural,Process,Task and function,Interface和Communication中值得註意的點。

1.Procedural

寫testbench的時候,除了tb與硬件交互的地方使用非阻塞賦值,tb裏面其他地方一律用阻塞賦值,OK

1 logic [3:0]        d0,d1;
2 initial    begin
3     d0 <= 3;
4     $display("d0 value %0d",d0);    //d0=x;logic在未被初始化的時候是x
5     d1 = 4;
6     $display("
d1 value %0d d0 value %0d",d1); //d1=4,d0=x;註意這個時候d0依然是x 7 #1 8 $display("d1 value %0d d0 value %0d",d1); //d1=4,d0=3;只有#1往前走了之後,<=才會賦值生效 9 end

Loop循環中的foreach,是專門針對數組輪詢時候用的。對二維數組遍歷,如下代碼:

1 int data[3][4];
2 initial
3     foreach(data[1]) begin
4         foreach(data[i][j]) begin
5             </**/
> 6 end 7 </**/> 8 end 9 end

在兩個for循環中,可以在裏面直接定義index,例如for(int i; i<10; i++) 這樣,如果有兩個for裏面都定義了int i,這兩個index i是相互不影響的。

哪些地方可以加label? Module...endmodule; begin...end; task...endtask; fork...join; interface...endinterface; 加標簽的主要好處是增加代碼的可讀性,例如下面的代碼:

 1 module test();
2 begin: b0 3 <...> 4 begin: b1 5 <...> 6 end: b1 7 end: b0 8 9 begin: b2 10 <...> 11 end: b2 12 endmodule:test

Final Blocks。這個塊在Verilog中沒有,當遇到$finish的時候,會進入到final塊中。一般用在打印一些信息,註意final塊中是不能加延遲#操作的,不然會報錯。

2.Process

initial塊和always塊都會產生進程Process。在SV中,可以使用fork來動態地產生子進程。fork有三種形式:fork...join fork...join_any fork...join_none 。使用fork...join_none時,不等待子進程執行,直接先執行主進程,就是fork...join_none外面的代碼,但是fork...join_none裏面的代碼在後臺也在執行,註意執行的先後順序。如下代碼:

 1 fork: fork 1
 2     begin
 3         #1;
 4     end
 5     begin
 6         #2 7     end
 8 join
 9 $dispaly($time);    // time is 2ns
10 fork: fork 2
11     begin
12         #1;
13     end
14     begin
15         #216     end
17 join_any
18 $dispaly($time);    // time is 1ns
19 fork: fork 3
20     begin
21         #1;
22     end
23     begin
24         #225     end
26 join_none
27 $dispaly($time);    // time is 0ns

使用wait fork來等待所有的進程執行完,如下代碼,只有exec1(), exec2(), exec3(), exec4()都執行完了,task才會結束。

 1 task mytask;
 2     fork: fork1
 3         exec1();
 4         exec2();
 5     join_any
 6     fork: fork2
 7         exec3();
 8         exec4();
 9     join_none
10     
11     wait fork;
12 endtask

使用disable fork,可以停止後臺掛起的進程。在fork...join_any中disable fork使用的較多,用來檢測程序,當fork...join_any中的任何一個監測進程執行OK後,就會使用disable fork來殺死fork中剩余的其他監測進程。

為了對Process更精細控制,SV中內建有Class,在UVM中使用到。(遇到再更新吧~.~)

3. task and function

1 task mytask(a, int b, output logic [15:0]u, v)
2 // a沒有定方向和類型,默認input logic;
3 // b默認是input方向
4 // v的方向和類型會繼承前一個參數,所以v也是output logic [15:0]
5     <...>
6 endtask

task和function也可以加標簽,如下代碼:

1 task mytask(a = 3, int b, output logic [15:0]u, v);
2 // a的默認值是3,如果傳參沒有傳,就會使用默認值
3      <...>
4 endtask: mytask
5 function my_func (a, int b, output logic [15:0]u, v);
6     <...>
7 endfunction: my_func

C語言有數值傳參和指針傳參,SV也有,在定義task的時候使用ref關鍵字去修飾形參,還可以加const,參考C語言的用法。

task中可以有時間消耗,function中不能有時間消耗。task可以調用function,反過來不可以。

4. Interface

使用interface...endinterface來定義,用來解決模塊之間的連接,模塊和硬件件的連接問題。可以像理解module一樣去理解interface,如下代碼:

 1 // 定義一個interface類型
 2 interface bus_A (input clk);        //定義interface時可以像module一樣有端口
 3     logic         req;
 4     logic [7:0]    addr,data;
 5     logic        start,rdy;
 6 endinterface
 7 // 使用這個interface,在module中例化
 8 module tb_top;
 9     logic clk = 0;
10     bus_A sb_intf(clk);        //例化
11     memMode u_inst_mem1(clk,sb_intf); //把memMode模塊,通過名字相同的線與sb_intf連接起來
12 endmodule

在定義interface的裏面,使用modport來對一些信號接口做子集分類,這樣在外層module中,例化一個模塊,模塊可以只連接interface其中的一個子集。

interface可以像module一樣,用#(AWIDTH=8,BWIDTH=9)來定義參數,在傳遞的過程中來改變值。

interface裏面還可以使用clock塊,在實際項目中遇到了再總結吧(~.~)!

在calss中使用interface,必須使用關鍵字virtual interface

5. 同步和通信

同步和通信有三種:Semaphone, Event, Mailbox。最後一個是用來傳遞數據的。

5.1 Semaphones

  解決進程資源間共享問題,提供四個函數:new, put, get, try_get。其中get相當於一個task,裏面有延遲,會阻塞其他的get拿到鑰匙,try_get相當於一個function,立即執行,不會產生阻塞。下面代碼示例:

 1 semaphone sem0 = new(1);    //鑰匙數量為1
 2 initial begin:process 0
 3     #10ns
 4     void(sem0.try_get())    //不會阻塞,拿不到鑰匙直接執行下面的語句;拿到鑰匙返回值為1
 5     sem0.get();                //不會拿到鑰匙,會一直阻塞在這裏,直到下面的進程100ns之後把鑰匙還了
 6     sem0.put();                //還鑰匙
 7 end:process 1
 8 
 9 initial begin:process 1
10     sem0.get();
11     #100ns
12     sem0.put();        //還鑰匙,key number 為1
13 end:process 1

5.2 Event

用來觸發事件,使用->;用來等待事件使用@或者wait。那麽@和wait有什麽區別呢?看下面的代碼:

 1 event a;    //使用關鍵字event來聲明一個事件a
 2 initial begin
 3     #1;
 4     ->a;
 5 end
 6 initial    begin
 7     #1;
 8     @a;        //第一個進程在1ns後觸發了事件a,那麽第二個進程在1ns的時候等待a,有可能等的到,有可能等不到,產生競爭
 9 end
10 initial begin
11     #1;
12     wait(a.triggered); //使用wait來等待事件a,這種方式是一定可以等到a的,這是和使用@來等待的區別
13 end

wait像是增強版的@,用來解決同一時刻的競爭冒險問題。

5.3 Mailbox

可以理解為能存儲任意數據類型的隊列。先挖坑,以後遇到了再做筆記(~.~)!

System Verilog基礎(二)