![5c1b647199b2cff42f672e082b2a3ebd.png](https://i-blog.csdnimg.cn/blog_migrate/cfc18df95f39a887b6272da54e5e6826.jpeg)
![cbce73ba73b2c1434a4d85e7ea9b4700.png](https://i-blog.csdnimg.cn/blog_migrate/84bf895c8119e01ad930d234d61ed5a4.png)
![260cee73c78dc39dd020492f6a3340f8.png](https://i-blog.csdnimg.cn/blog_migrate/48e56cd272d9180d233507fce9f92d85.png)
1.两态数据类型
Verilog有两种基本数据类型:变量(reg)和网线(wire),这是四态的数据类型(0、1、X、Z)。
RTL代码使用变量(reg)存储组合逻辑和时序逻辑的数值,可以是
- 标量
- 向量(reg[7:0] bus_addr)、
- 有符号数32位变量(integer)、
- 无符号数64位的变量(time)、
- 浮点数(real)
- 变量也可以用来定义一个固定大小的数组
即这些变量的存储是静态的,意味着所有的变量在整个仿真过程中不能使用堆栈来保存参数和当前值。
网线用来连接两个设计模块,如门级元件或例化模块。
两态(1/0)数据类型:
SystemVerilog中的两态数据类型减少了仿真器对内存的使用和提高仿真的运行效率。
其中,bit是无符号数,shortint、int、longint、byte是有符号数。
基本数据类型
![dc8e55b9db5107903000f0493408b4d0.png](https://i-blog.csdnimg.cn/blog_migrate/157fb067c8dc07bee155e99a70f938d9.png)
整数数据类型
![047b6a9cdb0f7730d3bd80dadaab0f03.png](https://i-blog.csdnimg.cn/blog_migrate/fea56bbbaa2e3764c1546f724669ee21.png)
![8b1f8e0a9c69b3acc3faf5225048854e.png](https://i-blog.csdnimg.cn/blog_migrate/46f3847c645170d25dbe9948d511ddf4.png)
两态和有符号数据类型
例子:
bit a;//两态,单比特
bit[31:0] b32; //两态,32比特无符号数
Int c32; //两,32比特有符号数
byte d8; //两态,8比特有符号数
shortint e16;//两态,16比特有符号数
longint 1;//两态 ,64比特有符号数
在数据算术运算操作的过程中,需要时刻注意区分有符号(shortint、int、longint、byte、integer)和无符号数据类型。上述这些都是整型数据类型。
SystemVerilog对reg的数据类型做了改进,reg可以被连续赋值语句、门逻辑和模块直接驱动。
SystemVerilog引入一个新的四态数据类型logic,可以替代reg;但不能用在双向总线和多驱动的情况下,此时只能使用网线类型(wire)。
2.自定义类型
通过用户自定义类型,简化了verilog代码量并实现更多功能;
用户自定义类型使得代码的可读性更强;
通过typedef来创建用户自定义类型;
通过enmu来创建枚举类型;
通过struct来创建结构体类型;
SV提供自定义类型可以帮助用户构建更高抽象层的数据类型;
同C语言一样,用户可以利用已有的数据类型定义新的数据类型,一旦定义了新的数据类型,就可以利用该类型声明变量。
Typedef int unsigned unit;//定义新类型unit
unit a,b;//unit自定义类型unit声明的2个变量
注意:为了代码可读性,通常添加“_t”后缀表示它是一个自定义类型(type),而不是比变量。
在某些时候,自定义一个新的数据类型也是必须的,因为在SystemVerilog中要通过数据类型的标识符才可以做类型转换,如代码所示。
用户自定义类型实例
module test_ typedef( );
typedef enum (red, green, blue, yellow, white, black) colors ;
colors my colors;
initial
begin
$display(“my_ color’s default vaule is %s”,my_colors );
my_colors = green;
//my_ colors=l; //错误使用方法,需要做数据类型转换
my_ co1ors=colors’(2); 通过colors数据类型标识符做类型转换
$disp1ay( “my_co1or is % s” ,my_colors.name);
end
endmodul e
3.枚举类型
枚举类型(enum)可以描述变量的合法值范围,其每一个值都需要提供一个用户自定义的名字;
枚举类型 IC可以拥有Icer1,Icer2,Icer3.....IcerN数值,
即enmu{Icer1,Icer2,Icer3.....IcerN} IC;
Verilog语言不支持枚举类型,因此为了提供类似于枚举类型设计方式,我们不得不采用参数来表示可取值的范围,或者使用宏来定义各个合法值的宏名称。
使用宏定义和参数
![11cc2ef6536f16b6c1bd4c4e65470f49.png](https://i-blog.csdnimg.cn/blog_migrate/16a0bbd9f5fe37be94f75d6d24bd2da7.jpeg)
使用枚举类型
![21c14d446b034ec4dcdaa0bcecdf74bd.png](https://i-blog.csdnimg.cn/blog_migrate/599db2aa36bbac5fe690079447b92e40.jpeg)
定义枚举值
默认的枚举类型是int,即32位的二值逻辑数据类型;
为了更准确的描述变量,SV允许指明其数据类型,例如:
enum bit {TRUE,FALSE} Boolean;
enum logic [1:0] {WAITE,LOAD,READY} state;
自定义枚举类型
如果枚举类型变量被赋值,那么所赋的值应在其数值范围。
Enum logic {2:0} {WAITE=3’b001,LOAD=3’b010,READY=3’b100} state;
如果枚举变量是四值逻辑,那么将其值赋为X或者Z也是合法;
enum logic {ON=1’b1,OFF=1’b z} out;
如果枚举类型并没有伴随着typedef,那么该枚举类型指的是匿名枚举类型;此时变量名应伴随其后;
将typedef与enum合并,可以将匿名枚举类型声明为自定义类型,这就使得可以用同一个枚举类型来声明多个变量或者线网;
typedef enum {WAITE,LOAD,READY} states_t;
States_t state,next_state;
verilog或者SV可以在不同的数据类型之间通过隐性转换,进行直接赋值,因此verilog/SV的数据类型转换是宽松的;
枚举类型赋值
枚举类型赋值时则相对严格,例如下面的例子中,赋值操作符“-”的左右两侧应该尽量为相同的枚举类型。
Typedef enum {WAITE, LOAD, READY} states_t;
states_t state, next_State ;
int foo;
state = next_state; //合法操作
foo=state+1;//合法操作
state=foo+1;//非法赋值
state = states_t’ (foo + 1) ;//合法赋值
state = state + 1; //非法赋值
state= states_t’ (state + 1) //合法赋值
state++; // 非法赋值
next_state += state; //非法赋值
SystemVerilog为枚举类型提供了如下内置方法( method)来方便操作
function enum first ():返回枚举类型中第一个成员的值。
Function enum last ():返回枚举类型中最后一个成员的值。
Function enum next ( int unsigned N=1):
以当前成员为起点,返回后续第N个成员的值,默认是下一个成员的值;若起点为最后一个成员,则默认返回第一个成员的值。
Function enum prev ( int unsigned N=1):
以当前成员为起点,返回前面第N个成员的值,默认是前面一个成员;若起点为第一个成员,则默认返回最后一个成员的值。
Function int num ():返回该枚举类型的成员数目。
Function string name ():以字符串的形式返回该成员名字。
4.结构体类型
SV添加了和C一样的结构体struct,而结构体成员可以是任何变量类型,包括自定义类型或者其他常量类型;
Struct{
Int a,b;//32位变量
Opcode_t opcode;//用户自定义类型
logic [23:0] address;//24位变量
Bit error;//1位变量
}Instruction_Word;//变量名
结构体类型的变量可以用来索引到其内部的变量,索引方式同C一样。
<structure_name>.<variable_name>
Instruction_Word.address=32’hF000001E;
结构体类型默认也是变量类型,用户可以显式声明为var或者wire类型;
类似与于枚举类型,结构体类型也可以伴随着typedef来实现自定义结构体类型;
Typedef struct { //自定义结构体
logic [31:0] a,b;
Logic [7:0] opcode;
Logic [23:0] address;
}instruction_word_t IW;// 结构体变量声明
结构体变量可以通过索引其各个成员做依次的成员赋值:
Always @(posedge clk or negedge rst_n)begin
If(!rst_n)begin
IW.a=100;//结构体成员
IW.b=5;
IW.address=0;
End
else begin
......
end
end
也可以通过分号’ 和花括号{}来实现整体赋初值;
IW=’ {100,3,8’hFF,0};
IW=’ {addres:0,opcode:8’hFF,a:100,b:5}; //成员和数值通过冒号:一一对应。
5.字符串类型
SV中引入string类型来容纳可变长度的字符串;
字符串类型变量的存储单元为byte类型;
字符串类型变量长度为N,则字符成员索引值从0到N-1;
不同与C语言,字符串结尾没有空字符 “0”;
字符串的内存是动态分配的,用户无需担心内存空间管理;
字符串内建方法:
str..len():返回字符串长度
str.putc(I,c):将第i个字符替换为字符c,等同于str[i]=c;
str.getc(i): 返回第i个字符;
str.substr(i,j): 返回第i个字符到第j个字符的字符串
str.tolower():返回一个小写字符串;
str.toupper(): 返回一个大写字符串;
str.{atoi(),atohex(),atooct(),atobin()}:返回十进制、十六进制、八进制、二进制数据;