數據類型
SV新特性:對比VERILOG
- 2值邏輯:提高性能,減少內存使用;
- 隊列,動態數組,關聯數組:減少內存使用,內建搜索和排序函數;
- unions 和 packed;
- class 和 structures
- string
- enumerated
賦值
- 賦全值(全0,全1,全x,全z)時,可以忽略位寬
- 注意verilog賦全1時,不能忽略位寬,也不能忽略進制。
// verilog parameter SIZE=64; logic [SIZE-1:0] data; data=`b0; data=`bz; data=`bx; data=64'hFFFFFFFFFFFFFFFF; //sv parameter SIZE=64; logic [SIZE-1:0] data; data=`0; data=`z; data=`x; data=`1;
4值邏輯
- 4值邏輯:0,1,x, z
- integer, logic, reg, net_type(例如wire, tri)
logic
- 支持連續賦值,門邏輯和模塊;
- 不支持多驅動,(例如:雙向端口,inout,只能用wire不能用logic);
- 可以替代VERILOG中的reg類型
2值邏輯
- bit, byte, shortint, int, longint
- 2值邏輯:0和1;z和x 會轉換成0
- 提升仿真性能和減少內存使用
- 不適用於DUT,因為DUT識別z和x,但是2值邏輯將會轉換為0
類型 | 描述 | 例子 |
bit | unsigned | bit b; bit [31:0] b32; |
byte | 8 bits, signed | byte b8; (-128~127) |
shortint | 16 bits, signed | shortint s; |
int | 32 bits, signed | int i; |
longint | 64 bits, signed | longint l; |
2值邏輯和4值邏輯
- 仿真時,4值邏輯默認為x,2值邏輯默認為0
- 2值邏輯變量不能代表一個未初始化的狀態
- 4值邏輯可以賦值給2值邏輯變量,x和z會轉化成0
- 使用$isunknown() check任何bit是x或z,如果表達式任何一個bit是z或x,返回1;if($isunknown(iport)==1);
有符號和無符號
- 有符號: byte, shortint, int, longint, integer
- 無符號: bit, logic, reg, net-type(例如wire, tri)
數據類型轉換
靜態轉換
- 在轉換的表達式前加上單引號即可
- 不會対轉換值做檢查,如果轉換失敗,無從得知
- 在編譯的時候做檢查
- 有符號轉換成無符號: unsigned'(signed_vec)
動態轉換
- 在仿真的時候做檢查
- $cast(tgt, src)
顯示轉換
- 靜態轉換和動態轉化都需要操作符號或者系統函數介入
隱式轉換
-
不需要進行轉換的一些操作
定寬數組
- 支持多維數組
- 超過邊界寫將會被忽略,超過邊界讀將會返回x,2值邏輯也是返回x;
- byte,int, shortint,都是存儲在一個32位的空間中
- longint存儲在兩個32位的空間中
- 默認為unpacked數組
語法
type name [constant]; type name [0: constant];
int array[20]; // 元素:0-19 int array[64:83]; // 元素:64-83 logic [31:0] data [1024]; // 元素: 0-1023, 32位寬 int array1 [4]=`{3,2,4,1}; array1 [0:2]=`{5,6,7}; array1=`{{3}, `{3{8}}}; int md [2][3] = `{`{0,1,2}, `{3,4,5}};
存儲空間:pack vs unpack
// 兩個變量都可以表示24bit的數據容量 // b_pack只會占據 1 個 WORD 的存儲空間 // b_unpack占據 3 個 WORD 的存儲空間 // 如果變量前后都有容量定義,右邊的維度高,即b_unpack的3的維度高 bit [3][7:0] b_pack bit [7:0] b_unpack[3]; // logic是四值邏輯,即需要2bit logic [3][7:0] b_pack; // 2 個WORD 2*8*3 logic [7:0] b_unpack[3]; // 3 個WORD 2*8=16, 1個WORD
數組復制和比較
-
可以利用賦值符號 "=" 直接進行數組的復制
- 可以直接利用 "==" 或者 "!=" 來比較數組的內容,結果僅限於內容相同或者不相同
動態數組
-
定寬數組的寬度在編譯時就確定了;
- 動態數組可以在仿真運行時靈活調節數組大小,即存儲量
// 動態數組在聲明時,需要使用 [] 聲明,此時數組數組是空的,即0容量 // 使用new[] 來分配空間,在方括號中傳遞數組的寬度 // 也可以在調用 new[] 時將數組名傳遞,將已有的數組的值復制到新的數組中 initial begin: dynamic_array int dyn1[], dyn2[]; dyn1 = new[5]; // 分配5個元素 dyn1 = '{1, 2, 3, 4}; $display("dyn1 = %p", dyn1); // copp method option-1 dyn2 = dyn1; // 重新復制一份數據到dyn2,相當於深拷貝 $display("dyn2 = %p", dyn2); $display("dyn2 size is %0d", dyn2.size()); // copp method option-2 dyn2 = new[dyn1.size()](dyn1); $display("dyn2 = %p", dyn2); $display("dyn2 size is %0d", dyn2.size()); dyn2.delete(); $display("dyn2 size is %0d", dyn2.size()); end
隊列
- 可以在任何地方添加或刪除元素,並且通過索引實現隊任一元素的訪問
- 使用美元符號聲明:[$],元素標號從0到$
- 不需要使用new[] 去創建空間,一開始其空間為0
- 使用 push_back 和 pop_front 結合實現FIFO的用法,還有push_front 和 pop_back
initial begin: queue_use int que1[$], que2[$]; que1 = {10, 30, 40}; // 不需要使用單引號賦值 $display("que1 = %p", que1); que2 = que1; $display("que2 = %p", que1); que1.insert(1, 20); $display("que1 = %p", que1); que1.delete(3); // delete que1[3]==40 void'(que1.pop_front()); // pop que[0]==10 $display("que1 = %p", que1); foreach(que1[i]) $display(que1[i]); que1.delete(); $display("que1 = %p", que1); end
關聯數組
- 用來保存稀疏矩陣的元素
initial begin: associate_array int id_score1[int], id_score2[int]; // key ID, value SCORE id_score1[101] = 111; id_score1[102] = 222; id_score1[103] = 333; // associate array copy id_score2 = id_score1; id_score2[101] = 101; id_score2[102] = 102; id_score2[103] = 103; foreach(id_score1[id]) begin $display("id_score1[%0d] = %0d", id, id_score1[id]); end foreach(id_score2[id]) begin $display("id_score2[%0d] = %0d", id, id_score2[id]); end if(id_score.first(idx)) begin do $display("id_score[%d]=%d", idx, id_score[idx]); while(id_score.next(idx)); end end
結構體
- 數據的集合
- 使用struct語句創建
- 結合typedef可以用來創建新的類型,並利用新類型來聲明更多的變量
struct { bit [7:0] r,g,b; } pixel; // 創建一個pixel結構體 typedef struct { bit [7:0] r,g,b; } pixel_s; pixel_s my_pixel; // 聲明變量 my_pixel = `{'h10, 'h10, 'h10}; // 賦值
枚舉
- 可讀性和可維護性更好
- 結合typedef使用
- 枚舉類型可以直接賦值給整型: int a = INIT;
- 整型不能直接賦值給枚舉類型,需要進行轉換
typedef enum {INIT,DECODE,IDLE} fsmstate_e; fsmstate_e pstate, nstate; // 聲明自定義類型變量 case(pstate) IDLE: nstate = INIT INIT : nstate = DECODE; default: nstate = IDLE; endcase $display("Next state is %s", nstate.name());
字符串(string)
- SystemVerilog 包含一個string數據類型,它是一個可變尺寸、動態分配的字節數組。
- SystemVerilog 還包含許多特殊的方法來對字符串進行操作。
- string類型的變量可以從0到N-1(數組的最后一個元素)進行索引
- 可以作用於一個特殊的空字符串:""
- 從一個字符串讀取一個元素會產生一個字節
- string類型變量的索引從字符串的左側開始排列,例如:對字符串"Hello World!",索引0對應"H",索引1對應"e",依此類推...
- 如果在聲明中沒有指定初始值,變量會被初始化成空字符串("")
- $sformatf() 函數: 格式化函數
- $display() 函數: 打印函數
string s; initial begin s = "IEEE"; $display (s.getc(0)); //顯示第0個字符: I $display (s.tolower()); //顯示小寫字符: ieee s.putc(s.len() - 1,"-"); //putc是替換,len() - 1是字符串最后一位,即將最后一位替換成“ -” s = {s,"P1800"}; //字符串拼接 ->IEE-P1800 $display(s.substr(2,5)); // 顯示第2-5位字符 ->E-P1 //創建一個臨時字符串並將其打印 my_log ($sformatf("%s,%5d",s,42)); end
task my_log (string message); //打印信息 $display ("@%0t:%s",$time,message); endtask
for循環
// $size 默認獲得最高的維度 initial begin bit [31:0] src[5], dst[5]; for(int i=0;i<$size(src); i++) src[i] = i; end
foreach循環
// 自動創建變量j, 默認為最高維度 initial begin bit [31:0] src[5], dst[5]; foreach(dst[j]) dst[j] = j; end