System Verilog新的数据类型
- 双状态数据类型:更好的性能,更低的内存消耗
- 队列、动态和关联数组:减少内存消耗,支持搜索和分类功能
- 类和结构:支持抽象数据结构
- 联合和合并结构:对同一数据有多种视图(view)
- 字符串:支持内建的字符序列
- 枚举类型:增加可读性
内建数据类型
- 四状态数据类型:0,1,Z,X
- 变量(reg)、线网(wire)
- 逻辑(logic)类型
- 双状态数据类型:0,1
- bit,byte,shortint,int,longint,real
- 四状态数据类型:0,1,Z,X
定宽数组
声明
1
2
3
4int lo_hi[0:15];
int c_style[16];
int array2[0:7][0:3];
int c_style_array2[8][4];Note: System Verilog 仿真器在存放数组元素时使用32比特的字边界,byte、shortint、int存放在一个字中,longint存放到两个字中。
常量数组
初始化:‘{ }
1
2
3
4
5int ascend[4] = '{0,1,2,3};
int descend[5];
descend[0:2] = '{5,6,7};
ascend = '{4{8}};
descend = '{9,8,default:1};
基本数组操作:for,foreach
一维数组
1
2
3
4
5
6
7initial begin
bit [31:0] src[5], dst[5];
for (int i=0; i<$size(src);i++)
src[i] = i;
foreach(dst[j])
dst[j] = src[j] * 2;
end多维数组 md[i, j]
1
2
3
4
5
6
7
8
9
10
11
12int md[2][3] = '{'{0,1,2},'{3,4,5}};
initial begin
foreach(md[i,j])
$display("md[%0d][%0d]=%0d",i,j,md[i][j]);
foreach(md[i]) begin
$write("%2d:",i);
foreach(md[,j])
$write("%3d", md[i][j]);
$display;
end
end
基本数组操作:聚合复制,比较
1
2
3
4
5
6
7
8
9
10
11initial begin
bit [31:0] src[5] = '{0,1,2,3,4},
dst[5] = '{5,4,3,2,1};
// 聚合比较
if (src == dst)
$display("src == dst");
else
$display("src!=dst");
// 聚合复制
dst = src;
end同时使用位下标和数组下标 (Verilog-2001)
1
2
3
4
5
6initial begin
bit [31:0] src[5] = '{5{5}};
$display(src[0],, // 'd5
src[0][0],, // 'b1
src[0][2:1]); // 'b10
end合并数组:存放方式是连续的bit集合
Principle 0 合并的位和数组的大小是数据类型的一部分
Principle 1 数组大小定义的格式必须是[msb:lsb],不是[size]
Principle 2 合并数组和非合并数组可以混合使用
Principle 3 敏感信号只能是标量或者合并数组
1
2
3
4
5
6
7
8
9
10
11
12
13bit [3:0] [7:0] bytes; // 4个字节组成32比特
bytes = 32'hCafe_Data;
$display(bytes,, // 'hCafe_Data
bytes[3],, // 'hCA
bytes[3][7]); // 'b1
bit [3:0] [7:0] barray [3]; // 具有3个合并元素的非合并数组
barray[0] = 32'h0123_4567; // 使用一个下标可以得到一个字的数据
barray[0][3] = 8'h01; // 使用两个下标可以得到一个字节的数据
barray[0][1][6] = 1'b1; // 使用三个下标可以得到一个比特位的数据
@(barray) // 错误
@(barray[0] or barray[1] or barray[2]) // 正确
动态数组
声明时使用空的下标[],仿真运行时调用new[]分配空间
内建子程序(routines):delete,size
1
2
3
4
5
6
7
8
9
10int dyn[], d2[];
initial begin
dyn = new[5]; // 分配空间:5个元素
foreach (dyn[j]) dyn[j] = j; // 初始化
d2 = dyn; // 复制动态数组
d2[0] = 5; // 修改元素值
dyn = new[20](dyn); // 分配20个整数值,复制dyn 5个值,删除原dyn
dyn = new[100]; // 分配100个整数值,删除原dyn 20个值的存储
dyn.delete(); // 删除所有元素
end
队列
声明时使用带美元符号的下标[$]
可以使用方法(method)在队列中增加和删除元素
可以使用字下标串联替代方法
- [$:2] 中\$代表最小值, [1:\$]中\$代表最大值
队列常量(literal)只有大括号没有数组常量中开头的单引号
不要对队列使用构造函数new[]
可以把定宽或动态数组的值赋给队列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24int j = 1,
q2[$] = {3,4},
q[$] = {0,2,5};
initial begin
q.insert(1,j); // {0,1,2,5}
q.insert(3,q2); // {0,1,2,3,4,5}
q.delete(1); // {0,2,3,4,5}
q.push_front(6); // {6,0,2,3,4,5}
j=q.pop_back; // {6,0,2,3,4}, j = 5
q.push_back(8); // {6,0,2,3,4,8}
j=q.pop_front; // {0,2,3,4,8}, j = 6
foreach(q[i])
$display(q[i]);
q.delete();
q = {q[0],j,q[1:$]);
q = {q[0:2],q2,q[3:$]};
q = {q[0],q[2:$]};
q = {6,q};
j = q[$];
q = q[0:$-1];
q = {}; // 删除队列
end
关联数组
保存稀疏矩阵的元素:超大地址空间,但只为实际写入的元素分配空间。
仿真器可以采用树或哈希表的形式存放关联数组。
声明时在方括号中放置数据类型,如[int],[packet]。
内建方法:num, exists
可以使用字符串索引寻址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51initial begin
bit [63:0] assoc[bit[63:0]], idx = 1;
// 对稀疏分布的元素进行初始化:1,2,4,8,16,...
repeat (64) begin
assoc[idx] = idx;
idx = idx << 1;
end
// 使用foreach遍历数组
foreach (assoc[i])
$display("assoc[%h]=%h",i,assoc[i]);
// 使用函数遍历数组
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
// 带字符串索引的关联数组
/* 输入文件内容如下:
42 min_address
1492 max_address
*/
int switch[string], min_address, max_address;
initial begin
int i,r,file;
string s;
file=$fopen("switch.txt","r");
while(!$feof(file)) begin
r = $fscanf(file,"%d %s", i,s);
switch[s] = i;
end
$fclose(file);
min_address = switch["min_address"]; // 获取最小地址值,缺省为0
if (switch.exists("max_address")) // 获取最大地址值,缺省为1000
max_address = switch["max_address"];
else
max_address = 1000;
foreach (switch[s]) // 打印数组所有元素
$display("switch['%s']=%d",s,switch[s]);
end
链表
- 应避免使用链表,优先使用队列。
数组的方法
对象:非合并数组类型
数组缩减方法:sum、product、and、or、xor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20bit on[10];
int total;
initial begin
foreach(on[i])
on[i] = i;
$display("on.sum = %0d", on.sum); // 1
$display("on.sum = %0d", on.sum + 32'd0); // 5
total = on.sum;
$display("total = %d", total); // 5
$display("int sum = %d", on.sum with (int'(item))); // 5
end
int count,total,d[]='{9,1,8,3,4,4};
count = d.sum with (item > 7); // 2: {9,8}
total = d.sum with ((item>7) * item); // 17: 9+8
count = d.sum with (item < 8); // 4: {1,3,4,4}
total = d.sum with (item < 8? item : 0); // 12: 1+3+4+4
count = d.sum with (item == 4); // 2: {4,4}随机选取一个元素
$urandom_range(\$szie(array)-1) : 定宽数组、队列、动态数组、关联数组
$urandom_range(array.size()-1):队列、动态数组
1
2
3
4
5
6
7
8
9// 关联数组中取一个元素,需要逐个访问它之前的元素
int aa[int], rand_idx, element, count;
element = $urandom_range(aa.size()-1);
foreach(aa[i])
if (count++ == element) begin
rand_idx = i;
break;
end
$display("%0d element aa[%0d]=%0d", element, rand_idx, aa[rand_idx]);
数组定位方法:min、max、unique、find
返回值:队列
条件语句with中,item是重复参数,代表数组中一个单独的元素
1
2
3
4
5
6
7
8
9
10
11
12
13int f[6] = '{1,6,2,6,8,6};
int d[] = '{2,4,6,8,10};
int q[$] = {1,3,5,7}, tq[$];
tq = q.min(); // {1}
tq = d.max(); // {10}
tq = f.unique(); // {1,6,2,8}
tq = f.find with (item > 3); // {6,6,8,6}
tq = f.find_index with (item > 3); // {1,3,4,5}
tq = f.find_first with (item > 99); // {}
tq = f.find_first_index with (item == 6); // {1}
tq = f.find_last with (item == 6); // {6}
tq = f.find_last_index with (item == 6); // {5}
数组的排序:reverse、sort、rsort、shuffle
reverse和shuffle方法不能带with条件语句,作用范围是整个数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15int d[] = '{9,1,8,3,4,4};
d.reverse(); // '{4,4,3,8,1,9}
d.sort(); // '{1,3,4,4,8,9}
d.rsort(); // '{9,8,4,4,3,1}
d.shuffle(); // '{9,4,3,8,1,4}
// 对结构数组排序
struct packed {byte red,green,blue;} c[];
initial begin
c=new[100];
foreach(c[i])
c[i] = $urandom;
c.sort with (item.red); // 只对红色像素进行排序
c.sort(x) with ({x.green,x.blue}); // 先对绿色像素后对蓝色像素进行排序
end
选择存储类型
- 灵活性
- 存储器用量
- 速度
- 排序
- 选择最优的数据结构
使用typedef创建新类型
1
2
3// uint定义:32比特双状态无符号数
typedef bit [31:0] uint;
typedef int unsigned uint;自定义结构
1
2
3// 声明
typedef struct {bit [7:0] r,g,b;} pixel_s;
pixel_s my_pixel;