System Verilog我的學習之路(一)

Data types

System Verilog引進了幾種新的數據類型。C語言程序員會熟悉其中的大多數。引進新的數據類型構思是這樣的,如果C語言和System Verilog有相同的數據類型可以使C語言算法模型更容易的轉化爲System Verilog模型。
Verilog的變量類型有四態:既是0,1,X,Z。SystemVerilog引進了新的兩態數據類型,每一位只可以是0或是1。當你不需要使用的X和Z值時,譬如在寫Testbench和做爲for語句的循環變量。使用兩態變量的RTL級模型,可以使模擬器更有效率。並且使用得當的話將不會對綜合結果產生影響。

常量

在變量前面加const,如果用戶把這個變量改變了,那麼仿真器會報錯。按照C語言中的const來理解。

整型常量

8‘b0  32’d0  '0  '1  'x  'z

省略位寬則意味着全位寬都被賦值。

實型常量

支持小數或者科學型表示,例如:3.14  2.0e3
real a = 3.14;

字符串常量

和c++類似,但是字符串末尾不是“\n”
string s=“123”
bit [7:0] d = “sv”; //也可以賦值給整型

數組常量

和c++類似
int array[1:2] = {5,6};

結構體常量

typedef struct{
     int     a;
     string b;
     real    c;      
}  name_1;

name_1 var;

var = {10, "sv", 1.24};

時間文本值

和verilog類似

`timescale 1ns/100ps    //時間單位是1ns,時間精度是100ps
module test;
initial begin
    #20;        //相當於20ns
    #20ns;
    #5.18ns;  //相當於5.2ns,因爲時間精度是100ps,即0.1ns,自動進位了
    #1step;   //相當於100ps
end
endmodule

`timescale必須定義在模塊的外面,使用關鍵字timeunit和timeprecision只能定義在模塊內部,只會影響單個模塊。

整型

類型 描述 符號
bit 2態,自定義位寬 無符號
byte 2態,8bit 有符號
int 2態,32bit 有符號
shortint 2態,16bit 有符號
longint 2態,32bit 有符號
logic 4態,自定義位寬 有符號
reg 4態,自定義位寬 有符號
integer 4態,32bit 有符號
time 4態,64bit 無符號

2態只有1和0;4態是0,1,Z,X。2態數據類型不初始化,則默認是0;4態數據類型不初始化,則默認是X。不要用2態的數據類型去做ADC數據採集。在對4態數據類型做比較的時候,使用三個等號(a===b)。2態和4態數據類型是可以相互轉化的。從4態轉化倒2態,那麼4態中的Z和X會默認爲2態的0。注意time類型是整數類型,64bit位寬。

logic類型

在SV中增加了logic類型,是reg類型的增強。在verilog中,一般輸入會定義成wire類型,但是在SV中,輸出和輸入都定義成logic就行。 在verilog中,reg類型只能在always塊中被賦值,不能用assign來賦值,但是logic類型可以在always塊中和assign中被賦值。

module(
    output    reg    a,
    input      wire   b
);
endmodule

SV:
module(
    output    logic    a,
    input      logic    b
);
endmodule

實數

類型 描述 符號
real 2態,64bit 有符號
shotreal 2態,32bit 有符號

分爲real data和shortreal data。real data相當於C語言中的double類型,64bit位寬,2態;shortreal data相當於C語言中的float類型,32bit位寬,2態。

字符串

初始值是空字符。字符串的比較按照ASIC碼來比較。使用[]來索引,隨意改變和取值。SystemVerilog字符串類型支持很多操作和函數。

操作 描述
{strA,strB} 連接——擴展指定的字符串。操作符可以是字符串類型,也可以是字符串文字。當所有的操作符都是字符串文字時,此操作完成整體的連接,結果也是一個字符串文字。
str.len 長度——返回代表字符串的長度的整數
str.putc(i, c) 字符輸入——將字符串str中的第i個字符替換成字符c。i必須是一個整數,c必須是一個字節類型的字符
str.getc(i) 獲取字符——返回字符串str的第i個字符。i必須是整數,返回的字符表示爲一個字節。
str.toupper() 轉成大寫——返回str中所有字符變成大寫的字符串
str.tolower() 轉成小寫——返回str中所有字符變成小寫的字符串
strA.compare(strB) 比較——比較strA和strB.從第一個字符開始比較。如果相等,則繼續後續字符,知道兩者有不同或者到達某個字符串的結尾。如果相等,返回’0‘;如果strA在strB之後,則返回整數;如果strA在strB之前,則返回負數.
strA.icompare(strB) 比較——和compare方法類似,但是不關心大小寫。
str.substr(i, j) 子串——i和j都是整數,返回一個新的字符串,由str的第i和和第j箇中間的所有字符組成
str.atoi() 字符串轉整數——返回一個32bit整數(不考慮此字符串表示的數字的長度),對於atoi, 字符串將被看作十進制;對於atoh,十六進制;對於atooct,八進制;對於atob,二進制。對於比較大的數字,使用系統任務$sscanf更加合適.
str.atoreal() 字符串轉實數——此方法返回字符串str表示的實數
str.itoa(i) 整數轉字符串——atoi,atohex,atooct,atobin的反運算。此係列方法輸入一個整數i,將其對應的表示方式存在字符串str中。
str.realtoa® 實數轉字符串——atoreal的反運算。此方法輸入一個實數r,將其對應的表示方式存在字符串str中。

空類型

SV中定義function也是可以有返回值的,如果不想有返回值,那麼在定義function後面添加void。調用有返回值的函數,但是不想用返回值,這個時候在調用函數的前面加void’(fun1());就可以了。不然會有warning,在驗證中最好不要有警告。

動態數組

在run-time才知道元素個數,在compile-time不知道,可以使用動態數組,在仿真的時候再確定元素個數。也可將固定數組賦值給動態數組,要求是元素個數相同。
data_type name_of_dynamic_array[];
name_of_ dynamic_array = new[number of elements];

實例:int dyn[]; dyn = new[5];dyn.delete();

隊列

和C++的類似,可插入,刪除,sort,search,push,pop等
  data_type queue_name[$] = {…} //隊列賦值時大括號前面不加單引號

實例:
int b[$] = {3,4}; //{3,4}
b.insert(1,1); //{3,1,4} 在第一個元素後面添加1
b.delete(1); //{3,4} 刪除元素1
b.push_front(6) ; //{6,3,4}
j = b.pop.back; //{6,3}, j = 4

聯合數組

充分利用內存裏的離散空間,不連續空間;索引值可以爲整型,字符型,一維數組。有如下的操作,遍歷(foreach),first,next,prev,delete,exits
data_type associative_array_name[*/string]
實例:
logic [63:0] assoc [*],idx=1;
repeat(64) begin
assoc[idx]=dix;
idx=idx<<1;
end
說明:標準數組存儲時,所有的存儲器都用到了;聯合數組使用內存時,稀疏。

數組的操作

   /*    
      Exercsise platform :     Questa Sim 10.1b
    */
    class Array;
      int array[9:0] ;
      
      function new();
         for( int i = 0 ; i < 10 ; i++ )
             array[i] = i ;
          /*
              array = '{'{1,2,3},'{5{5}},default:0};
              無法使用這種基本的賦值方式,可能是編譯器的版本過低了
          */
      endfunction:new
      
       function void print();
        foreach(array[i]) begin
          $display(" array[%d] = %d ",i,array[i]);
        end
        for ( int i = 0 ; i < 10 ; i++ )begin
          $write(" ** ");
        end
        $display();
      endfunction:print
      
      function void funcs();
          int pos[$] ;
        //   縮減操作 xor , or , and ,  xnor  , sum , product 等
        $display("the sum is %d ",array.sum());
        $display("the and is %d ",array.and());
        $display("the  or is %d ",array.or() );
        $display("the xor is %d ",array.xor());
        $display("the product is %d ",array.product());
        
        //   索引操作:取得相應的所需要的數組原素位置
        $display(" max value is %d ",array.max()[0]);
        $display(" min value is %d ",array.min()[0]);
        array = array.unique();
        print();       //  在類中時,調用自己類的函數,可以直接調用。這點與cpp相同
        pos = array.find with ( item == 7 ) ; 
        //  find 有多種變體: find_first   find_last  find_first_index   find_last_index
        $display(" pos : %d ? value: %d ",pos[0],array[pos[0]]);
        
        //  排序操作: sort ,  rsort  , reverse , shuffle , 
        // 其中 sort ,rsort  可以與with相結合,根據with後的條件排序
        array.shuffle();
        $display("shuffled:");
        print();
        array.sort();
        $display("Sorted:");
        print();
        array.rsort();
        $display("Resorted:");
        print();
        array.reverse();
        $display("Reversed:");
        print();  
      endfunction:funcs
    endclass:Array
    module top;
      Array array;
      int arr[] ;     //   動態數組的聲明
      
      initial begin
        //  initial process
        array=new();
        array.print();
        array.funcs();
        arr = new[20];   //   分配內存大小
        foreach(arr[i]) $display(" arr[%2d] = %d ",i,arr[i]); 
        $display("***************");
        arr.delete();
      end
    endmodule
    //   所有關於定長數組的操作都可以用在動態數組上

仿真結果:

# ** Note: (vsim-3812) Design is being optimized...
# 
# Loading sv_std.std
# Loading work.array_sv_unit(fast)
# Loading work.top(fast)
>>>run
#  array[          9] =           9 
#  array[          8] =           8 
#  array[          7] =           7 
#  array[          6] =           6 
#  array[          5] =           5 
#  array[          4] =           4 
#  array[          3] =           3 
#  array[          2] =           2 
#  array[          1] =           1 
#  array[          0] =           0 
#  **  **  **  **  **  **  **  **  **  **  
# the sum is          45 
# the and is           0 
# the  or is          15 
# the xor is           1 
# the product is           0 
#  max value is           9 
#  min value is           0 
#  array[          9] =           0 
#  array[          8] =           1 
#  array[          7] =           2 
#  array[          6] =           3 
#  array[          5] =           4 
#  array[          4] =           5 
#  array[          3] =           6 
#  array[          2] =           7 
#  array[          1] =           8 
#  array[          0] =           9 
#  **  **  **  **  **  **  **  **  **  **  
#  pos :           7 ? value:           2 
# shuffled:
#  array[          9] =           2 
#  array[          8] =           8 
#  array[          7] =           0 
#  array[          6] =           4 
#  array[          5] =           7 
#  array[          4] =           1 
#  array[          3] =           9 
#  array[          2] =           5 
#  array[          1] =           6 
#  array[          0] =           3 
#  **  **  **  **  **  **  **  **  **  **  
# Sorted:
#  array[          9] =           0 
#  array[          8] =           1 
#  array[          7] =           2 
#  array[          6] =           3 
#  array[          5] =           4 
#  array[          4] =           5 
#  array[          3] =           6 
#  array[          2] =           7 
#  array[          1] =           8 
#  array[          0] =           9 
#  **  **  **  **  **  **  **  **  **  **  
# Resorted:
#  array[          9] =           9 
#  array[          8] =           8 
#  array[          7] =           7 
#  array[          6] =           6 
#  array[          5] =           5 
#  array[          4] =           4 
#  array[          3] =           3 
#  array[          2] =           2 
#  array[          1] =           1 
#  array[          0] =           0 
#  **  **  **  **  **  **  **  **  **  **  
# Reversed:
#  array[          9] =           0 
#  array[          8] =           1 
#  array[          7] =           2 
#  array[          6] =           3 
#  array[          5] =           4 
#  array[          4] =           5 
#  array[          3] =           6 
#  array[          2] =           7 
#  array[          1] =           8 
#  array[          0] =           9 
#  **  **  **  **  **  **  **  **  **  **  
#  arr[ 0] =           0 
#  arr[ 1] =           0 
#  arr[ 2] =           0 
#  arr[ 3] =           0 
#  arr[ 4] =           0 
#  arr[ 5] =           0 
#  arr[ 6] =           0 
#  arr[ 7] =           0 
#  arr[ 8] =           0 
#  arr[ 9] =           0 
#  arr[10] =           0 
#  arr[11] =           0 
#  arr[12] =           0 
#  arr[13] =           0 
#  arr[14] =           0 
#  arr[15] =           0 
#  arr[16] =           0 
#  arr[17] =           0 
#  arr[18] =           0 
#  arr[19] =           0 
# ***************

語法

procedural statement

新操作符

  • i++,++i,i–,--i 同c語言,但易出現race現象。
  • ==?,!=? 如:a==?b ,x與z只能出現在右側,即b的值有x或者z
  • inside 用於值的範圍,類似python的 in

強制轉換

1、數據類型強制轉換
通過賦值的方式,例如
longint a,y;
real r;
y=a+longint(r);

2、位寬強制轉換

logic [15:0] a,b,c,sum;
logic carry
sum=a+16'(5)
{carry,sum}=17'(a+3)
sum=a+16'(b-2)/c;

3、符號位強制轉換
將無符號數轉化爲有符號數,將有符號數轉化爲無符號數
例子:signed’(expression) unsigned’(expression)

循環

1、 for循環
verilog中,循環體內的變量需要在循環體外聲明。sv裏和c++一樣,可在循環體內聲明變量,這種變量是local的,在循環體外看不見。若在循環體內外同時聲明同一變量,則互不干擾。
2、do while sv裏增加的循環,verilog裏沒有。
3、增加unique,priority(優先級)選項;

function

不消耗時間;不帶時序,function裏不能包含延時信息,@,wait等時間信息關鍵字;由於task可以帶時序,所以規定function不能調用task;
void function中,不返回值;在verilog裏,function一定返回值,且返回的值是function的名字。

task

消耗時間,含有輸入輸出雙向端口;可含delay,timing,event;

sv裏task與function增加點

  1. 不需要加begin…end
  2. 添加return,直接退出函數
  3. function增加了void function
  4. 在verilog裏function只有input,沒有output,返回值就是函數值;但在sv裏,function增加了output,inout變量
  5. 參數方向類型缺省時,類型默認爲logic,方向默認爲input
  6. 引用ref。所謂引用傳遞,就如c++裏面的指針,也就是變量的入口地址;只有automatic型task,function可以使用ref;傳值方式來傳遞參數,那麼參數會被整體複製到其他地址,這樣消耗一定的內存和操作時間;而用ref傳值方式來傳遞參數,只是獲得參數的入口地址,操作速度快,減少內存使用

automatic

一般硬件裏的所有對象都是靜態的;在verilog-1995,如果在多個地方調用同一個任務,本地變量是共同而且靜態分配的,爲此,不同的進程相互訪問同一個值。在verilog-2001中,可以通過使用automatic關鍵字,將任務,函數和模塊聲明爲自動存儲模式,這樣,仿真器就能夠對所有形式的參數和內部變量使用堆棧的形式來存儲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章