【UVM】别再说你的 VIP 用不了 RAL Model

编程入门 行业动态 更新时间:2024-10-26 16:21:21

【UVM】别再说你的 <a href=https://www.elefans.com/category/jswz/34/1767647.html style=VIP 用不了 RAL Model"/>

【UVM】别再说你的 VIP 用不了 RAL Model

一种通用的寄存器模型访问寄存器的方法
mangopapa@yeah

摘要

  基于 UVM 的验证平台中,常采用寄存器模型(RAL Model)对待测设备(DUT)进行寄存器访问。常用的方法是自定义 Adapter,寄存器模型发起寄存器访问请求,经 Adapter 转为 Sequencer 识别的 Transaction,发送到 Driver 上进行寄存器访问的读写操作。对于某些通用的 Sequencer 及 Driver,其 Transaction 没有地址数据的概念,寄存器访问操作所需的地址、数据需要分多笔发送,此时 Adapter 的方式不再适用。本文采用了一种新的方法,重写了 uvm_reg_map 的 do_bus_write、do_bus_read 任务,将一笔 Transaction 拆分为多笔 Transaction,分多次发送,可以解决以上问题。本文采用的方法,支持 Adapter + Non-Adapter 混合的模式。

关键词:UVM、寄存器模型、Adapter、通用接口、JTAG



文章目录

  • 摘要
  • 1. 背景介绍
  • 2. 问题分析与解决
    • 2.1 自定义 do_bus_write/do_bus_read
    • 2.2 多类型接口、Adapter + Non-Adapter 访问寄存器
    • 2.3 自定义 uvm_reg_map 的使用
  • 3. 实现案例
  • 4. 总结
  • 参考


1. 背景介绍

  基于 UVM 的验证平台中,常采用 RAL Model 对 DUT 进行寄存器访问,寄存器访问的接口也各式各样。常规的 RAL Model 使用方法为:

  1. reg_gen 等脚本生成 DUT 的 ralf、uvm_reg、reg_block。
  2. 写 Adapter,自定义 bus2reg 及 reg2bus 两个 Function。
  3. 寄存器模型集成到验证平台中,给寄存器模型指定 Sequencer 及 Adapter。
  4. 调用 reg.read、reg.write、reg_block.read_by_name、reg_block.write_by_name 等进行前门寄存器访问。

▲图 1:基于 RAL Model 的寄存器访问

  Adapter 是如何把寄存器模型与我们的 driver 联系起来的呢?可以简单参考《UVM 实战(卷 I)》这幅图(图 1)。采用 Adapter 的方法简便易用,对于 APB、AXI、PCIe 等数据帧格式固定的标准接口,在自定义 RAL Model 中的 Adapter 后,调用 reg.read、reg.write 发送一次携带有地址、数据的 Transaction 进行一次总线操作即可完成寄存器访问。对于 UART、SPI、JTAG 等较为通用的低速接口,没有统一的寄存器访问标准,且使能、地址、数据等需要按照 DUT 自定义的帧格式分多次发送,待 UART/SPI/JTAG Slave 收齐所有寄存器访问所有的指令后再进行寄存器访问。跟这些接口对接的 Master VIP 或 BFM 采用的 Sequencer 及 Driver 也多为通用,其 Transaction 没有地址数据的概念。显然 ,此时自定义的 Adapter 无法适用,因为 Adapter 无法完成以上多步操作。

  本文以 JTAG 接口寄存器访问为例,采用了一种新的通用方法,重写了 uvm_reg_map 的 do_bus_write、do_bus_read 任务,将一笔 Transaction 拆分为多笔 Transaction 分多次发送,可实现基于通用接口的寄存器访问。鉴于 DUT 存在支持多个接口访问寄存器的可能,有些需要 Adapter 有些无需 Adapter,这种情况下本文提出的方法仍然适用。



2. 问题分析与解决

  寄存器模型发起寄存器读写操作后,寄存器模型的 Sequence 生成一笔 uvm_reg_bus_op 类型的 Transaction,送到 uvm_reg_map 的 do_bus_write 或 do_bus_read。do_bus_write/read 调用自定义的 Adapter(其中定义了 reg2bus 及 bus2reg 两个 Function),在 uvm_reg_bus_op 类型的 Transaction 中获取读写地址数据等有用信息,赋值到我们 Sequencer 支持的 Transaction 类型(bus_req)中,并将之前指定的 Sequencer 赋给 bus_req,最后 bus_req.start_item 将寄存器读写操作发给 Driver。

  无论是直接调用 uvm_reg 的 write、read task,还是间接通过 uvm_reg_blcok 的 read_reg_by_name、uvm_reg_write_by_name、read_mem_by_name、write_mem_by_name 去读写寄存器,其最终都是调用了 uvm_reg_map 中的 do_bus_write 或 do_bus_read 两个 task 去进行总线操作。


2.1 自定义 do_bus_write/do_bus_read

  既然 Adapter 的模式行不通,那么我们可以直接绕过 Adapter,重写 uvm_reg_map 中的 do_bus_write/do_bus_read 两个 Task。
重写的 uvm_reg_map 示例代码如下:

class my_uvm_reg_map extens uvm_reg_map;...// User define do_bus_writetask do_bus_write(uvm_reg_item rw, uvm_sequencer_base sequencer,uvm_reg_adapter adapter);... my_seq   m_seq0_h;   // sequencemy_seqr  m_seqr0_h; // sequencer used to send transactionforeach (accesses[i]) begin// send cmd, like reg write/read enablem_seq0_h.data = accesses[i].kind==UVM_WRITE;m_seq0_h.start(m_seqr0_h);// send reg addressm_seq0_h.data = accesses[i].addr;m_seq0_h.start(m_seqr0_h);// send reg datam_seq0_h.data = accesses[i].addr;m_seq0_h.start(m_seqr0_h);end...endtask : do_bus_writetask do_bus_read(xxx);// The Same method as do_bus_write...my_do_bus_read0(xxx);endtask : do_bus_read...
endclass : my_uvm_reg_map
▲示例代码 1:自定义的 do_bus_write/read

  需要注意的是,虽然此处没有用到 Adapter,自定义 do_bus_write/read 中调用的 Sequencer 仍然可以采用 reg_model.default_map.set_sequencer(sequencer, adapter) 的方式去指定,Adapter 不填或者指定 null 即可。另外一种传递 Sequencer 到 uvm_reg_map 的方法:通过 uvm_resource_db 去传。


2.2 多类型接口、Adapter + Non-Adapter 访问寄存器

  采用 2.1 所述方法自定义 do_bus_read、do_bus_write 能够将 RAL Model 发来的一笔 Transaction 拆分为多笔,并按需发送出去。复写之后的 do_bus_write/read,仅支持特定的接口,无法满足多类型接口访问寄存器的需求。此外,有些接口仍想维持 Adapter 的方式访问寄存器。此时,直接复写 do_bus_write/read 的方式显然无法满足需求。

  为了支持多类型接口访问寄存器的需求,get_name() 后通过字符匹配来判断是谁在调用当前的任务,进而进入不同的代码分支,来选择是否启用 Adapter、选用哪个自定义的 do_bus_write/read,从而实现对多个自定义 my_do_bus_write/read 及 Adapter + Non-Adapter 的支持。示例代码如下所示。

class my_uvm_reg_map extens uvm_reg_map;...// If reg_blk0 call this task, use user defined my_do_bus_write/read task,// else use original do_bus_write by super.do_bus_write. // str_match is also an user defined function to realize the string matchingtask do_bus_write(uvm_reg_item rw, uvm_sequencer_base sequencer,uvm_reg_adapter adapter);...case (get_name())"reg_blk0_name" : my_do_bus_write0(rw, sequencer);"reg_blk1_name" : my_do_bus_write1(rw, sequencer);...default : super.do_bus_write(rw, sequencer, adapter);endcaseendtask : do_bus_writetask do_bus_read(xxx);// The Same method as do_bus_readendtask : do_bus_read// User defined do_bus_write/readtask my_do_bus_write0(uvm_reg_item rw, uvm_sequencer_base sequencer);my_seq   m_seq0_h;   // sequencemy_seqr  m_seqr0_h; // sequencer used to send transaction... foreach (accesses[i]) begin// send cmd, like reg write/read enablem_seq0_h.data = accesses[i].kind==UVM_WRITE;m_seq0_h.start(m_seqr0_h);// send reg addressm_seq0_h.data = accesses[i].addr;m_seq0_h.start(m_seqr0_h);// send reg datam_seq0_h.data = accesses[i].addr;m_seq0_h.start(m_seqr0_h);end...endtask : my_do_bus_write0task my_do_bus_read0(xxx);// Same method as my_do_bus_write0endtask : my_do_bus_read0;...
endclass : my_uvm_reg_map
▲示例代码 2:多类型接口、Adapter + Non-Adapter 时的 uvm_reg_map 用法

2.3 自定义 uvm_reg_map 的使用

  上文自定义了 my_uvm_reg_map,该如何使用呢?简单粗暴点,直接 override 掉原生的 uvm_reg_map。放在 Test Case 或者仿真选项中均可,以下是放在仿真选项中:

+uvm_set_type_override=uvm_reg_map,my_uvm_reg_map


3. 实现案例

  某个 DUT 的寄存器 Block 中包含两部分寄存器:Controller 的寄存器及 PHY 的寄存器。其中 Controller 的寄存器只能通过 AXI 接口访问到,PHY 的寄存器只能通过 JTAG 接口访问到。在 DUT 验证过程中,希望用 UVM 寄存器模型来访问寄存器,并提供有 AXI VIP 及 JTAG VIP 作为 Master 发起寄存器访问操作。

  采用 AXI 访问较为简单,鉴于 AXI VIP 支持寄存器模型,我们仍然采用 Adapter 的模式去访问寄存器,AXI VIP 发起一次总线操作即可完成。JTAG VIP 功能较简单,但 JTAG 访问比 AXI 访问复杂一些,只能通过调用既定的 Sequence 发送标准的 JTAG 数据包,驱动 TCK、TMS、TDI 动起来,没有寄存器访问所需的地址及数据的概念。

  JTAG VIP 作为 Master,DUT 中的 JTAG Controller 作为 Slave。按照 Slave JTAG Controller 的设计方案,采用 JTAG 接口访问其他 DUT 的寄存器,至少需要 3 步:

  1. JTAG Master 配置 Slave IR,将 DUT 寄存器访问模式配置为 JTAG 访问。
  2. JTAG Master 按既定帧格式往 Slave DR 写待访问寄存器的地址。
  3. 对于寄存器写操作,JTAG Master 按既定帧格式往 Slave DR 写待访问寄存器的数据。对于寄存器读操作,JTAG Master 持续往 Slave DR 写无关数据,直到 JTAG VIP 收到相关响应。
    我们把以上三步封装到一个 Sequence 里,便于在 do_bus_write/read 中直接调用。同时支持 AXI Adapter 访问寄存器及 JTAG Non-adapter 访问寄存器的关键代码如下图所示。

▲图 2:自定义 do_bus_write 示例

▲图 3:自定义 do_bus_read 示例


4. 总结

  本文采用了一种新的方法,重写了 uvm_reg_map 的 do_bus_write、do_bus_read 任务,将一笔 Transaction 拆分为多笔 Transaction,分多次发送,可以实现自定义的寄存器访问 Sequence 发送,且支持多个自定义 my_do_bus_write/read 及 Adapter + Non-Adapter 混合的模式。所以,别再说你的 VIP 用不了寄存器模型。

  直接篡改 uvm_reg_map 多少有些剑走偏锋。如非必要,勿用此法,能改 Driver 还是改 Driver 吧。



参考

  1. UVM-1.2 源码
  2. UVM 实战(卷 I),张强

更多推荐

【UVM】别再说你的 VIP 用不了 RAL Model

本文发布于:2024-02-07 09:27:03,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1755416.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:VIP   UVM   Model   RAL

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!