电子说
就像芯片本身一样,SoC上的CSR设计也沿用了层级设计的方法。从最底层往上,寄存器可以被分为以下几个层级。
下面我们就来一一简单介绍一下,它们是如何在设计里面实现的。
为了提升设计的效率,一个寄存器往往包含着许多功能的控制或是模块的状态,所以一个寄存器往往可以再向下分出几个更小的配置单元来达到不同的目的。比如说下图就是一个被设计了五个不同域的寄存器,每个域都有它特定的功能。
CSR中的不同域
A Register Block
那么Reg本身不用说就是最常见的CSR unit了。而Reg Block则是根据SoC上不同模块的Reg Collection组成的一个寄存器块。比如对于SoC Top层的寄存器有控制 Direct Memory Access(DMA) 的也有监视中断状态的寄存器。一个模块的寄存器往往都拥有同一个 offset address 。如下图所示。
一个SoC上通常都有一个或多个processor cores,direct memory access(DMA),bus network interconnects和许多种 peripheral module 。而每个外设模块都拥有一个它所有CSR的 Reg Block 。Memory Map就是这些所有Reg Block的顶层模块,并为每个Reg Block定义了不同的地址范围,每个Block都有它一个对应的 base address 。而且对于不同的 processor core ,这些地址范围还可能不一样,根据不同的 rocessor bus(Maybe AHB or AXI) 。
A Memory Map
在了解UVM Reg Model这一部分之前,让我们先了解一下它的一些来源吧。
At the begining, UVM_RGM is not part of the Accellera standard, it is a user contribution from Cadence which is based on their use contribution from the OVM. UVM1.1 has a Register Abstaction as a part of the Accellera standard called UVM_REG. There is already multiple vendors that supprot generations producing UVM_REG descriptions
这是来自一个论坛上对于UVM_REG的介绍。大致意思就是UVM_REG的前身是 UVM_RGM ,在加入到Accellera标准之前,它其实是一个民间创建的package。所以我们可以简单理解UVM_REG就是一个UVM的library。
UVM_REG重新定义了TB和设计中的寄存器,它提供了一种不同的验证方法来简化对芯片上的寄存器的仿真。那么它到底是如何简化的呢?
就像设计中寄存器的层级结构,在搭建寄存器验证环境的时候我们当然也想要一个能模仿DUT中CSR行为的结构,所以UVM Reg Model也提供了
正如前面所提,UVM将设计中的CSR每一层都抽象成了一种class。对于Reg Field而言就是uvm_reg_field这个class了。一般它在Reg Class中被声明成rand类型的变量。
对于Reg本身,UVM定义了uvm_reg这一class,就像所有的Reg field需要继承自uvm_reg_field一样,寄存器验证环境中的每个寄存器都要继承自uvm_reg。如下code所示,Reg Field被声明成rand类型的变量便于我们有时候做一些特殊的case,后面会介绍到。
就像所有uvm的class一样,我们需要将它实例化才能够真正使用它。这里我们看到一个函数——‘configure()‘这个configure()函数十分重要,它决定了这个寄存器中每个寄存器域的属性,决定了这个域的访问权限,是否具有失忆性等等。这在后面的验证过程中十分重要!!!
在一个uvm_reg中声明不同rand类型的域
当我们在环境里面定义了所有需要被仿真的寄存器后,就需要将它们集合在一起方便做一些更高层级的操作,就像DUT中的CSR一样。这个时候我们就用到了uvm_reg_block这个class了。以下是一段uvm block的code。
在uvm_block中声明所有这个block中的CSR
除了要声明,实例化这些寄存器以外,也不要忘记使用configure()定义这些寄存器的属性,并将它们添加到default map当中。一个reg_block的对象就是一个Register model然后通过它可以访问到里面所有的寄存器进行读写操作。
configure函数
到目前为止,我们只知道了如何去构建一个类似于DUT中的寄存器仿真模型(有点reference model内味儿)。但如何让环境中的寄存器模型“动起来”,like模拟DUT中CSR的读写操作还仍未知晓。
当然,这只是寄存器仿真环境的一部分,要想进行寄存器操作,我们还需要向bus发送bus transaction,就像直接通过普通的bus agent向外设寄存器配置接口发送读写的transaction一样。
但在我们继续这个环境的剩余部分之前我还需要向你们介绍UVM Reg中两个重要的概念——Mirror Value和Desired Value。这两个概念十分重要,对于理解后面UVM Reg内建的各种task和sequence帮助巨大!
这个value可以理解成我们期望DUT寄存器中的值。寄存器模型中的这个变量其实就是我们预先设定好而后再更新同步到DUT中的寄存器里。如下图:
CSR中的期望值
而mirror value则是尽它最大的可能反应实际DUT中的值,每次我们通过寄存器模型发送读写操作到DUT中,对应寄存器的mirror value都会被更新。如下图:
CSR中的镜像值
实际上,整个寄存器环境一共有四个组成部分:
寄存器模型环境整体
Register Model就是上文用了大量笔墨提到的一个组成部分。Agent也与其他常规验证环境中的agent类似,依据不同的protocol将不同的transaction通过agent作为激励送到DUT中。下面我们将重点介绍一下在寄存器环境中特有的两个组成部分:Adapter和Predictor
由于寄存器模型中的seq有它特有的封装方式,所以为了将寄存器模型类型的seq转化成bus agent可识别的bus transaction,我们需要一个转换器,同理来自bus agent的transaction也需要经过Adapter的转换才能将来自DUT的信息同步到寄存器模型中。Adapter中最重要的两个函数就是reg2bus() 和 bus2reg() 了,分别对应上述的两个方向的transaction的转化。
Predictor的作用也是用来同步寄存器模型中的值的。但经常,如果我们只通过寄存器模型里发起sequence,我们只拥有一个adpter就足够同步寄存器模型里面的值通过寄存器模型built-in的task——read(),write(),因为这些内建的task中都有predict()函数,它的作用就是来将我们配置或从DUT收集来的值同步到寄存器模型中。但如果有一些配置DUT中寄存器的transaction来自于其他sequencer发送到bus agent的话,这个时候寄存器模型就不能实时的更新了,这有可能使我们最后的check mismatch。
所以predictor的main idea就是在环境中增添了一个连接agent中monitor的component来无时无刻监视着bus agent的动态,只要有任何write/read transaction经过,都会将其同步回寄存器模型中。
集成了predictor的寄存器模型环境
ok,现在我们已经具备了寄存器模型环境中的所有所需要的“砖头”了,那么接下来就是如何将他们搭建成一个完整的房子了。如同其他所有验证环境一样,我们要在build phase将它们一个个实例化,然后在connect phase中再将它们衔接在一起。以下是一个简易的寄存器模型环境的实例,仅供参考。
寄存器虽然在整个芯片当中作为一个设计风险较小的组成部分,但在SoC验证过程中是要优先完成验证的部分。如果由于一个顶层寄存器的问题而导致一个芯片上大部分模块无法正常工作是很耽误验证时效的。对于寄存器验证来讲,特别是一个有很多寄存器的芯片来讲,如何通过UVM Reg进行高效,灵活的寄存器验证十分重要!
全部0条评论
快来发表一下你的评论吧 !