寄存器访问方法
在没有寄存器模型
之前,只能启动 sequence 通过前门(FRONTDOOR)访问的方式来读取寄存器,局限较大,在 scoreboard(或者其他 component )中难以控制。而有了寄存器模型之后,scoreboard 只与寄存器模型打交道,无论是发送读的指令还是获取读操作的返回值,都可以由寄存器模型完成。
有了寄存器模型
后,可以在任何耗费时间的phase中使用寄存器模型以前门访问或后门(BACKDOOR)访问的方式来读取寄存器的值,同时还能在某些不耗费时间的 phase(如 check_phase)中使用后门访问的方式来读取寄存器的值。
task my_model::main_phase(uvm_phase phase); … reg_model.version.read(status, value, UVM_FRONTDOOR); reg_model.version.write(status, value, UVM_FRONTDOOR); … endtask
利用寄存器模型可以更方便的对寄存器进行操作。两种访问寄存器的方式是前门访问(front-door)和后门访问(back-door)。
前门访问:
在寄存器模型上做的读写操作,通过总线SPI实现总线上的物理时序访问,是真实的物理操作
;
后门访问:指利用UVM DPI(uvm_hdl_read()、uvm_hdl_deposit()),将寄存器的操作直接作用到DUT内的寄存器变量,而不通过物理总线访问。
1.1.前门访问
- 下面的sequence,继承于uvm_reg_sequence。uvm_reg_sequence除了具备一般的预定义方法之外,还具有与寄存器相关的方法。
1)、第一种即uvm_reg::read( )/write( )。在传递时,用户注意将参数path指定为UVM_FRONTDOOR。uvm_reg::read()/write()方法传入的参数较多,除了status和value两个参数需传入
,其他参数若不指定,可采用默认值。
regmodel.register.write(status,value,UVM_FRONTDOOR,.parent(this)); //regmodel——寄存器模型实例名; register——寄存器实例名
regmodel.register.read(status,value,UVM_FRONTDOOR,.parent(this));
2)、第一种即uvm_reg_sequence::read_reg( )/write_reg( )。传递时,path指定为UVM_FRONTDOOR。
write_reg(regmodel.register,status,value,UVM_FRONTDOOR); read_reg(regmodel.register,status,value,UVM_FRONTDOOR); class apb_spi_seq extends uvm_reg_sequence; reg_block_rgm rgm; `uvm_object_utils(apb_spi_seq) //注册类 `uvm_declare_p_sequencer(apb_spi_sequencer) //创建p_sequencer变量,操作virtual sequence内容 ... task body(); uvm_status_e status; uvm_reg_data_t data; if(!uvm_config_db#(reg_block_rgm)::get(null,get_full_name(),"rgm",rgm))begin `uvm_error("GETRGM","no top-down RGM handle is assigned") end rgm.ctrl.read(status,data,UVM_FRONTDOOR,.parent(this)); //1. 寄存器模型提供的方法read()/write() rgm.ctrl.write(status,'h11,UVM_FRONTDOOR,.parent(this)); rgm.ctrl.read(status,data,UVM_FRONTDOOR,.parent(this));
<span class="token function">read_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>data<span class="token punctuation">,</span>UVM_FRONTDOOR<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//2. uvm_reg_sequence预定义方法read_reg()/write_reg() </span> <span class="token function">write_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>'h22<span class="token punctuation">,</span>UVM_FRONTDOOR<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">read_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>data<span class="token punctuation">,</span>UVM_FRONTDOOR<span class="token punctuation">)</span><span class="token punctuation">;</span>
endtask
endclass
1.2. 后门访问
1.2.1.访问前的地址映射
在进行后门访问时,首先要确保寄存器模型在建立时将各个寄存器映射到了DUT一侧的HDL路径
。下面的代码即实现了寄存器模型与DUT各个寄存器的路径映射。
- 通过uvm_reg_block::add_hdl_path函数将寄存器模型关联到DUT一端;
- 通过uvm_reg::add_hdl_path_slice函数将寄存器模型中的各个寄存器成员与HDL一侧的地址进行映射。
- 寄存器模型build()函数最后以lock_model函数结尾,结束地址映射关系。
calss reg_block_rgm extends uvm_reg_block; ...//寄存器成员和map声明 virtual function build(); ...//寄存器成员和map创建 add_hdl_path("reg_backdoor_access.dut"); //1.通过add_hdl_path()将寄存器模型关联到DUT一段 ctrl.add_hdl_path_slice("CHAR_LEN",0,7); //2. 各个参数含义有待确认 ss.add_hdl_path_slice("CHAR_LEN",0,32); lock.model(); //3. 结束映射关系 endfunction endclass
1.2.2.后门访问
在在寄存器模型完成了HDL路径映射后,便可以同前门访问一样,利用相关的函数方法进行后门访问。访问方式多样化。下面的sequence,继承于uvm_reg_sequence。uvm_reg_sequence除了具备一般的预定义方法之外,还具有与寄存器相关的方法。
1)、uvm_reg::read( )/write( )。在传递时,用户注意将参数path指定为UVM_BACKDOOR。
regmodel.register.write(status,value,UVM_BACKDOOR,.parent(this)); //regmodel——寄存器模型实例名; register——寄存器实例名 regmodel.register.read(status,value,UVM_BACKDOOR,.parent(this));
2)、uvm_reg_sequence::read_reg( )/write_reg( )。传递时,将参数path指定为UVM_BACKDOOR。
write_reg(regmodel.register,status,value,UVM_BACKDOOR);
read_reg(regmodel.register,status,value,UVM_BACKDOOR);
3)、此外,uvm_reg::peek( )/poke( ),也分别对应了读取寄存器(peek)和修改寄存器(poke)两种操作,用户无需指定UVM_BACKDOOR,这两种方法只针对后门访问。
regmodel.register.poke(status,value,.parent(this)); //regmodel——寄存器模型实例名; register——寄存器实例名 regmodel.register.peek(status,value,.parent(this)); poke_reg(regmodel.register,status,value); peek_reg(regmodel.register,status,value); class apb_spi_seq extends uvm_reg_sequence; reg_block_rgm rgm; `uvm_object_utils(apb_spi_seq) //注册类 `uvm_declare_p_sequencer(apb_spi_sequencer) //创建p_sequencer变量,操作virtual sequence内容 ... task body(); uvm_status_e status; uvm_reg_data_t data; if(!uvm_config_db#(reg_block_rgm)::get(null,get_full_name(),"rgm",rgm))begin `uvm_error("GETRGM","no top-down RGM handle is assigned") end rgm.ctrl.read(status,data,UVM_BACKDOOR,.parent(this)); //1. 寄存器模型提供的方法read()/write() rgm.ctrl.write(status,'h11,UVM_BACKDOOR,.parent(this)); rgm.ctrl.read(status,data,UVM_BACKDOOR,.parent(this));
<span class="token function">read_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>data<span class="token punctuation">,</span>UVM_FRONTDOOR<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//2. uvm_reg_sequence预定义方法read_reg()/write_reg() </span> <span class="token function">write_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>'h22<span class="token punctuation">,</span>UVM_FRONTDOOR<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">read_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>data<span class="token punctuation">,</span>UVM_FRONTDOOR<span class="token punctuation">)</span><span class="token punctuation">;</span> rgm<span class="token punctuation">.</span>ctrl<span class="token punctuation">.</span><span class="token function">peek</span><span class="token punctuation">(</span>status<span class="token punctuation">,</span>data<span class="token punctuation">,</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//3. 寄存器模型提供的方法read()/write()</span> rgm<span class="token punctuation">.</span>ctrl<span class="token punctuation">.</span><span class="token function">poke</span><span class="token punctuation">(</span>status<span class="token punctuation">,</span>'h22<span class="token punctuation">,</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> rgm<span class="token punctuation">.</span>ctrl<span class="token punctuation">.</span><span class="token function">peek</span><span class="token punctuation">(</span>status<span class="token punctuation">,</span>data<span class="token punctuation">,</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">peek_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//2. uvm_reg_sequence预定义方法read_reg()/write_reg() </span> <span class="token function">poke_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>'h33<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">peek_reg</span><span class="token punctuation">(</span>rgm<span class="token punctuation">.</span>ss<span class="token punctuation">,</span>status<span class="token punctuation">,</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
endtask
endclass
1.3.前/后门访问的比较
下图直观看出前门访问需要adapter。
前门访问 | 后门访问 |
---|---|
通过总线协议访问比较耗时,且在总线访问结束时才能结束前门访问 | 1. 通关UVM DPI关联硬件寄存器的信号路径(层次化引用),直接读取或修改 硬件寄存器变量,不消耗访问时间,零时刻响应 |
一般读写只能按字(word)读写,无法直接读写寄存器域 | 2. 可以对寄存器或者寄存器域直接做读写 |
依靠监测总线来对寄存器模型内容做预测 | 3. 依靠auto prediction方式自动对寄存器内容做预测 |
正确反映了时序关系 | 4. 不受硬件时序控制,对硬件做的后门访问可能发生时序冲突 |
不受总线时序功能影响 | 5. 通过总线协议,可以有效地捕捉总线错误,继而验证总线的访问路径 |
后门访问较前门访问更便捷,更快一些。但是实际上,为了验证寄存器的完备性,通常采用对寄存器模型的前门访问与后门访问的混合方式。
- 通过前门访问,先验证寄存器访问的物理通路正常工作,并且有专门的寄存器测试的前门访问序列来遍历所有的寄存器。在前门访问被充分验证的前提下,可在后续的测试中使用后门访问来节省访问多个寄存器的时间。
- 寄存器随机设置的精髓不在于随机可设置的域值,而是为了考虑日常不可预期的场景,先通过后门访问随机化整个寄存器列表(在一定的随机限制下),随后再通过前门访问来配置寄存器。这么做的
好处在于
,不再只是通过设置复位之后的寄存器这种更有确定性的场景,而是通过让测试序列一开始的寄存器值都随机化来模拟无法预期的硬件配置前场景,而在稍后设置了必要的寄存器之后,再来看是否会有意想不到的边界情况发生。
寄存器模型相关类的访问方法:
寄存器序列提供的寄存器访问方法:
二、两种跟踪寄存器值的方法——prediction
寄存器模型中的每一个寄存器成员都有两个值:一个是镜像值(mirrored value),一个是期望值(desireed value)。
镜像值(mirrored value):表示当前硬件的已知状态。镜像值往往有模型预测给出。
期望值(desireed value):先利用寄存器模型修改软件对象值,而后利用该值更新硬件值。
在应用寄存器模型时,除了利用它的寄存器信息外,还可以利用它来跟踪寄存器的值,这么做的目的有二:一是建立镜像值(mirrored value),二是建立期望值(desireed value)。然而镜像值有可能与硬件实际值(hardware actual value)不一致,例如状态寄存器的镜像值则无法保持与硬件实际值保持同步更新。
需要说明的是,mirrored value与desireed value是寄存器模型的属性,而actual value是硬件的真实数值。
UVM提供了两种跟踪寄存器值得方法,分别是自动预测(auto prediction)和显式预测(explicit)。两种预测方式的显著差别在于:显式预测对寄存器数值预测更准确。
自动(隐式)预测(auto prediction)
如果用户并没有集成独立的predictor在环境中,而是利用寄存器的操作来自动记录每一次寄存器的读写数值,并在后台自动调用predict()方法的话,这种方式被称之为自动预测。通过自动预测的方式获取寄存器的值需要调用函数uvm_reg_map::set_auto_predict(1)。详情参考UVM——RAL模型之一3.3.部分,如下。
rgm.build(); //1.显示调用build()函数,创建UVM寄存器层次
rgm.default_map.set_auto_predict(1); //2. 自动隐式预测寄存器的属性值
auto prediction 的不足之处:对于sequence 直接在总线层面上对寄存器操作(不用ral model 的write/read task)无法自动得到register的的mirror value 和期望值。
显式预测
显式预测可以弥补上述缺陷,默认情况下,系统将采用显式预测的方式。显式预测在物理总线上通过监视器来捕捉总线事务,并将捕捉到的事务传递给外部例化的predictor(预测器)。再利用adapter的桥接方法,实现事务信息转换,然后手动调用该寄存器的predict()方法直接更新镜像值,将转化后的寄存器模型有关信息更新到map中。
该predictor由UVM参数化类uvm_reg_predictor例化并集成在顶层环境中。集成的过程中,需要将adapter与map的句柄也传给predictor;
将monitor采集好的事务通过analysis port接入到predictor一侧将monitor采集好的事务通过analysis port接入到predictor一侧。monitor一旦捕捉到有效事务,会发送给predicotr。
调用函数uvm_reg_map::set_auto_predict(0) 进行显式预测,在调用predict()函数更新镜像值,不需要观察实际的物理变化。
参考:
https://blog.csdn.net/weixin_46022434/article/details/105857784
https://blog.csdn.net/weixin_43830240/article/details/111304028