目录
-
-
简化数据
-
define RTL 层级路径
`define TB_TOP top
`define RTL_WRAPPER `TB_TOP.ip_core
`define IP_ENGINE_TOP `RTL_WRAPPER.u_ips_engine_top
// Register
// generate
// for(i=0;i<4;i=i+1)
// begin: VFX_REG // VF_REG[*]
// ip_vfx_reg u_vf_reg(.....)
// end
// endgenerate
`define IP_VF0_REG `IP_ENGINE_TOP.VFX_REG[0].u_vf_reg
`define IP_VF1_REG `IP_ENGINE_TOP.VFX_REG[1].u_vf_reg
`define IP_VF2_REG `IP_ENGINE_TOP.VFX_REG[2].u_vf_reg
`define SELECT_CHA(chx) (1 << (32'h + (chx))) // 左移
-
paremeter 定义参数
parameter CORE_ID = (32'h001);
parameter VF_REG = (32'h000);
parameter CTRL_1 = (VF_REG + 32'h2);
Verilog中`define、parameter、localparam三者的区别及举例
https://blog.csdn.net/GOGOmusic/article/details/79047335
-
typedef 构建数据结构
int //32bit 有符号 整数
typedef bit[31:0] unit; //32bit 无符号 整数
typedef int unsigned unit; //等效
// struce 自定义类型
typedef struct {int a;
byte b;
int d;} my_struct_s;
my_struct_s st= '{32'haaaa_dddd,
8'hbb,
32'hbbbb_cccc};
//合并结构的struct
typedef sturct packed {
bit[31:4] rsv_31_4;
bit[3:3] num_3;
bit[2:2] num_2;
bit[1:1] num_1;
} CTRL_Type;
构建一个描述符结构
typedef struct packed {
bit[127:0] __rsv__ ;
bit[31:16] block_id;
bit[15:9] block_size;
bit[8:7] block_st;
bit[6:0] block_o;
} BLOCK_Descriptor_Type; // _Type _t: typedef定义
BLOCK_Descriptor_Type de_1_s; // _s : struct类型
-
数据类型
-
定宽数组
- 仿真器默认使用32bit的内存单元存储数据,所以bit [7:0] b_unpack[3]; 这种声明是非合并数组。
int value[5]; //value[0] value[1] .... value[4]
int value[0:4]; //效果一样
多维数组
int num[4][3];
int num[0:3][0:2];
多维数组的赋值
int packed_size[4][2] = '{
'{$urandom_range(32,128), $urandom_range(32,128},
'{$urandom_range(32,128), $urandom_range(32,128},
'{$urandom_range(32,128), $urandom_range(32,128},
'{$urandom_range(32,128), $urandom_range(32,128}
};
-
合并数组(属于定宽数组)
- 合并数组在内存上是连续的,32bit的仿真器默认的存储单元。
- Packed and unpacked arrays
- bit [7:0] val; packed
- bit val[7]; unpacekd
-
动态数组
- https://mp.weixin.qq.com/s/KGND0T2C7yN8jUmNUj4ZMA
多维动态数组
1.
class block_gen;
rand bit[63:0] block_idx[][];
function new();
block_idx = new[4];
foreach (block_idx[i]) begin
block_idx[i] = new[8];
end
endfunction
function print();
foreach(block_idx[i,j])
$display("block_idx[%0d][%0d] = %064h",i,j,block_idx[i][j]);
endfunction
endclass
2.
Cust_Type mem_pkg [4][2][]; //4个lane,2个channel,不定个idx
for(int lae = 0; lae < 4; lae ++) begin
for(int chl = 0; chl < 2; chl ++) begin
mem_pkg[lae][chl] = new[$urandom_range(10,128)]; // 动态数组的大小
end
end
foreach (mem_pkg[i,j,k]) begin // 多维度的foreach循环
mem_pkg[i][j][k] = new(); // mem_pkg class
assert(mem_pkg[i][j][k]).randomize());
end
-
>> << 流操作符
流操作符 ( >> 从左往右展开 << 从右往左展开 )
initial begin
int h;
bit [7:0] j[4] = '{8'ha,8'hb,8'hc,8'hd};
bit [7:0] q,w,e,r;
bit [7:0] k[4]; //非合并数组
bit [3:0][7:0] m;//合并数组
bit [7:0] dyna_a[];//动态数组
h = { >> bit [7:0] {j}}; // {j} = '{8'ha,8'hb,8'hc,8'hd} h = 32'h0a0b0c0d
{>> {q,w,e,r}} = j;
{q,w,e,r} = { >> {j}}; // 也可以
{>>{k}} = j; //正确
k = {>>{j}}; //错误,k是非合并数组
m = {>>{j}}; // m是合并数组
{>>{m}} = j;
{>> {dyna_a}} = j; //正确
dyna_a = {>> {j}}; //正确
{>>{dyna_a with [0:2]} = j;// with限制动态数组大小
end
initial begin
//动态数组,队列,定宽数组也可以操作
bit [7:0] data[];
bit [63:0] value = 64'h12345678_11223344;
data = {>> bit [7:0] {value}}; // data 为动态数组,此时不需要new()。
{>> {data}} = value; // 一些仿真器这样写也可以, value不需要加 {} 。
{>> {data}} = {<< {value}}; //也可以两边都使用流操作符
end
// 动态数组与 struct自定义类型转换
initial begin
bit [7:0] data[];
typedef sturct packed {
bit[31:4] rsv_31_4;
bit[3:3] num_3;
bit[2:2] num_2;
bit[1:1] num_1;
} CTRL_Type;
CTRL_Type data_s = 32'haaaa_1234;
data = {>> {data_s}};
end
-
automatic/static的method/data
//在module、program、interface、task和function之外声明的变量拥有静态的生命周期,即存在于整个仿真阶段
//automatic task内的变量默认是automatic类型
//class 中的task默认是automatic类型
//全局变量即伴随着程序执行开始到结束一直存在,例如module中的变量默认情况下全部为全局变量,用户也可理解为module中的变量由于在模拟硬件信号,所以它们是静态生命周期。
module test;
initial begin
for(int i=0;i<3;i++) begin
int a ; // static
a[i] = 1;
$display("a:%0b",i);
end
end
endmodule
a:1
a:11
a:111
module test;
initial begin
for(int i=0;i<3;i++) begin
automatic int a ; // automatic
a[i] = 1;
$display("a:%0b",i);
end
end
endmodule
a:1
a:10
a:100
关于automatic和static, 这些在C语言中解释的更到位:
-
post_randomize
- randomize产生不重复的value vcs -full64 -sverilog file.sv
- class new之后,分配一次内存,每次randomize,只对 rand 修饰的变量有效。
class c1;
rand int randnum;
int hist[$];
constraint cstr1 {randnum inside {[0:10]};};
constraint cstr2 {!(randnum inside {hist});};
function void post_randomize();
hist.push_back(randnum);
endfunction
endclass
module m1;
initial begin
c1 i1;
i1 = new();
repeat(10) begin
assert(i1.randomize());
$display("m1::proc2.i1 randnum %0d", i1.randnum);
end
end
endmodule
-
testbench的封装
- Testbench 是 module, 相当于硬件,里面有时钟的生产等模拟硬件。interface在tb之外,用于连接硬件DUT与软件验证环境
- 将一类相关的软件(parameter,data,type,task,function,class),可以通过package封装到一起,成为一个独立的命名空间
- library是编译的产物,可以容纳硬件和软件。
- UVM中软件的顶层是一个class::uvm_root,建立层次化关系的component。
- module中不能定义module,只能例化module。
- module中的wire可以直接连接到内部的例化module上,但是不能跨层级。
- assign 语句不能放入 initial begin end 语句块中。
- example:
module clock_gen( SysClk ); output SysClk; endmodule module dut_wrapper(); dut u_DUT( clk (tb_top.clock) ## 不可以将wire clock 直接连接,要通过tb_top层次化引用 ); endmodule module tb_top; wire clock; ## reg or wire ??? clock_gen u_clock_gen( SysClk(clock) ); dut_wrapper u_dut_wrapper(); endmodule