学习内容来源于芯片验证小白跟随路桑做SV练习——2203期
1. 使用struct创建新类型
module tb;
struct {
byte unsigned r;
byte unsigned g;
byte unsigned b;
} pixel_a, pixel_b, pixel_c;
initial begin
pixel_a = '{8'h12, 8'h24, 8'h36};
print_pixel('{pixel_a.r, pixel_a.g, pixel_a.b})
end
function void print_pixel(byte unsigned pix_arr[3]);
$display("r = %0x, g = %0x, b = %0x", pix_arr[0], pix_arr[1], pix_arr[2]);//%x是十六进制
endfunction
endmodule
这段代码中,我们声明了一个结构体
struct {
byte unsigned r;
byte unsigned g;
byte unsigned b;
} pixel_a, pixel_b, pixel_c;
默认情况下,结构体是一个非合并数组,所以我们在给结构体赋值时要用 '{ }
pixel_a = '{8’h12, 8’h24, 8’h36};
我们定义了一个打印函数print_pixel,形式参数为一个数组pix_arr[3],数组内有三个元素,每个元素为无符号byte。
function void print_pixel(byte unsigned pix_arr[3]);
我们传入了我们定义的非合并数组’{pixel_a.r, pixel_a.g, pixel_a.b},通过打印函数进行打印
print_pixel('{pixel_a.r, pixel_a.g, pixel_a.b})
以下代码是错误示例
module tb;
struct {
byte unsigned r;
byte unsigned g;
byte unsigned b;
} pixel_a, pixel_b, pixel_c;
initial begin
pixel_a = '{8'h12, 8'h24, 8'h36};
print_pixel(pixel_a)
end
//情况一:
function void print_pixel(byte unsigned pixel_a);
$display("r = %0x, g = %0x, b = %0x", pixel_a.r, pixel_a.g, pixel_a.b);//%x是十六进制
endfunction
//情况二:
function void print_pixel(pixel_a);
$display("r = %0x, g = %0x, b = %0x", pixel_a.r, pixel_a.g, pixel_a.b);//%x是十六进制
endfunction
endmodule
对于情况一:function void print_pixel(byte unsigned pixel_a);
传入的形式参数为byte unsigned pixel_a
,该参数实际上是一个无符号byte类型,变量名pixel_a与外面定义的结构体pixel_a是没有关系的。
对于情况二:function void print_pixel(pixel_a);
传入的形式参数为pixel_a
,该参数是一个变量,但是函数需要传递的是一个类型,同样,变量名pixel_a与外面定义的结构体pixel_a是没有关系的,不能指代pixel_a结构体类型。
2. 结构体的赋值方式
module tb;
struct {
byte unsigned r;
byte unsigned g;
byte unsigned b;
} pixel_a, pixel_b, pixel_c;
initial begin
pixel_a = '{8'h12, 8'h24, 8'h36};
print_pixel('{pixel_a.r, pixel_a.g, pixel_a.b})
pixel_b = pixel_a;
print_pixel('{pixel_b.r, pixel_b.g, pixel_b.b})
pixel_b = '{g:8'haa, b:8'hbb, r:8'hcc};
print_pixel('{pixel_b.r, pixel_b.g, pixel_b.b})//通过索引赋值
end
function void print_pixel(byte unsigned pix_arr[3]);
$display("r = %0x, g = %0x, b = %0x", pix_arr[0], pix_arr[1], pix_arr[2]);//%x是十六进制
endfunction
endmodule
3. 合并数组
结构体默认是非合并形的,添加packed后会变为合并形。合并形与非合并形的三个代码写法上的区别是:1.赋值方式有无单引号 ’ ,2.数组定义方式bit[2:0] [7:0]arr,bit arr[2:0][7:0](注意数组高低维度),3.只有bit和logic可以用于合并形
module tb;
struct packed{
logic[7:0] r;
logic[7:0] g;
logic[7:0] b;
} pixel_a, pixel_b, pixel_c;
initial begin
pixel_a = {8'h12, 8'h24, 8'h36};
print_pixel({pixel_a.r, pixel_a.g, pixel_a.b})
pixel_b = pixel_a;
print_pixel({pixel_b.r, pixel_b.g, pixel_b.b})
pixel_b = {g:8'haa, b:8'hbb, r:8'hcc};
print_pixel({pixel_b.r, pixel_b.g, pixel_b.b})//通过索引赋值,数组里也有这个用法
end
function void print_pixel(logic[2:0][7:0] pix_arr);
$display("r = %0x, g = %0x, b = %0x", pix_arr[2], pix_arr[1], pix_arr[0]);//%x是十六进制
endfunction
endmodule
这段代码中,我们对结构体struct添加了packed,添加了packed后,会将结构体里的r,g,b紧密的存放在一起,节省空间。也就意味着r,g,b缩减为一个向量。
struct packed{
logic[7:0] r;
logic[7:0] g;
logic[7:0] b;
} pixel_a, pixel_b, pixel_c;
此时,结构体变成了一个合并形数组,对合并形数组的赋值,我们的赋值方式是{ },没有单引号 '。
initial begin
pixel_a = {8’h12, 8’h24, 8’h36};
print_pixel({pixel_a.r, pixel_a.g, pixel_a.b})
pixel_b = pixel_a;
print_pixel({pixel_b.r, pixel_b.g, pixel_b.b})
pixel_b = {g:8’haa, b:8’hbb, r:8’hcc};
print_pixel({pixel_b.r, pixel_b.g, pixel_b.b})
end
函数形式参数里引入的数组类型的定义方式也要发生变化,更改为合并形数组类型
function void print_pixel(logic[2:0][7:0] pix_arr);
4.利用typedef将struct定义为一个类型
module tb;
typedef struct packed{
logic[7:0] r;
logic[7:0] g;
logic[7:0] b;
} pixel_t
pixel_t pixel_a, pixel_b, pixel_c;
initial begin
pixel_a = {8'h12, 8'h24, 8'h36};
print_pixel(pixel_a)
pixel_b = pixel_a;
print_pixel(pixel_b)
pixel_b = {g:8'haa, b:8'hbb, r:8'hcc};
print_pixel(pixel_b)//通过索引赋值,数组里也有这个用法
end
function void print_pixel(pixel_t pix);
$display("r = %0x, g = %0x, b = %0x", pix.r, pix.g, pix.b);//%x是十六进制
endfunction
endmodule
利用typedef将struct定义为一个类型pixel_t后,在函数里就可以引入该类型的形式参数了
function void print_pixel(pixel_t pix);