第二章:資料型別(續)
2.6 連結串列
SystemVerilog提供了連結串列資料結構,但是應該避免使用它,因為SystemVerilog提供的佇列更加高效易用。
2.7陣列的方法
SystemVerilog提供了很多種陣列的表示方法,那麼我們對這些陣列的操作方法又有哪些呢?下面就來一一介紹一下。
2.7.1 陣列的縮減方法
基本的陣列縮減方法就是把一個陣列縮減成一個值。最常用的方法就是求和sum,除此之外還有product(乘)and(與)or(或)xor(異或)等。
在進行陣列壓縮的時候,應該特別重要的一點需要注意,那就是位寬的問題下面就用一個例子來進行說明。
module test_enum();
bit on[10];
int total;
initial
begin
foreach(on[i])
on[i]=i;
$display("on.sum=%0d",on.sum); //on.sum是單位元無符號的數
$display("on.sum=%0d",on.sum+32'd0); //on.sum是32位元數
$display("int sum=%0d",on.sum with (int'(item))); //利用with來限定on.sum的資料型別,這是一種比較好用的方式
end
endmodule
結果:
# on.sum=1
# on.sum=1 //Medesim SE 10.2c模擬出來的結果並不支援相加方式得到的資料轉換
# int sum=5
SystemVerilog中,對定寬陣列、佇列、動態陣列和關聯陣列可以使用$urandom_range($size(array)-1)來選取隨機一個元素,而對於佇列和動態陣列還可以使用$urandom_range(array.size()-1)。
2.7.2 陣列定位方法
如何選取陣列中最大的值、最小的值?如何選取出陣列中唯一值的佇列?如何對陣列中滿足特定要求的值進行某種操作?下面我們就多這些問題一一作出求解方法。
module test_enum();
int f[6]={1,6,2,6,8,6},
d[]='{2,4,6,8,10},
q[$]={1,3,5,7},
tq[$];
initial
begin
tq=q.min(); //求最小值
foreach(tq[i])
$display("min:tq[%0d]=%0d",i,tq[i]);
tq=q.max(); //求最大值
foreach(tq[i])
$display("max:tq[%0d]=%0d",i,tq[i]);
tq=f.unique(); //求陣列中唯一值的佇列
foreach(tq[i])
$display("unique:tq[%0d]=%0d",i,tq[i]);
tq=d.find with (item>3); //利用find函式做操作
foreach(tq[i])
$display("find:tq[%0d]=%0d",i,tq[i]);
tq.delete(); //等價的操作
foreach(d[i])
if(d[i]>3)
tq.push_back(d[i]);
foreach(tq[i])
$display("tq[%0d]=%0d",i,tq[i]);
tq=d.find_index with (item>3); //輸出的是index索引也就是第幾位的值
foreach(tq[i])
$display("tq[%0d]=%0d",i,tq[i]);
end
endmodule
結果:
# min:tq[0]=1
# max:tq[0]=7
# unique:tq[0]=1
# unique:tq[1]=2
# unique:tq[2]=6
# unique:tq[3]=8
# find:tq[0]=4
# find:tq[1]=6
# find:tq[2]=8
# find:tq[3]=10
# tq[0]=4
# tq[1]=6
# tq[2]=8
# tq[3]=10
# tq[0]=1
# tq[1]=2
# tq[2]=3
# tq[3]=4
我想通過上述的程式碼和註釋,大家都能夠很好地理解。
注意:item被稱為重複引數,它代表了陣列中一個單獨的元素,item是預設的名字,你也可以指定別的名字。下面四種情況是等價的。
tq=d.find_first with (item==4);
tq=d.find_first() with (item==4);
tq=d.find_first(item) with (item==4);
tq=d.find_first(x) with (x==4);
當陣列的縮減方法和條件語句with結合使用時,sum操作符的結果是條件表示式為真的次數。下面我們來看一個例子。
module test_enum();
int count,
total,
d[]='{9,1,8,3,4,4};
initial
begin
count=d.sum with (item>7); //比較表示式返回0或1
total=d.sum with ((item>7)*item);
$display("count=%0d total=%0d",count,total); //2,17
count=d.sum with (item<8);
total=d.sum with (item<8?item:0);
$display("count=%0d total=%0d",count,total);//4,12
count=d.sum with (item==4);
$display("count=%0d",count); //2
end
endmodule
2.7.3 陣列的排序
SystemVerilog有幾個可以改變陣列中元素順序的方法。包括反向、正序、逆序、隨機。
int d[]='{9,1,8,3,4,4};
d.reverse();
d.sort();
d.rsort();
d.shuffle();
2.8 資料儲存型別的選擇
其實資料型別的選擇是多方面的,我們要考慮靈活性、儲存器用量、速度、排序和資料結構等多種方面,在我們以後的應用中,我們將會深入地理解每種不同的資料型別的利弊。
2.9 typedef建立新的型別
這是在原有資料型別之上定義新的資料型別。我們為了不混淆,約定所有使用者自定義型別都帶字尾“_t”。
下面我們來看幾個例子。
parameter opsize=8;
typedef reg[opsize-1:0] opreg_t;
opreg_t op_a,op_b;
typedef bit[31:0] uint;
typedef int unsigned uint; //等價的兩種方式
對於新的陣列定義並不是很明顯。你需要把陣列的下標放在新的陣列名稱中。如下面的例子所示:
typedef int fixed_array5[5];
fixed_array5 f5;
initial
begin
foreach(f5[i])
f5[i]=i;
end
2.10建立使用者自定義結構
Verilog中沒有資料結構,這是它的一個比較大的缺陷。在SystemVerilog中,我們引入了資料結構的概念。struct只是把資料組織在一起,只是一個資料的集合。
2.10.1 使用struct建立新型別
struct可以把若干個變數組合到一起。我們統一將struct建立的新型別用“_s”來表示。
typedef struct{bit[7:0] r, g,b;} pixel_s;
pixel_s my_pixel;
initial
begin
typedef struct {int a,
byte b,
shortint c;} my_struct_s;
my_struct_s st='{32'haaaaaaaa,
8'hbb,
16'hcccc};
$display("st=%x %x %x",st.a,st.b,st.c);
end
2.10.2建立可容納不同型別的聯合
聯合體,通常意義上來講就是同一位置放置不同型別的資料。如果需要以若干不同的格式對同一暫存器進行頻繁讀寫時,聯合體相當有用。我們約定以“_u”為字尾。
typedef union { int i; real f;} num_u;
num_u un;
un.f=0.0;
2.10.3合併結構
通過一個例子我們來描述一下合併結構(packed)可以節省儲存空間。
typedef struct packed {bit [7:0] r,g,b} pixel_p_s;
pixel_p_s my_pixel;
2.11型別的轉化
SystemVerilog提供了多種資料型別,在我們實際的應用過程中,我們需要對資料型別進行轉化。本部分就轉化提供了幾種方法,下面一一來介紹。
2.11.1靜態轉換
靜態裝換不對轉換值進行檢查。如果越界的話,我們也不能察覺到。
基本轉換格式:type'(val)。
int i;
real r;
i=int '(10.0-0.1);
r=real '(42);
2.11.2動態轉換
動態轉換函式$cast允許對越界的數值進行檢查,如果不越界返回1,否則返回0。
2.11.3流操作符
流操作符>>和<<用於把其後的資料打包成一個位元流。>>是把資料從左到右變成資料流,<<是把資料從右到左變成資料流。
基本的流操作
int h;
bit [7:0] b,
g[4],
j[4]='{8'ha,8'hb,8'hc,8'hd};
bit [7:0] q,r,s,t;
initial
begin
h={>>{j}}; //0a0b0c0d
h={<<{j}}; //b030d050
h={<<byte{j}}; //0d0c0b0a
b={<<{8'b0011_0101}};//10101100
b={<<4 {8'b0011_0101}};//0101_0011
{>>{q,r,s,t}}=j;//將分散到四個位元組變數裡
h={>>{t,s,r,q}};//將四個位元組集中到h裡
end
2.12 列舉型別
利用內建函式name()可以得到列舉變數值對應的字串。我們統一用字尾“_e”來表示列舉的資料型別。
定義列舉值
列舉值預設為從0開始遞增的整數,可以自己定義列舉值。通常在我們把0指給列舉常量,可以避免一些不必要的錯誤。-
列舉型別的子程式
(1)first() 返回第一個列舉變數
(2)last() 返回最後一個列舉變數
(3)next() 返回下一個列舉變數
(4)next(N) 返回以後第N個列舉變數
(5)prev() 返回前一個列舉變數
(6)prev(N) 返回以前第N個列舉變數
遍歷所有的列舉成員(注意對列舉型別值的定義)module test_typedef(); typedef enum{red,green,blue=6,yellow,white,black} colors; colors my_colors; initial begin my_colors=my_colors.first; do begin $display("my_colors=%0d/%s",my_colors,my_colors.name); my_colors=my_colors.next; end while (my_colors!=my_colors.first); end endmodule
結果:
# my_colors=0/red
# my_colors=1/green
# my_colors=6/blue
# my_colors=7/yellow
# my_colors=8/white
# my_colors=9/black
2.12.1列舉型別的轉換
列舉型別的預設型別為雙狀態的int。
可以通過簡單的賦值表示式把列舉變數直接賦值給變數int。
-
不允許直接把int賦值給列舉變數,這種是出於越界情況的考慮。
module test_enum(); typedef enum {RED,BLUE,GREEN} COLOR_E; COLOR_E color,c2; int c; initial begin color=BLUE; c=color; c++; if(!$cast(color,c)) $display("cast failed for c=%0d",c); $display("color is %0d/%s",color,color.name); c++; c2=COLOR_E'(c); $display("c2 is %0d/%s",c2,c2.name); if(!$cast(color,c)) $display("cast failed for c=%0d",c); end endmodule
結果:
# color is 2/GREEN
# c2 is 3/
# cast failed for c=3
$cast(color,c)將int型動態轉化為列舉型別,如果沒有越界返回1,否則返回0;界內(0,1,2),3已經越界了。
2.13 常量
SystemVerilog中支援const修飾符,允許在變數宣告時對其進行初始化,但不能在過程程式碼中改變其值。
initial
begin
const byte colon=":";
......
end
2.14 字串
SystemVerilog中的string型別可以用來儲存長度可變的字串。單個位元組是byte型別。字串使用動態的儲存方式,所以不用擔心儲存空間會全部用完。
module test_enum();
string s;
initial
begin
s="IEEE";
$display(s.getc(0));
$display(s.tolower());
s.putc(s.len()-1,"-");
s={s,"P1800"};
$display(s.substr(2,5));
my_log($psprintf("%s %5d",s,42));
end
task my_log (string message);
$display("@%0t:%s",$time, message);
endtask
endmodule
getc(N) 返回位置N上的位元組
tolower()返回一個小寫的字串
putc(M,C)把位元組C寫到字串的M位上,M必須介於0和len所給出的長度之間。
substr(start,end),讀取從位置start到end之間的所有字元。
-
task函式是用來返回一個格式化的臨時字串,並且可以直接傳遞給其他子程式。
結果:# 73 對應字元“I” # ieee # E-P1 # @0:IEE-P1800 42
相關文章
- 第二章 java基礎(基本資料型別介紹)Java資料型別
- js資料型別之基本資料型別和引用資料型別JS資料型別
- 資料型別: 資料型別有哪些?資料型別
- 強資料型別和弱資料型別資料型別
- 區別值型別資料和引用型別資料型別
- 資料型別,型別轉換資料型別
- 資料型別資料型別
- 3. php資料型別、資料型別轉換PHP資料型別
- JAVA中基本資料型別和引用資料型別Java資料型別
- 基本資料型別與字串型別資料型別字串
- Java中的基本資料型別與引用資料型別Java資料型別
- MySQL基礎之----資料型別篇(常用資料型別)MySql資料型別
- Mysql資料庫學習(二):資料型別(數值型別 日期和時間型別 字串型別)MySql資料庫資料型別字串
- 第二章 型別、運算子、表示式型別
- php資料型別PHP資料型別
- Symbol資料型別Symbol資料型別
- JavaScript - 資料型別JavaScript資料型別
- 資料型別2資料型別
- JavaScript 資料型別JavaScript資料型別
- js資料型別JS資料型別
- 1.2 資料型別資料型別
- 一、資料型別資料型別
- JavaScript資料型別JavaScript資料型別
- numpy資料型別資料型別
- Sqlite—資料型別SQLite資料型別
- NumPy 資料型別資料型別
- MYSQL 資料型別MySQL 資料型別
- Redis資料型別Redis資料型別
- protobuf資料型別資料型別
- mxArray資料型別資料型別
- Interval資料型別資料型別
- Oracle資料型別Oracle資料型別
- JavaScript: 資料型別JavaScript資料型別
- 基本資料型別資料型別
- WINDOWS資料型別Windows資料型別
- SQL 資料型別SQL資料型別
- Oracle 資料型別Oracle資料型別
- TypeScript資料型別TypeScript資料型別