mcdf_rgm_pkg——MCDF验证环境(3)

rgm_pkg的内容是每个寄存器都是一个单独的class,再加上一个顶层rgm继承于uvm_reg_block来对每一个寄存器做例化、配置、build,再将所有的reg加入到map中,做后门访问的配置。

首先是注册,域的声明,声明成随机变量rand uvm_reg_field slv_en;

然后写覆盖组covergroup value_cg;写明覆盖点以及位数;

new函数的参数要包含寄存器位数32和打开覆盖率的选项UVM_CVR_ALL;然后设置覆盖率选项,在has的时候例化覆盖组;

build函数是virtual的,做域的例化和配置,配置参数一共有9个,第一个是this,第二和第三个是位数,第四个是状态RW/RO,后面的五个参数固定为0初始值100。

最后是sample函数,参数是寄存器自己操作的trans——uvm_reg_bus_op中的两个data_t(data, byte_en)、bit is_read、uvm_reg_map map,一共四个参数,先写类型后写名,内容是调用super的后调用自定义的sample_values()函数;

sample_values()函数也调用super的,然后用if判断是否get了coverage,是的话就调用覆盖组的sample()采样函数。


slv_en_reg

第一个版本

覆盖组需要触发条件吗?域的位数怎么声明在覆盖组中?

(这里不需要;在覆盖点中域名.value[位数])

域的例化用new还是工厂?配置怎么写?

(用工厂,类型就是声明时的uvm_reg_field;域.configure(9个参数),reserved的属性是RO)

class slv_en_reg extends uvm_reg;
`uvm_object_utils(slv_en_reg)
rand uvm_reg_field slv_en;
rand uvm_reg_field reserved;

covergroup value_cg @(posedge clk iff rstn);
slv_en: coverpoint slv_en{ 
	type_option.weight=0;
	bins en={1};
	bins reserved={0};
	}

function new(32, UVM_CVR_ALL);
endfunction

virtual function void build();
	slv_en=
	slv_en.configure(this,3,0,"RW",0,'h0,1,0,0);
endfunction

function void sample(	uvm_reg_data_t data,
						uvm_reg_data_t byte_en,
						bit is_read,
						uvm_reg_map map);
	super.sample(data, byte_en, is_read, map);
	sample_values();
endfunction

function void sample_values();
	super.sample_values();
	if(get_coverage()) value_cg.sample();
endfunction

endclass: slv_en_reg

get_coverage()的参数是UVM_CVR_FIELD_VALS

第二个版本

class slv_en_reg extends uvm_reg;
`uvm_object_utils(slv_en_reg)
rand uvm_reg_field en;
rand uvm_reg_field reserved;

covergroup value_cg;
option.per_instance=1;
en:       coverpoint en.value[3:0];
reserved: coverpoint reserved.value[31:4];
endgroup

function new(string name="slv_en_reg");
	super.new(name, 32, UVM_CVR_ALL);
	void'(set_coverage(UVM_CVR_FIELD_VALS));
	if(has_coverage(UVM_CVR_FIELD_VALS)) begin
		value_cg=new(); end
endfunction

virtual function void build();
	en=uvm_reg_field::type_id::create("en");
	reserved=uvm_reg_field::type_id::create("reserved");
	en.configure(this,3,0,"RW",0,'h0,1,0,0);
	reserved.configure(this,31,4,"RO",0,'h0,1,0,0);	
endfunction

function void sample(	uvm_reg_data_t data,
						uvm_reg_data_t byte_en,
						bit is_read,
						uvm_reg_map map);
	super.sample(data, byte_en, is_read, map);
	sample_values();
endfunction

function void sample_values();
	super.sample_values();
	if(get_coverage(UVM_CVR_FIELD_VALS)) begin 
	value_cg.sample(); end
endfunction

endclass: slv_en_reg

parity_err_clr_reg

按照上面的模式写,覆盖组的例化是在new函数且条件是has cvr,sample_values函数是调用覆盖组的采样函数;

class parity_err_clr_reg extends uvm_reg;
`uvm_object_utils(parity_err_clr_reg)
rand uvm_reg_field parity_err_clr;
rand uvm_reg_field reserved;

covergroup value_cg;
option.per_instance=1;
parity_err_clr: coverpoint parity_err_clr.value[3:0];
reserved:       coverpoint reserved.value[31:4];
endgroup

function new(string name="parity_err_clr_reg");
	super.new(name, 32, UVM_CVR_ALL);
	void'(set_coverage(UVM_CVR_FIELD_VALS));
	if(has_coverage(UVM_CVR_FIELD_VALS)) begin
	value_cg=new(); end
endfunction

virtual function void build();
	parity_err_clr=uvm_reg_field::type_id::create("parity_err_clr");
	reserved=uvm_reg_field::type_id::create("reserved");
	parity_err_clr.configure(this,3,0,"RW",0,'h0,1,0,0);
	reserved.configure(this,31,4,"RO",0,'h0,1,0,0);
endfunction

function void sample(	uvm_reg_data_t data,
						uvm_reg_data_t byte_en,
						bit is_read,
						uvm_reg_map map);
	super.sample(data, byte_en, is_read, map);
	sample_values();
endfunction

function void sample_values();
	super.sample_values();
	if(get_coverage(UVM_CVR_FIELD_VALS)) begin
	value_cg.sample(); end
endfunction

endclass: parity_err_clr_reg

slv_id_reg

配置中的第二三个参数到底是不是表示位数?这个一次过了。

配置的第二个参数表示该域的总位数,所以都是8,第三个表示最低位,依次是24,16,8,0

class slv_id_reg extends uvm_reg;
`uvm_object_utils(slv_id_reg)
rand uvm_reg_field slv3_id;
rand uvm_reg_field slv2_id;
rand uvm_reg_field slv1_id;
rand uvm_reg_field slv0_id;

covergroup value_cg;
option.per_instance=1;
slv3_id: coverpoint slv3_id.value[31:24];
slv2_id: coverpoint slv2_id.value[23:16];
slv1_id: coverpoint slv1_id.value[15: 8];
slv0_id: coverpoint slv0_id.value[ 7: 0];
endgroup

function new(string name="slv_id_reg");
	super.new(name, 32, UVM_CVR_ALL);
	void'(set_coverage(UVM_CVR_FIELD_VALS));
	if(has_coverage(UVM_CVR_FIELD_VALS)) begin
	value_cg=new(); end
endfunction

virtual function void build();
	slv3_id=uvm_reg_field::type_id::create("slv3_id");
	slv2_id=uvm_reg_field::type_id::create("slv2_id");
	slv1_id=uvm_reg_field::type_id::create("slv1_id");
	slv0_id=uvm_reg_field::type_id::create("slv0_id");
	slv3_id.configure(this,31,24,"RW",0,'h3,1,0,0);
	slv2_id.configure(this,23,16,"RW",0,'h2,1,0,0);
	slv1_id.configure(this,15, 8,"RW",0,'h1,1,0,0);
	slv0_id.configure(this, 7, 0,"RW",0,'h0,1,0,0);
endfunction

function void sample(
      uvm_reg_data_t data,
      uvm_reg_data_t byte_en,
      bit            is_read,
      uvm_reg_map    map);
	super.sample(data, byte_en, is_read, map);
	sample_values();
endfunction

function void sample_values();
	super.sample_values();
	if(get_coverage(UVM_CVR_FIELD_VALS)) begin
	value_cg.sample(); end
endfunction

endclass: slv_id_reg

slv_len_reg

初始值全部为0,其他一模一样。

free_slot_reg

覆盖组要加option;

余量的初始值是'h20,为什么是32?

4个都一样。

parity_err_reg

初始值为0,其他同上

顶层环境rgm

顶层rgm继承于uvm_reg_block;

声明每一个reg为随机变量;同时声明map;

new函数不收集覆盖率;

build函数对每一个寄存器做例化(类型是那个reg)、配置(参数为this)、调用build;

为什么这里的配置的参数是this?

例化map,用的create_map(),参数是“map”,基地址0,总线宽度4(单位是byte,32位就是4byte),UVM_LITTLE_ENDIAN表示低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;

将所有的reg加入到map中,调用map的add_reg方法,参数是例化时的寄存器名,偏移地址,RO/RW;

后门访问:寄存器调用add_hdl_path_slice,参数是“???”,0,32;最后是add_hdl_path(“???”)和lock_model()

最后再定义两个函数:根据通道id获取域的长度和id,根据输入的ch选择对应reg中的field,调用get(),否则报错,最后返回fd;

第一个版本

class mcdf_rgm extends uvm_reg_block;
`uvm_object_utils(mcdf_rgm)
rand uvm_reg_field slv_en_reg;
rand uvm_reg_field parity_err_clr_reg;
rand uvm_reg_field slv_id_reg;
rand uvm_reg_field slv_len_reg;
rand uvm_reg_field slv0_free_slot_reg;
rand uvm_reg_field slv1_free_slot_reg;
rand uvm_reg_field slv2_free_slot_reg;
rand uvm_reg_field slv3_free_slot_reg;
rand uvm_reg_field slv0_parity_err_reg;
rand uvm_reg_field slv1_parity_err_reg;
rand uvm_reg_field slv2_parity_err_reg;
rand uvm_reg_field slv3_parity_err_reg;
uvm_reg_map map;

function new(string name="mcdf_rgm");
	super.new(name, 32, UVM_NO_CVR);
endfunction

virtual function void build();
	slv_en_reg=slv_en_reg::type_id::create("slv_en_reg");
	slv_en_reg.configure(this);
	slv_en_reg.build();
	parity_err_clr_reg=parity_err_clr_reg::type_id::create("parity_err_clr_reg");
	parity_err_clr_reg.configure(this);
	parity_err_clr_reg.build();
	slv_id_reg=slv_id_reg::type_id::create("slv_id_reg");
	slv_id_reg.configure(this);
	slv_id_reg.build();
	slv_len_reg=slv_len_reg::type_id::create("slv_len_reg");
	slv_len_reg.configure(this);
	slv_len_reg.build();
	slv0_free_slot_reg=slv0_free_slot_reg::type_id::create("slv0_free_slot_reg");
	slv0_free_slot_reg.configure(this);
	slv0_free_slot_reg.build();
	slv1_free_slot_reg=slv1_free_slot_reg::type_id::create("slv1_free_slot_reg");
	slv1_free_slot_reg.configure(this);
	slv1_free_slot_reg.build();
	slv2_free_slot_reg=slv2_free_slot_reg::type_id::create("slv2_free_slot_reg");
	slv2_free_slot_reg.configure(this);
	slv2_free_slot_reg.build();
	slv3_free_slot_reg=slv3_free_slot_reg::type_id::create("slv3_free_slot_reg");
	slv3_free_slot_reg.configure(this);
	slv3_free_slot_reg.build();
	slv0_parity_err_reg=slv0_parity_err_reg::type_id::create("slv0_parity_err_reg");
	slv0_parity_err_reg.configure(this);
	slv0_parity_err_reg.build();
	slv1_parity_err_reg=slv1_parity_err_reg::type_id::create("slv1_parity_err_reg");
	slv1_parity_err_reg.configure(this);
	slv1_parity_err_reg.build();
	slv2_parity_err_reg=slv2_parity_err_reg::type_id::create("slv2_parity_err_reg");
	slv2_parity_err_reg.configure(this);
	slv2_parity_err_reg.build();
	slv3_parity_err_reg=slv3_parity_err_reg::type_id::create("slv3_parity_err_reg");
	slv3_parity_err_reg.configure(this);
	slv3_parity_err_reg.build();
	//例化map
	map=create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
	map.add_reg("slv_en_reg", 'h0, "RW");
	map.add_reg("parity_err_clr_reg", 'h4, "RW");
	map.add_reg("slv_id_reg", 'h8, "RW");
	map.add_reg("slv_len_reg", 'hC, "RW");
	map.add_reg("slv0_free_slot_reg", 'h80, "RO");
	map.add_reg("slv1_free_slot_reg", 'h84, "RO");
	map.add_reg("slv2_free_slot_reg", 'h88, "RO");
	map.add_reg("slv3_free_slot_reg", 'h8C, "RO");
	map.add_reg("slv0_parity_err_reg", 'h90, "RO");
	map.add_reg("slv1_parity_err_reg", 'h94, "RO");
	map.add_reg("slv2_parity_err_reg", 'h98, "RO");
	map.add_reg("slv3_parity_err_reg", 'h9C, "RO");
	//后门访问
	slv_en_reg.add_hdl_path_slice("???", 0, 32);
	parity_err_clr_reg.add_hdl_path_slice("???", 0, 32);
	slv_id_reg.add_hdl_path_slice("???", 0, 32);
	slv_len_reg.add_hdl_path_slice("???", 0, 32);
	slv0_free_slot_reg.add_hdl_path_slice("???", 0, 32);
	slv1_free_slot_reg.add_hdl_path_slice("???", 0, 32);
	slv2_free_slot_reg.add_hdl_path_slice("???", 0, 32);
	slv3_free_slot_reg.add_hdl_path_slice("???", 0, 32);
	slv0_parity_err_reg.add_hdl_path_slice("???", 0, 32);
	slv1_parity_err_reg.add_hdl_path_slice("???", 0, 32);
	slv2_parity_err_reg.add_hdl_path_slice("???", 0, 32);
	slv3_parity_err_reg.add_hdl_path_slice("???", 0, 32);
	add_hdl_path("???");
	lock_model();
endfunction

function int get_ch_field_len(int ch);
	int fl;
	case(ch)
	0:fl=slv_len_reg.slv0_len.get();
	1:fl=slv_len_reg.slv1_len.get();
	2:fl=slv_len_reg.slv2_len.get();
	3:fl=slv_len_reg.slv3_len.get();
	default: $error("get_ch_field_len error!");
	return fl;
endfunction
	
function int get_ch_field_id(int ch);
	int fd;
	case(ch)
	0:fd=slv_id_reg.slv0_id.get();
	1:fd=slv_id_reg.slv1_id.get();
	2:fd=slv_id_reg.slv2_id.get();
	3:fd=slv_id_reg.slv3_id.get();
	default: $error("get_ch_field_id error!");
	return fd;
endfunction

endclass: mcdf_rgm

声明寄存器的时候是直接寄存器+新的名称;试试不加新名称怎么样,等下编译看看。

new函数不需要加位数了;

添加寄存器,reg不需要加引号,偏移地址要标明32位数,

报错要用uvm的消息机制;   


 注册的名称写错

寄存器声明的时候还是要有新的名称,解答上面的问题了。

然后是少了个endcase;

sample函数由于是继承于父类uvm_reg,参数必须是data,byte_en这个顺序,修改就好了;

顶层的new不收集覆盖率是UVM_NO_COVERAGE;

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值