十二 · 2021年11月12日

除了看波形,还能做点儿啥

要问做逻辑的什么看的最久,那一定是波形吧。那除了看波形,还能做点儿其他的么?

调试“三十六计”

作为逻辑开发者,仿真是一个永远跑不掉的话题。尽管说严格来讲设计和验证是分离的,但对于FPGA开发来讲,即便是大厂也很少配备专门的逻辑验证人员来支持你的工作。无论是单元级仿真还是系统级仿真,那些年我们常用到仿真调试手段首推的估计就是看波形了。但老实讲,小的模块或者小的case看看波形还好,但如果是比较大的模块或case需要很长的时间来跑的话那么追踪波形对我个人来讲还是很废眼神的~

那么除了查看波形,我们常用的仿真调试手段无外乎在待仿真测试逻辑里添加打印添加SVA了。对于添加打印,在之前通过verilog/systemVerilog搬砖时是时常干的事情,而SVA在上学的那会儿倒是看过下面这本书:

e12a1b9ea4031b0c258be1e09a064b8e.jpg    当时在知乎上做了两篇笔记,感兴趣的可以通过文末的“阅读原文”翻看。但老实讲,工作中SVA虽然有用到,但用的确实不多。 至于其他的调试方式也只是或多或少的用一些了。

那么如今转到SpinalHDL,这些手段是否还能用呢?

Assertion

与SystemVerilog中相似,SpinalHDL中也提供Assertion功能,其关键字也为assert:

: Bool, message : String = null, severity: AssertNodeSeverity = Error)
assert(assertion: Bool, message: Seq[Any], severity: AssertNodeSeverity)
  • assertion:断言条件
  • message:断言失败时显示信息,可以是字符串或者是Seq。
  • severity:断言等级:

2dcc354e8bf9ef2d65892857f4fd647f.png

来看一个demo:

80180d44e854c41bb0e743c6d29b3332.png

这里放置了两个assert,分别使用了两种assert的使用方式。message中放置Seq时可以显示更多的提示信息。

要知道即便我们是采用SpinalHDL,在仿真的时候还是要生成Verilog文件交给仿真器去执行的。那看下生成的RTL代码:

e4c856306d2791ea6bd75c5fad2d56ee.png

可以看到,在SpinalHDL中,对于SVA中的立即断言和并发断言,其只支持并发断言。而且会生成额外逻辑用来支持断言,而且在复位期间是不做断言检查的。

report

   
SpinalHDL中提供了report方法用于在逻辑中显示打印信息:

def report(message: String)   = assert(False, message, NOTE)def report(message: Seq[Any]) = assert(False, message, NOTE)
def report(message: String,   severity: AssertNodeSeverity) = assert(False, message, severity)def report(message: Seq[Any], severity: AssertNodeSeverity) = assert(False, message, severity)

可以看到,report的底层实现是基于assert来实现的,且默认断言失败,故而信息会一直打印。像上面的dmeo我们可以添加下面的打印信息:

report(Seq("data0:",io.data0,"\tdata1:",io.data1,"\tsum:",io.sum),WARNING)

在生成的RTL代码中会有:

17c059253500536d9b245eb3076e19d9.png

同样不出意外,在复位期间将不会打印任何信息。

Formal

针对SVA的支持,SpinalHDL提供了部分支持。在SpinalHDL-Doc中给出了下面的这个Demo:

29d02d5db85d408a392d8387e6a0bfcc.png

object MyToplevelSystemVerilogWithFormal {
 def main(args: Array[String]) {
   val config = SpinalConfig(defaultConfigForClockDomains = ClockDomainConfig(resetKind=SYNC, resetActiveLevel=HIGH))
    config.includeFormal.generateSystemVerilog(new TopLevel())
  }
}

但这个demo有几个问题是:

  1. 使用GenerationFlags.formal及includeFormal时如果我们的代码在GenerationFlags外围如果有使用assert或者report时,GenerationFlags.formal会将其屏蔽掉,在仿真时不起作用。
  2. initstate()在verilator中不支持。

针对上面的问题,可以采用:

  1. 采用GenerationFlags.simulation和includeSimulation替代GenerationFlags.formal及includeFormal。
  2. 如果要在复位期间添加sva,那么通过clockDomain.isResetActive替换initstate()

当在生成Verilog时不添加includeSimulation,那么GenerationFlags.simulation所包含的内容将不会生成在Verilog中,从而能够提供一个干净的代码。   

手册中给出了支持的SVA:

0b0e023f45d5ec5e801c68bbdcfa27a5.png

但具体还是要看仿真器是否支持,毕竟verilator和vcs这些在功能上还是有一些差距。

END

作者:玉骐
原文链接:https://mp.weixin.qq.com/s/JUmKDhcLcAnFZ4AyQS\_DMQ
微信公众号:
 title=

推荐阅读

更多SpinalHDL技术干货请关注Spinal FPGA专栏。
推荐阅读
关注数
1581
内容数
133
用SpinalHDL提升生产力
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息