目录
1.结构体
1.1 压缩结构体
1.2 非压缩结构体
1.3联合结构体
2.枚举类型
3.字符串
Verilog的最大缺陷之一是没有数据结构,SV中可以使用struct语句创建结构,跟C 语言类似。 不过struct的功能少,它只是一个数据的集合,其通常的使用的方式是将若干相关的变量组合到一个struct结构定义中,如bit,int,string,logic都可以放入一个struct当中。
然后用typedef可以用来创建新的类型,并利用新类型来声明更多变量。
struct {bit [7:0] r, g, b;} pixel; // 创建一个pixel结构体
//为了共享该类型,通过typedef来创建新类型
typedef struct {bit [7:0] r, g, b;} pixel_s;
pixel_s p1;//创建一个自定义的结构体的变量p1
pixel_s p2;//再定义一个p2
与数组类似,结构体也分压缩结构体和非压缩结构体。
对于压缩结构体,在系统为该结构体开辟一个32/64位的内存后,将该结构体里面的数组全部放到这个内存中,定义方式:
typedef struct packed{
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_t
和packed数组相似,将位宽合并到一起:
压缩结构体的赋值和packed数组类似,不需要'{ }:
typedef struct packed{
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_s;
pixel_s my_pixel; // 声明变量
my_pixel = {8'h10, 8'h10, 8'h10}; //结构体类型的赋值
对于非压缩结构体,系统会为每个元素分别开辟一条32/64bits的内存,定义方式:
typedef struct{
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_t
和unpacked数组类似,为每个元素单独开辟内存:
对于非压缩结构体的赋值和unpacked数组类似,需要用'{ }来进行赋值:
typedef struct {
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_s;
pixel_s my_pixel; // 声明变量
my_pixel = '{'h10,'h10,'h10}; //结构体类型的赋值,不是一个整体,需要分开赋值
联合结构体由于自身的一些限制使用较少(在某些SOC级的验证中,使用联合结构体为不同的寄存器建模),它是将多个结构体放入一个结构体中形成联合结构体:
typedef struct packed{
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_rgb_t;//定义一个压缩结构体
typedef struct packed{
bit [15:0] y;
bit [3:0] u;
bit [3:0] v;
} pixel_yuv_t;//定义一个压缩结构体
typedef union packed{
pixel_rgb_t rgb;
pixel_yuv_t yuv;
} pixel_t;//将上面两个组合在一起,注意union packed结构体中的成员必须有相同的位宽
pixel_rgb_t rgb_test;//定义一个pixel_rgb_t类型的压缩结构体rgb_test
pixel_yuv_t yuv_test;//定义一个pixel_yuv_t类型的压缩结构体yuv_test
pixel_t pixel_test;//定义一个联合结构体pixel_test
initial begin
rgb_test.r=8'h88;
rgb_test.g=8'h99;
rgb_test.b=8'haa;
$display(“Color RGB is: R=%h, G=%h, B=%h”,rgb_test.r, rgb_test.g, rgb_test.b);
yuv_test.y=16'h88;
yuv_test.u=4'h9;
yuv_test.v=4'ha;
$display(“Color YUV is: Y=%h, U=%h, V=%h”,yuv_test.y, yuv_test.u, yuv_test.v);
pixel_test = 0;
$display(“Color RGB is: R=%h, G=%h, B=%h”,pixel_test.rgb.r, pixel_test.rgb.g,pixel_test.rgb.b);
$display(“Color YUV is: Y=%h, U=%h, V=%h”,pixel_test.yuv.y, pixel_test.yuv.u,pixel_test.yuv.v);
pixel_test.rgb.r=8'hab;
pixel_test.rgb.g=8'hcd;
pixel_test.rgb.b=8'hef;
$display(“Color YUV is: Y=%h, U=%h, V=%h”,pixel_test.yuv.y, pixel_test.yuv.u,pixel_test.yuv.v);
end
仿真结果如下:
联合结构体带来的好处和风险?
联合结构体可以通过对整体的赋值从而将联合结构体里面的结构体同步赋值;但可见对联合结构体中的一个结构体赋值,会同步将另一个结构体也赋值,因此无法将联合结构体中的结构体分别赋值。
对于一个状态机,进行状态跳转的时候,以前可能是利用参数化的方法表明状态:
parameter INIT =2'b00;
parameter DECODE =2'b01;
parameter IDLE =2'b10;
现在我们可以用枚举类型的数据变量来更方便的表示不同的状态:
typedef enum {INIT, DECODE, IDLE} fsmstate_e;//默认INIT=0,DECODE=1,IDLE=2
fsmstate_e pstate, nstate; // 声明自定义类型变量
……
case (pstate)
IDLE: nstate = INIT; // 数值赋值
INIT: nstate = DECODE;
default: nstate = IDLE;
endcase
$display(“Next state is %s”, nstate.name()); // 显示状态名,如果不用.name,则显示编号:0/1/2
可见定义的枚举变量会默认为其中的元素赋值,当然我们也可以自定义其中的数值:
typedef enum {A=1,B,C,X=35,Y,Z} fsmstate_e;//此时A=1,B=2,C=3,X=35,Y=36,Z=37
枚举变量有且仅有一个数值。
需要注意的是,枚举类型会被当成int型变量存储,因此其默认值是0,所以如下给枚举赋值时由于并没有值为0的元素,但会被默认初始化为0,就会造成仿真时没有合适的枚举name而只有其默认值0:
仿真结果如下:
这种情况我们需要给枚举类型里的某个元素赋值为0即可
仿真结果:
枚举遍历:
枚举类型的默认值是二值的int,可以直接将枚举变量直接赋值给int,但是int不能直接赋值给枚举变量,需要做一个cast转换,可参见SV学习笔记—多态与类型转换
所有与字符串相关的处理,都使用string来保存和处理。 与字符串处理相关的还包括字符串的格式化函数,即如何形成一个你想要的字符串句子呢?可以使用SV系统方法$sformatf();
如果只需要将它打印输出,那么就使用$display()。
string s;
initial begin
s = "IEEE ";
$display(s.getc(0)); // 显示第0个字母‘I’的ASCII码,73
$display("%s", s.getc(0)); // 显示‘I’
$display(s.tolower()); // 将大写变成小写,显示 ieee
s.putc(s.len()-1,"-"); // 将空格变为‘-’
s = {s,"P1800"}; // "IEEE-P1800"
$display(s.substr(2, 5)); // 将第2-5个字母提出来,显示 EE-P
my_log($sformatf("%s %5d", s, 42)); // 创建一个临时字符串并将其打印
end
task my_log(string message); // 打印消息
$display("@%0t: %s", $time, message);
endtask