<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] 和verilog相比system verilog提供了很多數據改進的數據結構,一些數據對于創建者和測試者都有用。 ># 內建數據類型 ## 邏輯(logic)類型 system verilog對經典的reg數據類型進行了改進,使他除了作為變量以外,還能被**連續賦值、門單元、和驅動模塊所驅動**,這種改進的數據類型被稱為**logic**。</br> 它既可被過程賦值也能被連續賦值,編譯器可自動推斷**logic**是**reg**還是**wire**。唯一的限制是**logic**只允許一個輸入,不能被多重驅動,所以**inout**類型端口不能定義為**logic**。不過這個限制也帶來了一個好處,由于大部分電路結構本就是單驅動,如果誤接了多個驅動,使用**logic**在編譯時會報錯,幫助發現bug。*所以單驅動時用**logic**,多驅動時用**wire***。</br> 在[Jason的博客](https://link.zhihu.com/?target=http%3A//www.verilogpro.com/verilog-reg-verilog-wire-systemverilog-logic)評論中,Evan還提到一點**logic**和**wire**的區別。**wire**定義時賦值是連續賦值,而**logic**定義時賦值只是賦初值,并且賦初值是不能被綜合的。 ```verilog wire mysignal0 = A & B; // continuous assignment, AND gate logic mysignal1 = A & B; // not synthesizable, initializes mysignal1 to the value of A & B at time 0 and then makes no further changes to it. logic mysignal2; assign mysignal2 = A & B; // Continuous assignment, AND gate ``` ``` module tb ; logic [7:0]i; //聲明logic結構數據 initial begin i = 0; repeat(10) begin //循環10次 $display("i=%d",i); i = i + 1; end $display("test running!"); end endmodule ``` 仿真結果 ``` Start run at Nov 2 19:42 2020 i= 0 i= 1 i= 2 i= 3 i= 4 i= 5 i= 6 i= 7 i= 8 i= 9 ``` logic不僅能夠作為變量,而且可以被連續賦值,門單元和模塊所驅動。但是logic不能夠被多個結構體驅動。下面這段代碼展示了logic的使用方法。 ``` module logic_test(input logic rst_h ); parameter CYCLE = 20; logic q,q_1,d,clk,rst_1; initial begin clk = 0; forever #(CYCLE/2) clk = ~clk; // 過程賦值 end assign rst_1 = ~ rst_h; //連續賦值 not n1(q_1,q); //q_1被門驅動 my_dff d1(q,d,clk,rst_1); //q被模塊驅動 endmodule ``` **SystemVerilog logic的使用方法** * 單驅動時**logic**可完全替代**reg**和**wire**,除了Evan提到的賦初值問題。 * 多驅動時,如**inout**類型端口,使用**wire**。 ## 雙狀態數據類型 相比于verilog中的4狀態數據類型(1,0,x,z),SV引入雙狀態數據類型有利于提高仿真器的性能并減少內存的使用量。下面逐例解釋。 ``` bit b; // 雙狀態 單bit bit [31:0] b32; // 雙狀態,32bit,無符號 int unsigned ui; // 雙狀態,32bit,無符號 int i; // 雙狀態,32bit,有符號 byte b8; // 雙狀態,8bit ,有符號 shortint s; // 雙狀態,16bit,有符號 longint l; // 雙狀態,64bit,有符號 integer i4; // 四狀態,32bit,有符號 time t; // 四狀態,64bit,無符號 real r; // 雙狀態,雙精度浮點數。 ``` 雙狀態數據類型有利于提高仿真器的性能并減少內存。</br> **對四態信號的檢查:**($isunknown) 這會讓任意位置出現X或者Z時返回1,使用實例如下: ``` if( $isunknown(iport) == 1) $display("@%0t: 4-state velue detected on iport %b",$time,iport) ``` ***** 部分仿真結果如下: ``` module tb ; longint i; //聲明logic結構數據 byte b8; initial begin i = 0; b8 = 2; repeat(3) begin //循環 $display("i=%0d , b8=%0d",i,b8); i = i - 1; b8=b8*2; end end endmodule ``` ``` Start run at Nov 2 20:01 2020 i=0 , b8=2 i=-1 , b8=4 i=-2 , b8=8 ``` ># 定寬數組 verilog要求在聲明中必須給出數組的上下邊界,因為幾乎所有的數組都是用0作為索引下界,**所以sv允許只給出數組的寬度**,跟c語言類似。</br> **例 :數組的聲明** ``` int arr[0:15]; //16個整數 int c_style[16]; //c風格,16個整數 ``` 可以通過**在變量后面指定維度的方式來聲明多維數組**;</br> **例 : 聲明8行4列多維數據** ``` int arr2 [0:7][0:3]; //完整聲明 int arr2_cstyle[8][4]; ``` **特別注意:**如果讀取的數據地址越界,那么sv會**返回數組元素的缺省值** * logic類型:返回 X * 雙狀態類型:返回 0 * 線網在沒有驅動時輸出為 Z ## 數組的遍歷 ``` module tb ; int md[2][3] = '{'{1,2,3},'{4,5,6}}; // 聲明2行3列數組并賦初值,這里使用常量數組來初始化md數組 initial begin foreach(md[i,j]) //遍歷數組 $display("md[%0d][%0d]=%0d",i,j,md[i][j]); end endmodule ``` 輸出結果 ``` VCS Build Date = May 24 2016 20:38:43 Start run at Nov 2 20:26 2020 md[0][0]=1 md[0][1]=2 md[0][2]=3 md[1][0]=4 md[1][1]=5 md[1][2]=6 ``` 按維度遍歷 ``` module tb ; int md[2][3] = '{'{1,2,3},'{4,5,6}}; // 聲明2行3列數組并賦初值 initial begin foreach( md[i] ) begin //遍歷第1維 $write("%2d:",i); foreach( md[,j] ) //遍歷第2維 $write("%3d",md[i][j]); $display;//顯示一個維度 end end endmodule ``` 結果 ``` 0: 1 2 3 1: 4 5 6 ``` ## 數組的比較與復制 ``` module tb ; bit [31:0] src[5] = '{0,1,2,3,4}, dst[5] = '{5,4,3,2,1}; initial begin //比較兩個數組 if( src == dst ) $display("src == dst"); else $display("src != dst"); //把src元素拷貝到dst dst = src; //只改變一個元素 dst[0] = 5; //所有元素的值是否相等 $display("src %s dst",(src == dst)? "==" : "!="); //使用數組片段對第 1-4 個元素進行比較 $display("src[1:4] %s dst[1:4]",(src[1:4] == dst[1:4]) ? "==" : "!="); end endmodule ``` 輸出結果 ``` Start run at Nov 2 20:41 2020 src != dst src != dst src[1:4] == dst[1:4] ``` ## 使用數組位下標和數組下標 **例 : 位下標和數組下標** ``` module tb ; bit [31:0] src[5] = '{5,1,2,3,4}; initial begin $display(src[0],, // 5 src[0][0],, // 1 src[0][2:1]); // 2 end endmodule ``` ## 合并數組 對于一些數據你可能既希望作為**整體**訪問,也希望**拆分為更小單元**訪問,使用sv的合并數組可以實現這個功能。</br> **例 : 合并數組例子** ``` module tb ; bit [3:0][7:0] bytes ; //四個字節組裝而成的32 bit數據 initial begin bytes = 32'hCafe_Dada; $display(bytes,, //顯示所有32 bit bytes[3],, //顯示最高字節 "CA" bytes[3][7]); //顯示最高bit位 ”1“ end endmodule ``` 結果 ``` 3405699802 202 1 ``` **擴展說明:** 已知一個多維混合數組的定義為: ``` bit [3:0][7:0][15:0] Array [3:0][7][6]; ``` 那么當我們寫下 ``` Array[2][3][2][2] = xxxx; ``` 的時候,到底是對哪個位置賦值了?? 話不多說,直接看解答好啦~最后的答案其實很簡單,因為有一個簡單的圖示估計很多人知道,就是逆時針索引法: ![](https://img.kancloud.cn/df/ee/dfee598075719706775ec92a8906638d_533x330.png) **合并數組和非合并數組的選擇** * 合并數組:和標量進行相互轉換,等待數組中的變化必須使用合并數組 > # 動態數組 sv提供動態數組,動態數組在聲明時使用空下標[ ]。**寬度將不會在編譯時給出,而是在程序運行時在指定**。數組開始時為空,因此你必須調用`new [ ] `操作來分配空間。</br> **例 :動態數組實例** ``` module tb ; int dyn[],d2[] ; //聲明動態數組 initial begin dyn = new[5] ;//分配5個元素空間 foreach( dyn[i] ) dyn[i] = i; //對5個元素空間的值進行初始化 d2 = dyn ; //復制數組dyn到d2 d2[0] = 5 ; //修改d2[0]的值為5 $display(dyn[0],d2[0]); //顯示數值 dyn = new[20](dyn); //分配20個證書值并進行復制 dyn = new[100]; //分配 100 個新的整數值 dyn.delete(); //刪除所有元素 end endmodule ``` **例 : 使用動態數組保存元素數量不定的列表** ``` bit [7:0] mask[] = '{ 8'h00,8'h01, 8'h03,8'h04, 8'h23,8'h36}; ``` ># 隊列 隊列與鏈表類似,可以**在一個隊列中的任何地方增加和刪除元素**,這類操作在性能上的損失比動態數組小的多!</br> 隊列的聲明使用`[$]`,隊列元素的編號從0到$。sv的隊列類似與STL的雙端隊列。可以通過增加元素來創建隊列。**你可以擴大和縮小隊列,但是不用向動態數組一樣付出很大的代價**。</br> **例 : 隊列操作** ``` module tb ; //注意,隊列常量不需要使用“’” int q2[$] = {3,4}; int q[$]= {0,2,5}; initial begin //在2之前插入1 q.insert(1,1); // 0 1 2 5 foreach(q[i])$write("%3d",q[i]); $display; //顯示結果 //在5之前插入隊列q2 q.insert(3,q2); // 0 1 2 3 4 5 foreach(q[i])$write( "%3d",q[i]); $display; //顯示結果 //刪除q下標為1的元素 q.delete(1); //0 2 3 4 5 foreach(q[i])$write( "%3d",q[i]); $display; //顯示結果 //以下操作速度很快 //在隊列最前面插入 8 q.push_front(8); //8 0 2 3 4 5 foreach(q[i])$write( "%3d",q[i]); $display; //打印整個鏈表 //在隊列最前后面插入 6 q.push_back(6); //8 0 2 3 4 5 6 foreach(q[i])$write( "%3d",q[i]); $display; //顯示結果 //讀出隊列最前面的元素并從隊列中移除該元素 $display(q.pop_front()); foreach(q[i])$write( "%3d",q[i]); $display; //顯示結果 0 2 3 4 5 6 //讀出隊列最后面的元素并從隊列中移除該元素 $display(q.pop_back()); foreach(q[i])$write( "%3d",q[i]); $display; //顯示結果 0 2 3 4 5 end endmodule ``` 結果 ``` Start run at Nov 2 21:56 2020 0 1 2 5 0 1 2 3 4 5 0 2 3 4 5 8 0 2 3 4 5 8 0 2 3 4 5 6 8 0 2 3 4 5 6 6 0 2 3 4 5 ``` >>**說明:** 可以使用字下標串聯來代替方法。對于隊列`q[$]={0,2,4}`,如果把`$`放在一個范圍表達式的左邊,那么`$`將代表最小值,例如`[$:2]`就代表`[0:2]`。如果把`$`放在一個范圍表達式的右邊,那么`$`將代表最大值,例如`[1:$]`就代表`[1:2]`。 使用上述方法的操作如下:</br> **例 : 隊列串聯表達式** ``` module tb ; //注意,隊列常量不需要使用“’” int q2[$] = {3,4}; int q[$]= {0,2,5}; initial begin //在2之前插入1 q={q[0:1],1,q[2:$]}; // 0 1 2 5 foreach(q[i])$write("%3d",q[i]); $display; //顯示結果 //在5之前插入隊列q2 q={q[0:2],q2,q[3:$]}; // 0 1 2 3 4 5 foreach(q[i])$write( "%3d",q[i]); $display; //顯示結果 //刪除q下標為1的元素 q.delete(1); //0 2 3 4 5 foreach(q[i])$write( "%3d",q[i]); $display; //顯示結果 //刪除整個隊列 q={}; end endmodule ``` ># 關聯數組 當你只需要偶爾創建一個大容量數組,那么動態數組已經足夠好用了,但是如果需要超大容量的呢?sv提供了關聯數組用來保存稀疏矩陣的元素。也就是說只為實際寫入的數據開辟存儲空間。**可以將其理解為哈希表**,雖然哈希表帶來了額外開銷,但是在這種情況下,這是可以也接受的。</br> **例 : 關聯數組聲明,初始化和使用** ``` module tb ; bit [63:0] assoc[ bit [63:0] ],idx = 1; initial begin //對稀疏分布的元素進行賦值 repeat (3) begin assoc[idx] = idx; idx = idx << 1; end //foreach遍歷數組 foreach(assoc[i])$display("assoc[%h]=%h",i,assoc[i]); $display("+++++++++++++++++++++++"); //使用函數遍歷數組 if( assoc.first(idx) ) begin do $display("assoc[%h]=%h",idx,assoc[idx]); while( assoc.next(idx) ); //得到下一個索引 end //找到并刪除第一個元素 assoc.first(idx); assoc.delete(idx); $display("The array now has %0d elements",assoc.num); end endmodule ``` 結果 ``` Start run at Nov 2 22:22 2020 assoc[0000000000000001]=0000000000000001 assoc[0000000000000002]=0000000000000002 assoc[0000000000000004]=0000000000000004 +++++++++++++++++++++++ assoc[0000000000000001]=0000000000000001 assoc[0000000000000002]=0000000000000002 assoc[0000000000000004]=0000000000000004 The array now has 2 elements ``` **例 : 使用帶字符串索引的關聯數組** ``` //關聯數組也可以用字符串索引進行尋址,使用字符串索引讀取文件,并建立關聯數組switch,可以實現字符串到數字的映射。 /* 輸入文件內容如下: 42 min_address 1492 max_address */ int switch[string],min_address,max_address; //定義變量 initial begin //初始化 int i,r,file; string s;//string 用來年保存長度可變的字符串常量 file = $fopen(“switch.txt”,r); //在當前目錄下以只讀的方式打開文件switch.txt,使用指針向量file指向該文件 while(! $feof(file) ) begin //未讀取到文件的結尾時 r=$fscanf (file, “%d %s”, i, s); //將文件中的數字以10進制的方式保存到i中,字符串保存到s中 switch[s] = i; //為數組中的字符串指定地址 end $fclose(fire); //關閉文件 //獲取最小地址值,缺省為0 min_address=switch[“min_address”] //將min_address對應的地址(數字)賦值給min_address //獲取最大地址值,缺省為1000 if(switch.exists(“max_address”)) //使用exists函數判斷switch數組中是否含有“max_address” max_address = switch[“max_address”]//含有的話,將內容的地址賦值給 max_address else max_address =1000 //不存在指定內容,則默認地址為1000 //打印數組的所有元素 foreach(switch [s]) $display(“switch[ ‘ %s ’ ] = %0d ”, s ,switch[s] );//打印數組的內容和相應的地址 end ``` --- **例 : 字符關聯數組操作** ``` module tb ; bit [63:0] assoc[ string ]; initial begin //對稀疏分布的元素進行賦值 assoc["a"] = 1; assoc["b"] = 2; assoc["c"] = 3; //foreach遍歷數組 foreach(assoc[i])$display("assoc[%s]=%h",i,assoc[i]); end endmodule ``` ># 鏈表 sv提供了鏈表數據結構,類似于STL的列表容器,這個容器被定義為參數化的類,可以根據用戶所需存放各種類型的數據。</br> 雖然sv提供了鏈表,但是應該避免使用它。sv使用隊列更高效。 ># 數組的方法 sv提供了很多數組的方法,可以用于任何一種非合并數組的類型,**包括定寬數組,動態數組,隊列和關聯數組**。 ## sum方法:數組求和 **例 : 數組求和** ```module tb ; bit on[5] = '{0,1,0,1,0};//單bit數組 initial begin foreach( on [i])$write("%3d",on[i]);$display; //單bit求和 $display("on.sum=%0d",on.sum); end endmodule ``` 結果 ``` Start run at Nov 2 22:49 2020 0 1 0 1 0 on.sum=0 ``` >>sum方法的結果位寬和數組定義的位寬是一致的。 ## product方法:數組求積 **例 :數組求積** ``` module tb ; int on[3] = '{1,2,3};//單bit數組 initial begin foreach( on [i])$write("%3d",on[i]);$display; //單bit求和 $display("on.product=%0d",on.product); end endmodule ``` 結果 ``` Start run at Nov 2 22:57 2020 1 2 3 on.product=6 ``` ##and,or,xor方法:數組求與,或,異或 **例 :數組求與,或,異或** ``` module tb ; int on[3] = '{1,3,3};//單bit數組 initial begin foreach( on [i])$write("%3d",on[i]);$display; $display("on.and=%0d",on.and); $display("on.or=%0d",on.or); $display("on.xor=%0d",on.xor); end endmodule ``` ## min,max方法:最大值最小值方法 **注意返回值為一個隊列!** **例 :最大值最小值方法** ``` module tb ; int on[] = '{1,3,3,9}; int rt[$]; initial begin foreach( on [i])$write("%3d",on[i]);$display; rt=on.min();foreach(rt[i])$write("%3d",rt[i]);$display; rt=on.max();foreach(rt[i])$write("%3d",rt[i]);$display; end endmodule ``` 結果 ``` Start run at Nov 2 23:11 2020 1 3 3 9 1 9 ``` ## unique方法:排除重復數值 **注意返回值為一個隊列!** **例 :排除重復數值** ``` module tb ; int on[] = '{1,3,3,9}; int rt[$]; initial begin foreach( on [i])$write("%3d",on[i]);$display; rt=on.unique();foreach(rt[i])$write("%3d",rt[i]);$display; end endmodule ``` 結果 ``` Start run at Nov 2 23:15 2020 1 3 3 9 1 3 9 ``` ## size方法:獲取數組大小 **例 :獲取數組大小** ``` module tb ; int on[] = '{1,3,3,9}; int rt[$]; initial begin foreach( on [i])$write("%3d",on[i]);$display; //獲取動態數組的大小 $display("len=%0d",on.size()); //獲取各種數組大小的方法 $display("len=%0d",$size(on)); endmodule ``` 結果 ``` Start run at Nov 2 23:18 2020 1 3 3 9 len=4 len=4 ``` ## find方法:數組定位方法 **注意返回值為一個隊列!** **例 :find數組定位方法** ``` module tb ; int on[] = '{4,1,3,3,9}; int rt[$]; initial begin foreach( on [i])$write("%3d",on[i]);$display; //找出所有大于等于3的元素 4 3 3 9 rt=on.find with (item >= 3); foreach(rt[i])$write("%3d",rt[i]);$display; //找出值大于等于2的索引 0 2 3 4 rt=on.find_index with (item >= 2); foreach(rt[i])$write("%3d",rt[i]);$display; //找出第一個大于4的值 9 rt=on.find_first with (item >4); foreach(rt[i])$write("%3d",rt[i]);$display; //找出最后一個小于9的值 3 rt=on.find_last with (item < 9); foreach(rt[i])$write("%3d",rt[i]);$display; //找出第一個大于4的數據的索引值 4 rt=on.find_first_index with (item >4); foreach(rt[i])$write("%3d",rt[i]);$display; //找出最后一個==3的數據的索引值 rt=on.find_last_index with (item == 3); foreach(rt[i])$write("%3d",rt[i]);$display; end endmodule ``` 結果 ``` Start run at Nov 2 23:31 2020 4 1 3 3 9 4 3 3 9 0 2 3 4 9 3 4 3 ``` **例 : 等同的幾種描述** ``` rt=on.find_first with (item >= 3); rt=on.find_first() with (item >= 3); rt=on.find_first(item) with (item >= 3); rt=on.find_first(x) with (x >= 3); ``` ## 數組排序方法:reverse,sort,rsort,shuffle **例:數組排序** ``` module tb ; int on[] = '{4,1,3,3,9}; int rt[$],msum; initial begin foreach( on [i])$write("%3d",on[i]);$display; //數組反序 on.reverse(); foreach( on [i])$write("%3d",on[i]);$display; //數組 小->大 on.sort(); foreach( on [i])$write("%3d",on[i]);$display; //數組 大->小 on.rsort(); foreach( on [i])$write("%3d",on[i]);$display; //數組洗牌 on.shuffle(); foreach( on [i])$write("%3d",on[i]);$display; end endmodule ``` 結果 ``` Start run at Nov 3 00:12 2020 4 1 3 3 9 9 3 3 1 4 1 3 3 4 9 9 4 3 3 1 3 4 1 9 3 ``` ## 結構數組的使用和排序 **例 : 結構數組的使用和排序例子** ``` module tb ; int rt[$],msum; struct packed {byte red,green,blue;} c[]; //結構數組 initial begin c=new[5]; foreach(c[i])c[i] = $urandom;//隨機賦值 foreach( c[i])$write("%10d",c[i].red);$display; c.sort with (item.red); //up排序red foreach( c[i])$write("%10d",c[i].red);$display; end endmodule ``` 結果 ``` Start run at Nov 3 00:17 2020 -30 -34 127 -86 121 -86 -34 -30 121 127 ``` > # typedef創建新的數據類型 **例 :創建新數據類型** ``` parameter N = 8; typedef reg [N - 1 : 0 ] opreg_t; opreg_t c; ``` > # struct創建新的數據類型 **例 :struct創建新數據類型** ``` module tb ; int rt[$]; typedef struct packed {byte red,green,blue;} pixel_s;//結構數組 typedef struct packed {int a;bit[2:0] b;} m_s;//結構數組 pixel_s c='{1,2,3}; m_s cc = '{ 32'd23, 3'b101 }; initial begin $display("%5d %5d %5d",c.red,c.green,c.blue); $display("%5d %5d",cc.a,cc.b); end endmodule ``` 結果 ``` Start run at Nov 3 00:38 2020 1 2 3 23 5 ``` ># 靜態轉換 靜態轉換操作不對轉換值進行檢查。 **例 : 靜態轉換例子** ``` module tb ; int rt[$]; int i ; real r; initial begin i = int '(10.0 - 0.1); //非強制轉換 r = real '(42); $display(i); $display(r); end endmodule ``` > # 流操作 ``` module tb ; int rt[$]; byte h ; bit [3:0] q[2] = '{4'h04,4'h01} ; initial begin $display("%6b %6b",q[0],q[1]); //將q打包為byte h = {>>{q}}; //0100_0001 $display("%b",h); //位倒敘 h = {<<{h}}; //1000_0010 $display("%b",h); end endmodule ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看