0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

UVM寄存器模型的常规方法有哪些呢?

jf_GctfwYN7 来源:IC修真院 2023-11-25 09:27 次阅读

寄存器模型的常规方法

mirrored、 desired 和 actual value

在应用寄存器模型时, 除了利用它的寄存器信息, 还可以利用它来跟踪寄存器的值。

跟踪寄存器的值, 一方面是建立 mirrored value, 另一方面是为建立 desired value。

寄存器模型中的每一个寄存器都应该有两个值,一个是镜像值(mirrored value),一个是期望值 (desired value) 。期望值是先利用寄存器模型修改软件对象值, 而后利用该值更新硬件值;镜像值是表示当前硬件的已知状态值。镜像值往往由模型预测给出,关于预测,在前门访问时通过观察总线或在后门访问时通过自动预测等方式来给出镜像值。

然而,镜像值有可能与硬件实际值 (hardware actual value)不一致,例如状态寄存器的镜像值就无法与硬件实际值保持同步更新。另外, 如果其他访问寄存器的通路修改了寄存器, 那么可能由于那一路总线没有被监测, 导致寄存器的镜像值未得到及时更新。

prediction的分类

UVM 提供了两种用来跟踪寄存器值的方式, 我们将其分为自动预测 (auto prediction)和显式预测 (explicit)。如果读者想使用自动预测的方式,还需要调用函数 uvm_reg_map: :set_auto_predict () 。两种预测方式的显著差别在于, 显式预测对寄存器数值预测更为准确, 我们可以通过下面对两种模式的分析得出具体原因。

自动预测 (auto prediction) :如果读者没有在环境中集成独立的 predictor, 而是利用寄存器的操作来自动记录每一次寄存器的读写数值, 并在后台自动调用 predict()方法的话, 则这种方式称为自动预测。这种方式简单有效, 然而需要注意, 如果出现其他一些sequence 直接在总线层面上,对寄存器进行操作(跳过寄存器级别的 write()/read()操作), 或通过其他总线来访问寄存器等这些额外的情况, 都无法自动得到寄存器的镜像值和预期值。

显式预测 (explicit prediction):更为可靠的一种方式是在物理总线上通过监视器来捕捉总线事务, 并将捕捉到的事务传递给外部例化的 predictor (预测器),该 predictor 由 UVM 参数化类 uvm_reg_predictor 例化并集成在顶层环境中。 如下图, 在集成的过程中需要将 adapter 与 map 的句柄也一并传递给 predictor, 同时将 monitor 采集的事务通过 analysis port 接入到 predictor一侧。这种集成关系可以使得 monitor一旦捕捉到有效事务, 会发送给 predictor, 再由其利用adapter 的桥接方法, 实现事务信息转换, 并将转化后的寄存器模型有关信息更新到 map 中。默认情况下,系统将采用显式预测的方式, 这就要求集成到环境中的总线 UVC monitor 需要具备捕捉事务 的功能和对应的 analysis port, 以便于同 predictor 连接。

782c4978-8ab5-11ee-939d-92fbcf53809c.png

关于 predictor 在顶层环境中的集成, 读者可以通过下面的一段例码片段来掌握集成时的几个要素:

class mcdf_bus_env extends uvm_env;
mcdf_bus_agent agent;
mcdf_rgm rgm; 
reg2mcdf_adapter reg2mcdf; 
uvm_reg_predictor #(mcdf_bus_trans) mcdf2reg_predictor; 
`uvm_component_utils(mcdf_bus_env)
...
function void build_phase(uvm_phase phase); 
agent=mcdf_bus_agent::create("agent", this); 
if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
`uvm_info("GETRGM", "no top-down RGM handle is assigned", UVM_LOW) 
rgm = mcdf_rgm::create("rgm", this); 
`uvm_info("NEWRGM", "created rgm instance locally", UVM_LOW)
end 
rgm. build() ; 
reg2mcdf = reg2mcdf_adapter::create("reg2mcdf"); 
mcdf2reg_predictor = uvm_reg_predictor#(mcdf_bus_trans)::type_ id: : create ("mcdf2reg_predcitor", this); 
mcdf2reg_predictor.map = rgm.map; 
mcdf2reg_predictor.adapter = reg2mcdf; 
endfunction 
function void connect_phase(uvm_phase phase);
rgm.map.set_sequencer(agent.sequencer, reg2mcdf); 
agent.monitor.ap.connect(mcdf2reg_predictor.bus_in);
endfunction 
endclass

uvm_reg的访问方法

在给出寄存器模型的常见应用模式之前,首先从下表中更全面地了解uvm_reg_ block、 uvm_reg 和uvm_reg_ field 三个类提供的用于访问寄存器的方法。

7841c9d8-8ab5-11ee-939d-92fbcf53809c.png

uvm_reg_ sequence 提供的方法(均是针对寄存器对象的, 而不是寄存器块或寄存器域)如下表。

7860b028-8ab5-11ee-939d-92fbcf53809c.png

结合mirrored value、 desired value 和 actual value, 我们需要理解这4种方法在调用时, 三种数值的变化时序关系:

• 对于前门访问的 read()和 write(),在总线事务完成时, 镜像值和期望值才会更新为与总线上相同的值,这种预测方式是显式预测

对于 peek()和 poke(), 以及后门访问模式下的 read()和 write(),由于不通过总线,默认采取自动预测的方式,因此在方法调用返回后,镜像值和期望值也相应修改。

关于 reset()和 get_reset()的用法, 下面也给出部分例码。例如硬件在复位触发时, 会将内部寄存器值复位, 而寄存器模型在捕捉到复位事件时, 为了保持同硬件行为一致, 也应当对其复位。这里注意的是, 复位的对象是寄存器模型, 而不是硬件。

@(negedge p_sequencer.vif.rstn);

rgm. reset(); / / register block reset for mirrored value and desired value

rgm.chnl0_ctrl_reg.reset(); // register level reset

rgm.chnl0_ctrl_reg.pkt_len.reset(); // register field reset

在复位之后, 用户也可以通过读取寄存器模型的复位值(与寄存器描述文件一致), 与前门访问获取的寄存器复位值进行比较, 以此判断硬件各个寄存器的复位值是否按照寄存器描述去实现。这里的 get_reset()方法指的也是寄存器模型的复位值, 而不是硬件。

// register model reset value get and check

rstval = rgm.chnl0_ctrl_reg. get_reset() ;

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")

mirror()方法与 read()方法类似, 也可以选择前门访问或后门访问, 不同的是, mirror()不会返回读回的数值, 但是会将对应的镜像值修改。在修改镜像值之前, 用户还可以选择是否将读回的值与模型中的原镜像值进行比较。下面的例码在更新镜像值之前, 首先将读回的值与上一次镜像值做了比对, 随后再更新镜像值。比如, 对于配置寄存器, 可以采用这种方法来检查上一次的配置是否生效, 又或者对于状态寄存器可以选择只更新镜像值不做比较, 这是因为状态寄存器随时可能被硬件内部逻辑修改。

// get register value and check

rgm.chnl0_ctrl_reg.mirror(status, UVM_CHECK, UVM_FRONTDOOR,parent(this));

下面的方法是运用 set()和 update()对寄存器做批量修改。首先 set()方法的对象是寄存器模型自身,通过set()可以修改期望值, 而在寄存器配置时不妨先对其模型随机化,再配置个别寄存器或域, 当寄存器的期望值与镜像值不相同时,可以通过update()方法来将不相同的寄存器通过前门访问或后门访问的方式做全部修改

这种 set()和 update()的方式较 write()和 poke()的写寄存器方式更为灵活的是,它可以实现随机化寄存器配置值(先随机化寄存器模型,后将随机值结合某些域的指定值写入到寄存器),继而模拟更多不可预知的寄存器应用场景。另外,update()强大的批量操作寄存器功能使得修改寄存器更为便捷。

// randomize register model, set register/field value and update to 
// hardware actual value 
void'(rgm. chnlO_ctrl_reg. randomize()); 
rgm.chnlO ctrl reg.pkt len.set('h3); 
rgm.chnlO ctrl reg. update (status, UVM FRONTDOOR, .parent (this)); void'(rgm.chnll_ctrl_reg.randomize()); 
rgm. chnl0_ctrl_reg. set ('h22); 
rgm.update(status, UVM FRONTDOOR, .parent(this));

mem与reg的联系和差别

UVM寄存器模型也可以用来对存储建模。uvm_mem 类可以用来模拟RW (读写)、 RO(只读)和WO(只写)类型的存储,并且可以配置存储模型的数据宽度和地址范围。uvm_mem不同于uvm_reg 的地方在于,考虑到物理存储一旦映射到 uvm_mem 会带来更大的资源消耗,因此 uvm_mem 并不支待预测和影子存储(shadow storage) 功能, 即没有镜像值和期望值。

uvm_mem 可以提供的功能就是利用自带的方法去访问硬件存储, 相比于直接利用硬件总线 UVC进行访问,这么做的好处在于:

• 类似于寄存器模型访问寄存器,利用存储模型访问硬件存储便于维护和复用。

• 在访问过程中,可以利用模型的地址范围来测试硬件的地址范围是否全部覆盖。

• 由于 uvm_mem 也同时提供前门访问和后门访问,这使得存储测试可以考虑先通过后门访问预先加载存储内容,而后通过前门访问读取存储内容,继而做数据比对,这样做不但节省时间,同时也在测试方式上保持了一致性。同时这种方式相比于传统前后测试方式(利用系统函数或仿真器函数实现存储加载),要在UVM测试框架中更为统一。

与 uvm_reg 相比, uvm_mem不但拥有常规的访问方法read() 、 write()、peek()和 poke(),也提供了 burst_read()和 burst_write() 。之所以额外提供这两种方法, 不但是为了可以更高速地通过物理总线的BURST方式连续存储,也是为了尽可能贴合实际访问存储中的场景。要实现BURST访问形式, 需要考虑下面这些因素:

• 目前挂载的总线UVC是否支持BURST形式访问,例如APB不能支持BURST访问模式。

• 与 read()、 write()方法相比,burst_read()和 burst_write()的参数列表中的一项uvm_reg_ data _t value[]采用的是数组形式, 不再是单一变量, 即表示用户可以传递多个数据。而在后台,这些数据首先需要装载到 uvm_reg_item 对象中,装载时 value 数组可以直接写入, 另外两个成员需要分别指定为 element_kind = UVM_MEM , kind = UVM_BURST_READ。

• 在 adapter 实现中, 也需要考虑到存储模型 BURST 访问的情形, 实现4 种访问类型(uvm _access_ e) 的转换,即UVM_READ、UVM_WRITE、UVM_BURS_READ 和UVM_BURST_ WRITE。对于 UVM_READ 和 UVM_WRITE 的桥接, 已经在寄存器模型访问中实现, 而 UVM_BURST_READ 和 UVM_BURST_WRITE的转换,往往需要考虑写入的数据长度,例如长度是否是 4、 8、 16 或其他。比如 AHB 总线, 支持连续 4 个、8 个、 16 个数据的读写 (INCR4 、 INCR8、 INCR16), 但是如果数据长度不是这些固定长度时, adapter 还需要自己处理来实现 INCR 的连续访问方式。

• 此外还需要考虑不同总线的其他控制参数, 例如 AHB 支持 WRAP 模式, AXI 支持out-of-order 模式等, 如果想要将更多的总线控制封装在 adapter 的桥接功能里, 需要将更多的配置作为扩展配置, 在调用访问方法时作为扩展信息类,传入到形式参数uvm_object_extension。待传入后, adapter 将可以在桥接方法中抽取出扩展信息类,作为更准确的协议访问的限定依据。

• 对于更为复杂的 BURST 形式, 如果需要实现更多的协议配置要求, 那么笔者推荐直接在总线 UVC 层面去驱动。这样做的灵活性更大, 且更能充分全面的测试存储接口的协议层完备性。因此, 验证师在为存储模型访问实现 adapter 方法时, 需要考虑的是, uvm_mem 层面的方法应该尽员便捷、必要的参数应该少量, 以便于使用和维护;而另一方面, 如果要首先测试存储接口协议, 则应该在总线 UVC 的层面上完成更充分的验证。

内建sequences

不少有经验的 UVM 用户可能会忽略 UVM 针对寄存器模型内建的(built-in) 一些sequence, 实际上, 将这些自建的序列作为验证项目开始前的健康检查必选项, 对整个项目的平稳运行会有不小的贡献。

这是因为,在项目的开始阶段,设计内部的逻辑尚不稳定,验证师要跟上设计的进度,可以展开验证的部分无外乎是系统控制信号时钟、复位、 电源)和寄存器的验证。在项目早期,寄存器模型的验证可以为后期各个功能点验证打下良好的基础。比如,通过内建的寄存器序列可以实现完善的寄存器复位值检查,又比如检查读写寄存器的读写功能是否正常等。

不过有一些寄存器即便可以测试, 也建议将其作为例外而过滤出去, 例如一些重要的系统控制信号(时钟、复位、电源), 当写入某些值以后, 会使得系统全部或局部复位、时钟也可能被关闭 , 这就可能阻碍寄存器的下一步检查。所以 UVM 提供了一些特殊域, 用来禁止sequence 检查这些寄存器或存储。接下来,我们从下表来分别浏览整理出的寄存器和存储相关的自建sequence 。

78847936-8ab5-11ee-939d-92fbcf53809c.png

寄存器模型内建序列

789170f0-8ab5-11ee-939d-92fbcf53809c.png

存储器模型内建序列

接下来我们给出一段例码,来演示如何利用内建序列完成MCDF寄存器测试一开始的健康检查。下面的例码分别添加了 uvm_reg_ hw _reset_ seq、 uvm_reg_ bit_ bash_ seq和 uvm _reg_ access_ seq 来测试寄存器模型, 从代码的整洁性来看, 用户并不需要额外再添加什么, 这种使用方式非常方便, 且又能完成寄存器的大规模集成测试。

mcdf_rgm rgm; 
`uvm_object_utils(mcdf_example_seq)
`uvm_declare_p_sequencer(mcdf_bus_sequencer)
...
task body(); 
uvm_status_e status;
uvm_reg_data_t data; 
uvm_reg_hw_reset_seq reg_rst_seq = new(); 
uvm_reg_bit_bash_seq reg_bit_bash_seq = new(); 
uvm_reg_access_seq reg_acc_seq = new(); 
if (! uvm_config_db# (mcdf_rgm)::get (null, get_full_name (), "rgm", rgm)) begin 
`uvm_error("GETRGM", "no top-down RGM handle is assigned") 
end 
// wait reset asserted and release 
@(negedge p_sequencer.vif.rstn); 
@(posedge p_sequencer.vif.rstn); 
`uvm_info ("BLTINSEQ", "register reset sequence started", UVM LOW) 
reg_rst_seq.model = rgm; 
reg_rst_seq.start(m_sequencer);
`uvm_info ("BLTINSEQ", "register reset sequence finished", UVM_LOW) 
`uvm_info("BLTINSEQ", "register bit bash sequence started", UVM_LOW)
//reset hardware register and register model 
reg_bit_bash_seq.model = rgm; 
reg_bit_bash_seq.start(m_sequencer); 
`uvm_info("BLTINSEQ", "register bit bash sequence finished", UVM_LOW) 
`uvm_info("BLTINSEQ", "register access sequence started", UVM_LOW) 
//reset hardware register and register model 
reg_acc_seq.model = rgm;
`uvm info ("BLTINSEQ", "register access sequence finished", UVM LOW )
endtask 
endclass
如果想将一些寄存器排除在某些内建序列测试范围之外, 可以额外添加上面列表中提到的“禁止域名 ”。由于 uvm_reg_block 和 uvm_reg 均是 uvm_object 类而不是 uvm_ component 类,所以可以使用 uvm_resource_ db 来配置 “ 禁止域名 “。下面的代码摘自 mcdf_rgm::build()方法, 这相当于寄存器模型在自己的建立阶段设定了一些属性。当然, uvm_resource_ db 的配置也可以在更高层指定, 只不过考虑到 uvm_resource_ db 不具备层次化的覆盖属性, 我们建议只在 一个地方进行 “ 禁止域名 ” 的配置。
class mcdf_rgm extends uvm_reg_block;
...
virtual function build(); 
// disable built-in seq attributes 
uvm_resource_db#(bit)::set ({"REG::", this. chnlO stat reg. get full name () } , 
NO REG ACCESS TEST", 1); 
uvm_resource_db# (bit)::set ({ "REG: : ", this. chnll stat reg.get full name () } , 
"NO REG ACCESS TEST", 1); 
uvm_resource_db#(bit):: set ({"REG: : ", this. chnl2 stat reg. get full name () } , 
"NO REG ACCESS TEST", l); 
endfunction
endclass






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    31

    文章

    5342

    浏览量

    120297
  • UVM
    UVM
    +关注

    关注

    0

    文章

    182

    浏览量

    19168
  • uvc
    uvc
    +关注

    关注

    1

    文章

    127

    浏览量

    14530

原文标题:IC学霸笔记 | UVM寄存器模型的常规方法

文章出处:【微信号:IC修真院,微信公众号:IC修真院】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    从设计的角度一块儿来看下这些UVM寄存器模型

    对于搞验证的同学来讲,UVM里面中关于寄存器的概念自然是耳熟能详,对于搞设计的小伙伴来讲,也许我们对于使用的场景和UVM寄存器模型对照并没有
    发表于 06-23 16:06

    介绍UVM寄存器模型访问上的一些内容

    寄存器域段(uvm_reg_field)是构造寄存器模型最小的功能单元。这也就意味着,寄存器的值,是由多个域段的值拼接起来的。那么,在介绍
    发表于 07-04 15:36

    如何构建UVM寄存器模型并将寄存器模型集成到验证环境中

    ),通常也叫寄存器模型,顾名思义就是对寄存器这个部件的建模。本文要介绍的内容,包括对UVM寄存器模型
    发表于 09-23 14:29

    寄存器的作用哪些?

    寄存器的作用哪些? 寄存器用途  1.可将寄存器内的数据执行算术及逻辑运算;  2.存于寄存器内的地址可用来指向
    发表于 03-08 14:35 1.6w次阅读

    寄存器分类哪些?

    寄存器分类哪些? 寄存器分类
    发表于 03-08 14:42 1.1w次阅读

    集成级的UVM寄存器模型

    UVM使得验证测试平台的结构得以标准化,各种复用策略及标准对于提高验证质量、缩短项目周期都非常有效。垂直重用是常见的复用策略之一,即同一项目测试平台复用于不同验证层次。验证中常将最底层的IP级验证平台向更高的集成层复用,而UVM寄存器
    发表于 09-15 11:49 16次下载
    集成级的<b class='flag-5'>UVM</b><b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>

    五个广泛使用的特殊寄存器

      下一步是学习如何在 IP-XACT 或 SystemRDL 中定义这些特殊寄存器。还需要学习如何在 RTL 中对其进行编码,并创建 UVM 寄存器模型并完成
    的头像 发表于 06-08 09:55 4563次阅读
    五个广泛使用的特殊<b class='flag-5'>寄存器</b>

    简化UVM寄存器模型的使用教程

    当我开始使用UVM RAL时,我无法理解UVM基类库对更新Desired和Mirror 寄存器的解释。觉得使用的术语并不能准确地反映里面的真实的意思。花了一些时间后,我想出了一个表格,它可以帮助我理解
    的头像 发表于 01-30 15:25 2252次阅读
    简化<b class='flag-5'>UVM</b><b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>的使用教程

    简述RAL寄存器模型基础

    RAL(Register Abstract Layer,寄存器抽象层),通常也叫寄存器模型,顾名思义就是对寄存器这个部件的建模。本文要介绍的内容,包括对
    的头像 发表于 02-14 16:55 2715次阅读
    简述RAL<b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>基础

    RAL寄存器模型操作图鉴

    寄存器模型操作,指的是通过寄存器模型对RTL中寄存器进行读写访问,或者同步寄存器
    的头像 发表于 05-17 09:01 934次阅读
    RAL<b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>操作图鉴

    UVM为什么要引入寄存器模型

    新需求:为带寄存器的DUT搭建UVM仿真环境
    的头像 发表于 05-26 14:57 1818次阅读
    <b class='flag-5'>UVM</b>为什么要引入<b class='flag-5'>寄存器</b><b class='flag-5'>模型</b><b class='flag-5'>呢</b>?

    简化UVM寄存器模型的使用

    当我开始使用 UVM RAL 时,我无法理解 UVM 基类库对更新所需值和镜像值寄存器的值什么看法。我还认为,所使用的术语没有准确反映其意图。花了一些时间后,我想出了一个表,帮助我了
    的头像 发表于 05-29 10:15 1253次阅读
    简化<b class='flag-5'>UVM</b><b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>的使用

    基于DUT内部寄存器值的镜像

    (outdated) 。 寄存器模型可以通过使用 uvm_reg_field::mirror() , uvm_reg::mirror() , 或 u
    的头像 发表于 06-24 12:02 891次阅读

    寄存器模型Register Model学习笔记

    UVM寄存器模型是一组高级抽象的类,用来对DUT中具有地址映射的寄存器和存储进行建模。
    的头像 发表于 07-11 09:20 2220次阅读
    <b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>Register Model学习笔记

    RAL寄存器模型操作指南

    寄存器模型操作,指的是通过寄存器模型对RTL中寄存器进行读写访问,或者同步寄存器
    的头像 发表于 07-12 09:37 1078次阅读
    RAL<b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>操作指南