寄存器模型-2

本文详细介绍了寄存器模型与总线UVC之间的桥接机制,重点讨论了adapter的角色和实现。adapter负责在uvm_reg_item和bus_seq_item之间转换,处理读写操作和反馈信号。前门访问通过总线物理操作,后门访问则直接作用于DUT寄存器,提供了快速访问途径。文章强调了结合两者进行寄存器验证的重要性,并给出了应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

寄存器模型与总线UVC实现桥接呢?下图中添加了更多的细节来表示寄存器桥接(adapter)的作用。

  • 从激励的流向来看,寄存器序列(而不是总线序列)会将带有目标寄存器的相关信息存放到uvm_reg_item实例中,送往adapter。

  • adapter在接收到uvm_reg_item之后,需要从中抽取出总线UVC所需的信息,同时生成总线UVC需要的bus_seq_item类型。在完成了数据内容抽取和二次写入之后,bus_seq_item由adapter送往了总线UVC。

  • 总线UVC从bus_seq_item获取了地址、数据、操作模式等信息之后会发起总线的读写访问。对于写访问而言,如果总线上有反馈信号来标示访问是否成功,则该标示应当由总线sequencer按照item response的路径返回至adapter,adapter也应对该反馈信号做出处理。这一反馈路径在读访问时也会将总线读回的数据返回至adapter,并最终交回到与寄存器操作有关的方法返回值。

 对于寄存器模型而言,它生成之时并不会有adapter伴随。实际上adapter的上层UVM寄存器包是一个标准包,但下层即各个总线UVC,考虑到总线协议的不同带来的总线sequence item的不同、以及不同公司、团队开发的同一种总线UVC也存在不小差异,因此adapter开发的责任就落到了总线UVC本身。而实际情况是,目前大多数商业总线UVC并没有自带寄存器adapter,而多数自研的总线UVC也并未顾及到adapter的开发。这里,路桑提倡总线UVC的开发也应当将adapter一并囊括进去,这样就将寄存器模型与总线UVC集成时的各自边界划分的很清晰,否则只能由TB构建者来实现不同总线的adapter,这无疑增加了额外的TB构建开销。

但有时候,事实如此,读者现阶段如果要集成寄存器模型,恐怕仍然需要掌握实现adapter的一些基本技巧,同时理解adapter充当抽象层转化的原理。我们贯穿本章的材料依然是MCDF寄存器模块,以及接下来的较为简单的访问寄存器的总线UVC和对应的adapter实现。希望通过本节内容,读者可以懂得依靠adapter来实现的前门(front-door)访问和后门(back-door)访问两种方式。

在具备了MCDF总线UVC之后,需要实现adapter。每一个总线对应的adapter所完成的桥接功能即是在uvm_reg_bus_op(寄存器操作transaction)和具体总线的transaction(这里指mcdf_bus_trans)之间的转换。uvm_reg_adapter类以及通过稍后的adapter集成,使得用户在开发某一个总线adapter类型时,只需要下面几点:

  • uvm_reg_bus_op与总线transaction中各自的数据映射。

  • 实现reg2bus()和bus2reg()两个函数,这两个函数即实现了不同transaction之间的数据映射。

  • 如果总线支持byte访问,可以使能supports_byte_enable;如果总线UVC要返回response数据,则应当使能provides_responses

前门访问

利用寄存器模型,我们可以更方便地对寄存器做操作。接下来我们分别两种访问寄存器的方式,即前门访问(front-door)和后门访问(back-door)。前门访问,顾名思义指的是在寄存器模型上做的读写操作,最终会通过总线UVC来实现总线上的物理时序访问,因此是真实的物理操作;而后门访问,指的是利用UVM DPI (uvm_hdl_read()、uvm_hdl_deposit()),将寄存器的操作直接作用到DUT内的寄存器变量,而不通过物理总线访问。

下面给出一段进行前门访问的例码。下面的这个sequence,继承于uvm_reg_sequence,其除了具备一般uvm_sequence的预定义方法外,还具有跟寄存器操作相关的方法。下面对寄存器操作的例码中,用户可以看到两种方式:

  • 第一种即uvm_reg::read()/write()。在传递时,用户需要注意将参数path指定为UVM_FRONTDOOR。uvm_reg::read()/write()方法可传入的参数较多,除了status和value两个参数需要传入,其它参数如果不指定,可采用默认值。

  • 第二种即uvm_reg_sequence::read_reg()/write_reg()。在使用时,也需要将path指定为UVM_FRONTDOOR。

    后门访问

    在进行后门访问时,用户首先需要确保寄存器模型在建立时,是否将各个寄存器映射到了DUT一侧的HDL路径。下面的例码即实现了寄存器模型与DUT各个寄存器的映射:

  • 后门访问的路径地址:reg_backdoor_access.dut+$sformatf()内容

    例码中通过uvm_reg_block::add_hdl_path(),将寄存器模型关联到了DUT一端,而通过uvm_reg::add_hdl_path_slice完成了将寄存器模型各个寄存器成员与HDL一侧的地址映射。例如在稍后对寄存器SLV0_RW_REG进行后门访问时,UVM DPI函数会通过寄存器HDL路径“reg_backdoor_access.dut.regs[0]”映射到正确的寄存器位置,继而对其进行读值或者修改。另外,寄存器模型build()函数最后一句,以lock_model()结尾,该函数的功能是结束地址映射关系,并且保证模型不会被其它用户修改。

    在寄存器模型完成了HDL路径映射后,我们才可以利用uvm_reg或者uvm_reg_sequence自带的方法进行后门访问,下面仍然给出一段后门访问的例码。类似于前门访问,后门访问也有几类方法提供:

  • uvm_reg::read()/write(),在调用该方法时需要注明UVM_BACKDOOR的访问方式。

  • uvm_reg_sequence::read_reg()/write_reg(),在使用时也需要注明UVM_BACKDOOR的访问方式。

  • 另外,uvm_reg::peek()/poke()两个方法,也分别对应了读取寄存器(peek)和修改寄存器(poke)两种操作,而用户无需指定访问方式尾UVM_BACKDOOR,因为这两个方法本来就只针对于后门访问。

前门访问和后门访问的比较

下面的表总结了前门访问和后门访问的主要差别:

  从面的差别可以看出,后门访问较前门访问更便捷一些更快一些,但如果单纯依赖后门访问也不能称之为“正道”。实际上,利用寄存器模型的前门和后门访问两种混合方式,对寄存器验证的完备性更有帮助。下面给出一些实际应用的场景:

  • 通过前门访问的方式,先验证寄存器访问的物理通路工作正常,并且有专门的寄存器测试的前门访问用例,来遍历所有的寄存器。在前门访问被验证充分的前提下,可以在后续测试中使用后门访问来节省访问多个寄存器的时间。

  • 如果DUT实现了一些特殊寄存器,例如只能写一次的寄存器等,我们建议用物理方式去访问以保证反映真实的硬件行为。

  • 寄存器随机设置的精髓不在于随机可设置的域值,而是为了考虑日常不可预期的场景,先通过后门访问随机化整个寄存器列表(在一定的随机限制下),随后再通过前门访问来配置寄存器。这么做的好处在于,不再只是通过设置复位之后的寄存器这种更有确定性的场景,而是通过让测试序列一开始的寄存器值都随机化来模拟无法预期的硬件配置前场景,而在稍后设置了必要的寄存器之后,再来看是否会有意想不到的边界情况发生。

  • 有的时候,即便通过先写再读的方式来测试一个寄存器,也可能存在地址不匹配的情况。譬如寄存器A地址本应该0x10,寄存器B地址本应该为0x20;而在硬件实现用,寄存器A对应的地址位0x20,寄存器B对应的地址位0x10。像这种错误,即便通过先写再读的方式也无法有效测试出来,那么不妨在通过前门配置寄存器A之后,再通过后门访问来判断HDL地址映射的寄存器A变量值是否改变,最后通过前门访问来读取寄存器A的值。上述的方式是在之前前门测试的基础之上又加入了中途的后门访问和数值比较,可以解决地址映射到内部错误寄存器的问题。

  • 对于一些状态寄存器,在一些时候外界的激励条件修改会依赖这些状态寄存器,并且在时序上的要求也可能很严格。例如,上面MCDF的寄存器中有一组状态寄存器表示各个channel中FIFO的余量,而channel中FIFO的余量对于激励驱动的行为也很重要。无论是前门访问还是后门访问,都可能无法第一时间反映FIFO在当前时刻的余量。因此对于需要要求更严格的测试场景,除了需要前门和后门来访问寄存器,也需要映射一些重要的信号来反映第一时间的信息。

<think>好的,我现在需要向用户介绍如何添加寄存器模型。首先,我得明确用户的问题背景。寄存器模型通常出现在数字电路设计或验证中,特别是在使用UVM(通用验证方法学)这样的验证框架时。用户可能是硬件验证工程师,或者是正在学习相关领域的学生。他们可能需要了解如何在验证环境中添加寄存器模型,以提高测试的自动化和覆盖率。 接下来,我应该回顾寄存器模型的基本概念。寄存器模型是对硬件寄存器的抽象表示,用于验证过程中预测寄存器的状态,自动生成读写操作,并检查寄存器的行为是否符合预期。在UVM中,寄存器模型(Register Model)是一个重要的组件,它帮助验证工程师管理寄存器的配置和状态,而不需要直接访问硬件。 然后,我需要分解添加寄存器模型的步骤。通常,这个过程包括几个主要步骤:定义寄存器结构、生成寄存器模型、集成到验证环境、编写测试用例以及调试和验证。每个步骤都需要详细说明,以确保用户能够逐步理解和实施。 首先,定义寄存器结构需要使用特定的描述语言,如XML或IP-XACT,或者使用工具提供的格式。例如,Synopsys的ralgen工具需要特定的寄存器描述文件。这里可能需要举例说明一个寄存器的结构,包括地址、字段、访问权限等属性。例如,一个控制寄存器可能有多个字段,每个字段有不同的位宽和访问权限。 接下来是生成寄存器模型。使用自动化工具根据寄存器描述文件生成对应的UVM寄存器类。例如,运行ralgen命令处理寄存器定义文件,生成SystemVerilog代码。生成的类通常包括寄存器块(register block)、寄存器(register)和字段(field)的层次结构。需要说明这些类的作用,比如uvm_reg_block代表寄存器组,uvm_reg表示单个寄存器,uvm_reg_field表示寄存器中的各个字段。 然后是集成到验证环境。需要将生成的寄存器模型实例化到验证环境中,并连接到适配器(adapter)和预测器(predictor)。适配器负责将寄存器模型的抽象操作转换为具体的总线事务,而预测器则根据总线活动更新寄存器模型的状态,保持模型与硬件同步。这里可能需要解释适配器和预测器的作用,以及如何将它们连接到环境中的代理(agent)和记分板(scoreboard)。 编写测试用例部分需要说明如何利用寄存器模型进行读写操作。例如,使用后门访问初始化寄存器,或者通过前门访问执行正常的读写操作。同时,需要提到如何利用寄存器模型的自动检查功能,比如检查寄存器的复位值和读写后的值是否符合预期。 调试和验证阶段可能会遇到的问题,比如寄存器地址映射错误,字段掩码不正确,或者预测器未正确更新模型状态。需要提醒用户使用波形调试、日志分析和功能覆盖来确保正确性。 此外,可能还需要提到一些注意事项,比如寄存器模型需要与RTL设计保持同步,特别是在设计变更时,必须重新生成和更新模型。同时,强调寄存器模型在验证中的优势,比如提高效率、减少人为错误和支持复杂的测试场景。 最后,总结整个过程,并建议用户参考工具文档和UVM手册以获取更详细的信息。确保语言清晰,结构合理,步骤明确,让用户能够按照指导逐步实施。</think>添加寄存器模型是数字验证中的关键步骤,主要用于实现寄存器访问的抽象化验证。以下为分步说明: $$register\_model \xrightarrow{映射} RTL设计$$ 一、核心组件 1. 寄存器抽象层 - 使用uvm_reg构建寄存器层级 - 每个寄存器包含多个uvm_reg_field - 示例字段定义: ```systemverilog class CTRL_REG extends uvm_reg; rand uvm_reg_field enable; rand uvm_reg_field mode; virtual function void build(); enable = uvm_reg_field::type_id::create("enable"); enable.configure(this, 1, 0, "RW", 0, 1'b0, 1, 1, 0); mode = uvm_reg_field::type_id::create("mode"); mode.configure(this, 2, 1, "RW", 0, 2'b00, 1, 1, 0); endfunction endclass ``` 二、实施步骤 1. 模型生成 - 使用RALGen工具转换寄存器描述文件 - 生成包含地址映射的寄存器块 ```bash ralgen -t block_name -I UVM regs.ralf ``` 2. 环境集成 ```systemverilog class env extends uvm_env; reg_model regmodel; uvm_reg_predictor #(bus_trans) predictor; function void build_phase(); regmodel = block_type::type_id::create("regmodel"); regmodel.build(); regmodel.lock_model(); predictor = new("predictor", this); endfunction function void connect_phase(); predictor.map = regmodel.default_map; predictor.adapter = bus_agt.adapter; bus_agt.monitor.item_collected_port.connect(predictor.bus_in); endfunction endclass ``` 3. 测试应用 - 前门访问: $$write\_reg(address, value, .path(UVM_FRONTDOOR))$$ - 后门访问: $$read\_reg(status_reg, .path(UVM_BACKDOOR))$$ 三、验证策略 1. 功能覆盖 - 字段值组合覆盖 - 特殊位跳变覆盖 $$covergroup ctrl_reg_cg; enable: coverpoint regmodel.ctrl_reg.enable.value; mode: coverpoint regmodel.ctrl_reg.mode.value; endgroup$$ 2. 自检机制 - 自动比对预测值与读取值 - 错误注入测试 $$assert(regmodel.status_reg.get() === expected_value)$$ 注意事项: 1. 保持地址映射与RTL设计严格同步 2. 总线协议适配器需正确处理字节使能 3. 复位值验证应包含上电复位和软复位场景 完整模型应支持: - 动态地址重映射 - 多总线接口协同 - 寄存器访问权限校验 - 影子寄存器追踪 建议结合具体验证方法学手册和EDA工具文档进行实现优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值