Systemverilog 语法相关

目录

 

简化数据

define RTL 层级路径

 paremeter 定义参数

typedef 构建数据结构

数据类型

定宽数组

合并数组(属于定宽数组)

动态数组

>> << 流操作符

automatic/static的method/data

post_randomize

testbench的封装


  •  

  • 简化数据

  • 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}
        };
 
多维动态数组
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;
    
    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}}; //错误,因为 q/w/e/r 是[7:0]的类型,非合并数组,实际占用32bit的存储单元,所以流操作符要放到左边   !!!和仿真器有关!!!
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中的变量由于在模拟硬件信号,所以它们是静态生命周期。
  • 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

猜你喜欢

转载自blog.csdn.net/Holden_Liu/article/details/104961039