天天看點

SV過程語句1.邏輯比較操作符2.inside包含3.變量類型轉換Type Casting4.for循環5.while循環6.do…while循環7.case語句(case,casex,casez)8.function和task

1.邏輯比較操作符

  • 等于==,不等于 !=
邏輯1為真,邏輯0為假,如果比較值中存在x或z,則邏輯值為1’bx
  • 全等===,不全等!==
完全比對四種狀态值:0,1,x,z
  • 通配符邏輯比較
比對等==?和不比對等!=?,按位比較,把x和z值當作比對值,僅僅把右側操作數中的z和x當作屏蔽信号
a=4'b1111;
b=4'b11xz
a==?b//數字相等,隻要x和z能通配到1就可以是比對等,傳回邏輯值為1'b1,真
           

2.inside包含

  • inside可以比對一組資料範圍内的任何一個數值,下述代碼等價
//代碼1
logic [2:0] a;
if((a==3'b001)||(a==3'b010)||(a==3'b100))
//代碼2
logic [2:0] a;
if(a inside{3'b001,3'b010,3'b100})
           

3.變量類型轉換Type Casting

  • 變量類型轉換符可以在任何時刻對表達式進行類型轉換,$cast可以強制進行類型轉換(枚舉類型)
module cast();
typedef enum {IDLE, SFD, PREAMBLE,DATA, FCS, EFD} eth_state;//0,1,2,3,4,5
eth_state fsm;
initial begin
	#5 fsm = IDLE;
	$dispTay ("@%0dns Current value of FSM : %s\n",$time, get_name(fsm));//IDLE
	#5 fsm =SFD;
	$display ("@%0dns Current value of FSM : %s\n",$time, get_name(fsm));//	SFD
	#1 $cast (fsm, 1+2);
	$display ("@%0dns Current value of FSM : %s\n",$time, get_name (fsm));//DATA
// Below line should give compile error
// fsm=2 + 1;
end
           
  • SV還可以進行矢量位寬轉換。表達式轉換成較小位寬時,左側的比特位會被删除;表達式轉換成較大位寬時,左側的比特位會被擴充
size'(expression)//位寬轉換方式
//example
logic [15:0] a,b,c,sum;
logic array;
sum += a + 16'(5);//操作數位寬拓展,16bit的a加上16bit的5
{carry,sum} = 17'(a+3);//表達式結果位寬擴充,a+3擴充為17bit,多了一個進位
sum = a+16'(b-2)/c;//中間結果位寬擴充,b-2擴充到16bit
           
  • SV可以轉換符号位,可以完成操作數符号轉換和表達式結果符号位轉換
//z轉換方式
signed'(expression);
unsigned'(expression);
//example
sum = signed'(a)+signed'(b);
if(unsign'(a-b)<=5)
           

4.for循環

  • SV可以在for循環内部聲明循環變量,每個變量都為本地的唯一的變量,是以外部使用的相同名字的變量不會互相影響,本地循環變量是atuomatic,for循環内部聲明的本地變量在循環語句之外就不存在了,下述代碼中,兩個i就是不一樣的變量
int i;
always_ff @(posedge clk)begin
	for(int i=1;i<1024;i++)
		...
	end
           
  • continue隻能用于循環語句,結束本次循環,繼續下一次循環,即截至到contine語句上一句,再重新去開始下一次循環
  • break隻能用于循環語句,破壞循環,跳出循環,不再執行循環語句,即結束循環
  • return可以用于循環語句用來結束循環,也可以用于task和function用來結束task或function

5.while循環

  • 當表達式為真,則執行下面的語句;語句執行完之後再判斷表達式是否為真,如果為真,再次執行下面的語句;然後再判斷表達式是否為真……就這樣一直循環下去,直到表達式為假,跳出循環。
while (表達式)
{
        語句;
}
           

6.do…while循環

  • 至少執行一次循環語句,再循環語句的最後判斷循環變量
do<statement or statement block>
...
while(<condition>)
           

7.case語句(case,casex,casez)

  • SV在case語句中增加了unique和priority辨別符

(1). unique辨別符表示case語句中表達式相對應的數值的先後順序是沒有優先級的,case表達式對應的每個值必須是唯一的,unique辨別符要求case表達的值不能有重疊

(2).priority辨別符則必須有一個case表達式的值是有效的,如果case表達式對應多個值,按照代碼的先後順序,第一個比對的值有效

  • casez個人了解的意思就是表達式中可以存在z,casex就是表達式中可以存在x和z

8.function和task

  • 函數執行的時候不消耗仿真時間,是以延時不能放在function中,否則報錯,也不能有阻塞語句(@(posedge clk)或wait(ready)),不能調用task
  • task中含有input、output、inout語句,可以消耗仿真時間,可以調用function,event
  • task和function中不需要使用begin…end語句,增加了return語句,void function沒有傳回值,function可以有output(函數可輸出)和inout(既可輸入也可輸入)作為形式參數
  • return語句執行時傳回表達式的值,否則最後的傳回數值指派給函數名(return的優先級高于函數名),return語句用于退出task和function,下述代碼意義相同
//example1
function int add_and_inc(input [31:0] a,b);
	add_and_inc = a+b+1;
endfunction
//example2
function int add_and_inc(input [31:0] a,b);
	add_and_inc = a+b;
	return ++add_and_inc;
endfunction
           
  • void function 沒有傳回值,output和inout形式參數為void function提供了傳遞變量的途徑,可以像task一樣被調用,但必須和函數的内容限制保持一緻
  • 可以通過直接把函數名或任務名作為輸出,不用在其中定義,調用時也同樣适用
  • 每個形式參數都有一個預設的類型,調用task和function時,不必給具有預設參數值的參數傳遞數值
  • 使用reference替代複制的方式傳遞參數(值傳遞),使用引用(reference)的方式顯式的向task和function傳遞參數,使用ref關鍵字取代input,output,inout,且隻有automatic任務和函數才可以使用ref參數,其實ref就相當于c語言裡的指針,比如一個函數已經寫好了,要想不修改函數内部,通過外部修改函數裡的參數值,就可以定義成ref,相當于這個函數直接通路到了它在磁盤裡的存儲位置,然後進行更改,那麼也就會造成原來的數組的改變;
//
 function automatic int crc (ref bype packet[1000:1]);
    for (int i = 1; i <= 1000; i++)begin
         crc ^= packet[i];
    end
 endfunction
           
  • 當參數通過引用傳遞時,調用者和子程式共享參數的相同表示方式;是以,在調用者或子程式中對參數所做的任何更改都互相可見。 通過引用傳遞的變量指派的語義是在子程式之外立即看到對其的更改(在子程式傳回之前)。
  • 傳遞常量數組給function的格式如下:
'{數組索引:值, 數組索引: 值, 數組索引: 值};
array_test('{0:5,3:6,1:2,2:9});//array[0]=5,array[1]=2,array[2]=9,array[3]=6
           
  • 傳遞關聯數組給function,由于關聯數組類似于哈希數組,沒有順序,隻是一些鍵-值(key-value),下述代碼就隻傳遞了一個值:
module my_associative_array_test();
    function associative_array_test(int array[bit [1:0]]);
        foreach(array[i])begin
            $display("array[%0d] = %0d",i,array[i]);
        end
    endfunction

initial begin
    associative_array_test('{3:10});//array[3] = 10
end
endmodule
           
  • 傳遞數組的引用給function
module my_ref_array_test();
  int array[5] = '{0, 1, 2, 3, 4}; //數組賦初值
  function automatic ref_test(ref int array[5], input [7:0] start);
    foreach(array[i]) begin
      array[i] = i + start;
      $display("[NOW]array[%0d] = %0d", i, array[i]);
    end
  endfunction
  initial begin//列印初始數組,{0,1,2,3,4}
    foreach(array[i]) begin
      $display("[BFE]array[%0d] = %0d", i, array[i]);
    end
 
    ref_test(array, 5);//調用函數,start=5,{5,6,7,8,9}
 //列印目前數組,{5,6,7,8,9}
    foreach(array[i]) begin
      $display("[AFT]array[%0d] = %0d", i, array[i]);
    end
  end
endmodule
           
  • 傳遞數組的引用給function,但不允許子函數修改數組的值(要是想讓其隻讀的話就要使用const):
module my_ref_array_test();
  int array[5] = '{0, 1, 2, 3, 4};     //'
  function automatic const_ref_array_test(const ref int array[5], input start);
    foreach(array[i]) begin
      //array[i] = i + start; //不允許修改數組的值,取消注釋會有編譯錯誤
      $display("[NOW]array[%0d] = %0d", i, array[i]);
    end
  endfunction
  //{0,1,2,3,4}
  initial begin
    foreach(array[i]) begin
      $display("[BFE]array[%0d] = %0d", i, array[i]);
    end
 //{0,1,2,3,4}
    const_ref_array_test(array, 5);
 //{0,1,2,3,4}
    foreach(array[i]) begin
      $display("[AFT]array[%0d] = %0d", i, array[i]);
    end
  end
 
endmodule
           

繼續閱讀