《UVM实战》学习笔记——第七章 UVM中的寄存器模型2——期望值/镜像值、自动/显示预测、操作方式


前言

2023.4.24 寄存器模型学起来感觉好难,没太理解,主要是还没有实际使用,理论知识学起来枯燥


一、寄存器模型对DUT的模拟

1.1 期望值和镜像值

  • 镜像值mirrored value,表示当前硬件状态的已知值。镜像值往往由模型预测给出,即在前门访问时通过观察总线或在后门访问时通过自动预测等方式来给出镜像值。镜像值有可能与硬件实际值(actual value)不一致,无法保持同步更新。

  • 期望值desired value,先利用寄存器模型修改软件对象值,而后利用该值更新硬件值。

  • mirrored value与desired value是寄存器模型的属性,而actual value对应硬件的真实数值。

  • 对于存储器,并不存在期望值和镜像值。

class case0_cfg_vseq extends uvm_sequence;
	virtual task body();
		p_sequencer.p_rm.invert.set(16'h1);  //设置期望值
		value = p_sequencer.p_rm.invert.get();  //get函数去获得期望值
		value = p_sequencer.p_rm.invert.get_mirrored_value();  //得到镜像值
		
		p_sequencer.p_rm.invert.update(status, UVM_FRONTDOOR);  
		//update函数会去检查两者是否一致,不一样,会把期望值写入DUT,同时更新镜像值
	...
endclass

1.2 常见操作对期望值和镜像值的影响

在这里插入图片描述

read/write/peek/poke:read先去读DUT,再去更新期望值和镜像值,write写DUT,同时写期望值和镜像值
set:写期望值
get:得到期望值
get_mirrored_value:得到镜像值
reset:期望值和镜像值均复位
predict:两者都更新
mirror:读DUT,去更新镜像值
update:检查是否一致,不一致会去更新镜像值,使其和期望值相同
randomize:随机化后,期望值会改变,镜像值不改变。但不是所有寄存器模型都支持此函数,此外可以在configure函数的第八个参数关闭随机化功能。

一般randomize和update配合使用,上电复位后,先随机化,再update去配置DUT。

二、prediction分类

左边是自动预测,右边是显示预测
在这里插入图片描述

2.1 自动预测

auto prediction:没有predictor和monitor的情况下,利用寄存器的操作来自动记录每次寄存器的读写数值并在后台自动调用predict()方法

  • 后门访问的时候只能自动预测uvm_reg_map::set_auto_predict()
  • 如果出现其它一些sequence直接在总线层面上对寄存器进行操作(跳过寄存器级别的write()/read()操作)或通过其它总线访问寄存器等额外情况,都无法自动得到寄存器的镜像值和预期值。

2.2 显式预测

explicit:更加可靠的方式是在物理总线上通过monitor捕捉总线事务,并将捕捉到的事务传递给外部例化的predictor,再利用adapter的桥接方法实现事务信息转换,并将转化后的寄存器模型有关信息更新到map中。

  • 显式预测对寄存器数值预测更为准确
class base_test extends uvm_test;
	reg_model rm; //寄存器模型
	my_adapter reg_sqr_adapter;
	my_adapter mon_reg_adapter;  //adapter是object类
	uvm_reg_predictor #(bus_transaction) reg_predictor;  //predictor是组件类,参数类,声明要传递的transaction类型
	...
endclass

function void base_test::build_phase (uvm_phase phase) ;
	rm = reg_model::type_id::create ( "rm", this) ;
	rm.configure ( null, "");
	rm.build ( ) ;
	rm.lock_model ( );
	rm.reset ( ) ;
	reg_sqr_adapter = new ( "reg_sqr_adapter" ) ;
	mon_reg_adapter = new ( "mon_reg_adapter" ) ;
	reg_predictor = new ( "reg_predictor", this) ;
	env.p_rm = this.rm;
endfunction

function void base_test::connect_phase (uvm_phase phase) ;
	rm.default_map.set_sequencer (env.bus_agt.sqr,reg_sqr_adapter);  //连接sequencer和adapter
	rm.default_map.set_auto_predict (0);  //此处设置为0的话,就会关闭右图虚线更新寄存器模型的路径  
	reg_predictor.map = rm.default_map;  
	reg_predictor.adapter = mon_reg_adapter;
	env.bus_agt.ap.connect (reg_predictor.bus_in) ;
endfunction

在connect_phase中,需要将reg_predictor和bus_agt的ap口连接在一起,并设置reg_predictor的adapter和map。只有设置了map后,才能将predictor和寄存器模型关联在一起。
(在集成的过程中需要将adapter与map的句柄也一并传递给predictor,同时将monitor采集的事务通过analysis port接入到predictor一侧。)

三、访问寄存器方式

1、uvm_reg_blockuvm_reguvm_reg_field三个类提供用于访问寄存器的方法:
在这里插入图片描述

  • mirror():读取actual value去更新mirrored value,前门后门都可以,还可以检查
  • update():先set修改软件的值,然后再去修改硬件actual value,最后总线获得数据去更新mirrored value。最后三个数据都是一样的。(这个两个函数前门后门访问都可以使用,但是不能对寄存器域进行操作)
  • set():set的是desired value,是软件的值,不是硬件实际值。set之后的操作是update,因为两侧的值不相同了。
  • get():get的是desired value,是软件的值,不是硬件实际值
  • reset():复位block/reg/field的期望值和镜像值
  • get_reset():得到reg/field的复位值

mirror和read对比:

  • 相同:都可以进行前门或后门访问
  • 不同:mirror不会返回读取的值,但是会把镜像值进行修改;mirror前门访问可以进行block级别操作

randomize、set和update配合使用模拟场景:
先随机化寄存器的值,再去设置某些特定的值,最后再根据这些值去配置寄存器,相比较于write和read来说,这样做可以模拟更多的场景。

void'(rgm.chnl0_ctrl_reg.randomize());
rgm.chnl0_ctrl_reg.pkt_len.set('h3);
rgm.chnl0_ctrl_reg.update(status, UVM_FRONTDOOR, .parent(this));

void'(rgm.chnl1_ctrl_reg.randomize());
rgm.chnl1_ctrl_reg.set('h22);
rgm.update(status, UVM_FRONTDOOR, .parent(this));

2、uvm_reg_sequence的访问方式:针对寄存器对象reg的,不是寄存器块或寄存器域
在这里插入图片描述

  • 对于前门访问的read()和write(),在总线事务完成时镜像值和期望值才会更新为与总线上相同的值,这种预测方式是显式预测
  • peek()和poke()及后门访问模式下的read()和write(),由于不通过总线,默认采取自动预测的方式,故在零时刻方法调用返回后镜像值和期望值也相应修改
  • 复位操作:捕捉到硬件进行复位时,需要把验证平台的寄存器模型进行复位。
    复位后,可以读取复位值,并与后门访问获得的寄存器复位值进行比较,来判断复位是否成功。
@(negedge p_sequencer.vif.rstn);
rgm.reset();	 
rgm.chnl0_ctrl_reg.reset();		
rgm.chnl0_ctrl_reg.pkt_len.reset();		

//检查复位是否成功
rstval = rgm.chnl0_ctrl_reg.get_reset();  //得到复位值只能在reg/field层次
rgm.chnl0_ctrl_reg.read(status, data, UVM_BACKDOOR, .parent(this));
if(rstval != data)
	`uvm_error("RSTERR", "reset value read is not the desired reset value")

四、mem和reg的联系和差别

UVM寄存器模型也可以对存储建模。可以模拟RW、RO、WO类型的存储,而且可以配置存储模型的数据宽度和地址范围。

  • 一旦映射,会带来很大的资源消耗,因此就不支持预测和影子存储功能(shadow storage),没有镜像值和期望值
  • 利用自带的方法去访问硬件存储。利用模型的地址范围去测试硬件的地址范围是否全部覆盖。
  • 提供前门和后门访问,可以先后门写,前门读(以前是系统函数或者仿真器)
  • 除了有read/write/peek/poke之外,还有burst_readburst_write函数连续传输,传进去的是数组形式,传递多个数据。
  • 如果需要实现更多的协议配置要去,建议在总线UVC层面去驱动

五、内建built_in sequence

UVM自带的一些sequence,可以在项目初期对寄存器模型进行验证,为后期各个功能点验证打下基础

5.1 寄存器模型内建序列

在这里插入图片描述

5.2 存储器模型内建序列

在这里插入图片描述

5.3 禁止域名

对一些寄存器,如果想将其排除在某些内建序列测试范围之外,可额外添加上面列表中提到的“禁止域名”。由于uvm_reg_block和uvm_reg都是uvm_object类而不是uvm_component类,所以可以使用uvm_resource_db来配置“禁止域名”。

class mcdf_rgm extends uvm_reg_block;
	...
	virtual function build();
		...
		//disable build-in seq attributes
		uvm_resourcr_db #(bit)::set({"REG::", this.chnl0_stat_reg.get_full_name()}, "NO_REG_ACCESS_TEST", 1);
		uvm_resourcr_db #(bit)::set({"REG::", this.chnl1_stat_reg.get_full_name()}, "NO_REG_ACCESS_TEST", 1);
		uvm_resourcr_db #(bit)::set({"REG::", this.chnl2_stat_reg.get_full_name()}, "NO_REG_ACCESS_TEST", 1);
	endfunction
endclass

六、寄存器模型的应用场景

  • 检查寄存器,以及协助检查硬件设计逻辑和比对数据
  • 在对硬件数据通路做数据比对时,需及时知道当时的硬件配置状况,而利用寄存器模型的镜像值可实现实时读取,不需要从前门访问。
  • 寄存器模型不但可以用来检查硬件寄存器,也可用来配合scoreboard实时检查DUT的功能。

七、检查寄存器的方式

  • 从前门写,并且从前门读。这种方式最为常见,但是无法检查地址是否正确映射。而前门与后门混合操作的方式可以保证地址的映射检查
  • 从前门写再从后门读。利用write()实现前门写,再用read()或peek()从后门读。
  • 从后门写再从前门读。利用write()或poke()实现后门写,再用read()从前门读。
  • 对一些状态寄存器(硬件自身信号会驱动更新其实际值),先用peek()获取(并且会调用predict()方法更新镜像值),再调用mirror()方法从前门访问并且与之前更新的镜像值比较。

八、覆盖率收集

在验证前期可以不例化covergroup保证更好的资源利用;在验证后期需采集功能覆盖率时再考虑例化、使能采样。

  • read/write函数会自动调用回调函数sample,进行自动采样数据。sample又会调用sample_values函数,再去调用covergroup
  • sample_values函数是供外部调用的函数,在发生特定事件的触发时,如中断、复位等,可以在外部通过监听具体事件来调用该方法
  • 采样的时候会采集所有的域的值,但有些是没用的。希望可以采用自定义的形式,限定感兴趣的域和采样事件。
class ctrl_reg extends uvm_reg;
	`uvm_object_utils(ctrl_reg)
	uvm_reg_field reserved;
	rand uvm_reg_field pkt_len;
	rand uvm_reg_field prio_level;
	rand uvm_reg_field chnl_en;
	
	covergroup value_cg;
		option.per_instance = 1;
		reserved: coverpoint reserved.value[25:0];
		pkt_len: coverpoint pkt_len.value[2:0];
		prio_level: coverpoint prio_level.value[1:0];
		chnl_en: coverpoint chnl_en.value[0:0];
	endgroup
	
	function new(string name="ctrl_reg");
		super.new(name, 32, UVM_CVR_ALL);  //包含所有的覆盖率类型
		set_coverage(UVM_CVR_FIELD_VALS);
		if(has_coverage(UVM_CVR_FIELD_VALS)) begin   //是否具备对应的covergroup,有就例化group
			value_cg = new();
		end
	endfunction
	
	virtual function build();
		reserved = uvm_reg_field::type_id::create("reserved");
		pkt_len = uvm_reg_field::type_id::create("pkt_len");
		prio_level = uvm_reg_field::type_id::create("prio_level");
		chnl_en = uvm_reg_field::type_id::create("chnl_en");
		reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0, 0);
		pkt_len.configure(this, 3, 3, "RW", 0, 3'h0, 1, 1, 0);
		prio_level.configure(this, 2, 1, "RW", 0, 2'h3, 1, 1, 0);
		chnl_en.configure(this, 1, 0, "RW", 0, 1'h0, 1, 1, 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   //是否允许使用对应的covergroup进行采样
			value_cg.sample();
		end
	endfunction
endclass
  • 7
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UVM寄存器模型镜像和DUT(Design Under Test)的实际不一致时,可以按照以下步骤解决问题: 1. 检查寄存器模型的配置:确保寄存器模型的配置与DUT的规范一致。检查寄存器模型寄存器的位宽、地址映射等是否正确。 2. 检查测试环境的设置:确认测试环境的时钟、复位信号以及其他相关信号是否正确连接,并且与DUT一致。确保寄存器访问时序和时钟同步是正确的。 3. 检查寄存器访问顺序:验证寄存器访问的顺序是否正确。在UVM,通常使用sequences来定义寄存器访问顺序,确保sequences按照正确的顺序访问寄存器。 4. 检查寄存器读写操作:确认寄存器读写操作的正确性。检查读写接口是否正确连接,确保在正确的时机进行读写操作。 5. 检查DUT的功能实现:如果以上步骤都没有问题,那么可能是DUT本身的功能实现有问题。可以通过添加临时信号、打印调试信息等方式来定位问题,并进行修复。 6. 调试和排查:如果问题仍然存在,可以使用调试工具来观察和分析寄存器访问的过程,以便找到问题所在。可以使用波形查看器、日志输出等工具来帮助定位问题。 总之,当UVM寄存器模型镜像和DUT实际不一致时,需要仔细检查寄存器模型的配置、测试环境的设置、寄存器访问顺序、寄存器读写操作以及DUT的功能实现等方面,以确定问题的原因并进行修复。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值