路科验证的个人空间 https://blog.eetop.cn/1561828 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

通过可复用的随机策略类实现SystemVerilog约束分层

已有 3383 次阅读| 2016-11-6 21:50 |个人分类:验证前沿资讯|系统分类:芯片设计

为便于我们创建验证激励,SystemVerilog类和随机约束提供了非常强大的机制。为了在一个约束对象中对约束分层,SystemVerilog也提供了几种机制,约束可以通过派生类的继承添加。内联约束(即randomize with {…}或`uvm_do_with)允许在随机化一个对象时,指定特殊的附加约束。不幸的是,在随后的“randomize with”调用中,SystemVerilog并没有提供提供一些较好的方法保存这些内联约束,使其便于复用。
 文提供了一种方法,把约束封装进可复用的随机化“策略”类中,并在随机化另外一个类的时候,使用其中的一种或者多种策略去声明约束。不同的测试测试场景可以采用这些策略规则的不同组合。这种方法适用于SystemVerilog或者诸如UVM的验证方法。
约束分层场景
考虑到多处理器存储系统的激励,事务地址中有几类比较典型也比较值得关注的约束类型:
  • 限制系统存储器映射的地址范围,在仿真过程中,这些范围可能会动态产生。
  • 避免保留区域的地址(例如用于testbench 控制的“magic”地址)
  • 为从数据缓存中回收而对地址进行约束,这就需要持续追踪哪些地址正在缓存中,并产生不在缓存中的地址。
理论上,可以用合适的控制功能把这些约束类包含进一个transaction基类中,或者使用继承来添加这些约束。但是实际中,你很难预测test case到底想要怎样的约束,所以写test case的工程师会把约束写进新的派生类中。
使用内联约束 (randomize with{} 或 `uvm_do_with)对于相对简单的约束(如transaction的数目、简单的分布等)是可行的。但是对于复杂的约束类型,如果还使用这种方法的话,就比较难处理了。你需要精心地迭代(如foreach)约束或者在post_randomize方法中更新历史信息。
现有的约束分层技术
为说明我们提出的约束方法,我们从一个简单的transaction(addr_txn)开始分析,
这个transaction包括地址和数据大小(字节数)。从基类中我们派生得到read/write transaction (rw_txn):
我们可以在派生类中添加约束,对地址进行约束:
虽然这两种技术都可用,但是我们需要更多的约束时,派生类和内嵌的约束就变得非常难以管理了。很容易会想到,如果有一种方法把约束封装进一个可复用的模块就好了。
分层约束容器
SystemVerilog提供了层次化的约束机制。一个类可以声明一个对象成员(即类的实例)为“rand”类型,当顶层对象随机化后,底层的对象也会被随机化。顶层和底层的随机变量和约束同时定义生成。
采用这种机制来解决我们的问题,我们把一组约束移入单独的类中,并在base transaction中,为带约束的类声明随机的类句柄。这时,当顶层的transaction随机化时,子类实例也同时被随机化。然而这时我们有一个问题要解决:约束类有了它们自己独立的“addr” 和“size” ,它们是独立随机化的,而我们需要保证他们有相同的值。解决这个问题的一个方法是,在顶层添加额外的“等式约束”,以确保每个类中的“addr”和“size”成员有相同的值。这种方式当然是可行的,但是我们需要顶层约束知道哪种里层约束正在被使用。我们展示一种更好的解决方式。
在顶层实现多约束类还是比较容易的,具体可以从一个普通基类中派生所有的约束类,或者使用队列来包含任意数量的约束类。使用foreach来约束“addr”和“size”成员,可以在任意数量的约束容器中添加等式约束。
但是,保持顶层等式约束和约束对象同步是一个苦差事,例如,如果我们想要使用rw_txn里的“op”成员(READ 或 WRITE)添加一个新约束,我们需要同步顶层约束,使其支持新的成员。即使一个约束类中没有对某个顶层成员进行约束,约束类仍要对其进行声明,这样顶层等式约束才能有效。
消除顶层等式约束
 为消除顶层等式约束,我们可以这样做,在每一个约束类中声明一个对象的句柄,这个句柄将包含要被随机化的顶层对象的索引,这样我们就可以访问所有的顶层对象成员,具体见图六。约束基类(addr_constraint_base)包含一个和顶层对象(addr_txn)一样的变量“item”。
另外,在随机化之前,还需要设置“item”变量指向顶层对象。如下所示,在pre_randomize方法中进行实现。
随机策略类
在我们的实例中,约束类还有一个硬编码类型。通过定义参数化基类,可以使随机化更通用一些。这个参数化基类带有指示被随机化的顶层对象的类型参数。我们还为设置item句柄而添加了set_item函数,我们称这种新的容器类型为“随机化策略”
把多个随机策略和单个对象捆绑在一起也不太难,我们可以创建一个包含了策略队列的policy_list类,set_item方法要为列表中所有的策略设置item句柄。所以,这就允许调用顶层set_item方法,递归设置item句柄。使用这种方法,我们可以把所有值得关注的策略放在一起,并通过一次赋值传送这些策略。
这些策略列表可以装载任意层次的约束,例如,我们可能想要把默认的地址映射规则(即允许和禁止地址),和一个默认的策略对象捆绑,随后将其添加到更高层次的策略对象里。
应用
既然我们已经有了合适的方式封装约束,我们就可以创建一些较为通用的约束策略了,我们关于地址范围的例子目前已经有了硬编码地址范围,我们可以创建可配置的许可/禁止地址策略:
 在UVM中的应用
这些技术可以很容易应用于UVM环境。我们只需要从uvm_sequence_item得到我们现有的事务类,并在随机化sequence_item之前,在uvm_sequence中设置随机化策略。将原本一步的`uvm_do拆成这样三个步骤:`uvm_create、设置约束策略、和`uvm_rand_send。
为了简化这个过程,我们可以创建一个新的宏:“uvm_do_with_policy”。这个宏结合上文所述的三个步骤,并允许把策略对象作为一个附加的宏声明传递。
另一种可行的方式是使用UVM配置数据库。顶层序列将默认策略对象嵌入config_db中。
写入config_db时,我们使用顶层序列完整的层次名,并加上一个 “.*”通配符。从config_db读取数据时,我们使用sequence_item的完整的层次名。这种方案可以让我们为序列顶层的所有item设置一个默认策略,如果要覆盖默认策略,只需要添加有更详细路径的附加config_db语句。
 结果
对本文提到的技术使用简单的UVM环境进行验证,每种技术方法随机化一个transaction 10000次,总运行时间从testbench 内部测得。为了更科学,数据从三大SystemVerilog仿真器中的两个仿真器收集。
  • 使用内联约束(randomize with{})和在类里规定约束,运行时间基本相等
  • 带“等式约束”的策略类运行时间最长,要处理的约束太多,所以这种方法就比较慢。
  • 对比在随机化前设置约束策略,从config_db中获取约束策略使运行时间增加了约16%

    结论
    本文提供了用于SystemVerilog约束分层的技术。使用随机策略类的方法,把不同类型的约束混合匹配进一个被随机化的对象中,方便快捷。这种技术还可以很容易的应用于UVM环境。而且鉴于随机策略可复用,不同的测试测试场景可以采用这些策略规则的不同组合,文中方法确实是一种比较不错的方法。

点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 253

    粉丝
  • 25

    好友
  • 33

    获赞
  • 45

    评论
  • 访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-4-27 10:06 , Processed in 0.015949 second(s), 12 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部