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增加點
- 不需要加begin…end
- 添加return,直接退出函數
- function增加了void function
- 在verilog裏function只有input,沒有output,返回值就是函數值;但在sv裏,function增加了output,inout變量
- 參數方向類型缺省時,類型默認爲logic,方向默認爲input
- 引用ref。所謂引用傳遞,就如c++裏面的指針,也就是變量的入口地址;只有automatic型task,function可以使用ref;傳值方式來傳遞參數,那麼參數會被整體複製到其他地址,這樣消耗一定的內存和操作時間;而用ref傳值方式來傳遞參數,只是獲得參數的入口地址,操作速度快,減少內存使用
automatic
一般硬件裏的所有對象都是靜態的;在verilog-1995,如果在多個地方調用同一個任務,本地變量是共同而且靜態分配的,爲此,不同的進程相互訪問同一個值。在verilog-2001中,可以通過使用automatic關鍵字,將任務,函數和模塊聲明爲自動存儲模式,這樣,仿真器就能夠對所有形式的參數和內部變量使用堆棧的形式來存儲。