连线对不对,仿真靠边站,让代码自己做

描述

✎ 编 者 按   

    最近做些RTL代码连线正确性检查的一些事情,在对于Verilog代码进行连接性检查,只能依赖仿真的形式,过程深感不便。且在一个大型工程里,比如检测一个fifo的overflow是否都连接到了debug接口上通过仿真就是一个很耗时的事情。作为SpinalHDL的坚定支持者,这种类型的工作交给代码自己做,在SpinalHDL里so easy。

》连接性检查    所谓的连接性检查,无非就是A、B两个信号,判断下两者之间有没有驱动关系。比如说我们认为A应该驱动B,在仿真里Force A为一个值,然后delay一段时间看B是否有变更为对应的值。如果针对某一类连线规则,在Verilog里通过这种仿真的形式一根根进行检查是一个很耗时的事情。然而在SpinalHDL里,采用LatencyAnalysis,搞什么仿真,轻轻松几行代码定义下规则就可以搞定了。    如上面的判断A是否有驱动B,仅需通过下面的一行代码即可:
LatencyAnalysis(A,B)

    其会自动分析A到B之间的路径并返回其寄存器级数。即使跨时钟域也能轻松搞定。

》Example

    通过在代码里制定连接性检查规则,根本不需要仿真,生成RTL代码的时候就可以直接顺便把这件事给做了。以下面的例子为例:

import spinal.core._
import spinal.lib._

object connectCheck{
  def fifoPortCheck(componecnt:Component,portBoolean={
    for (elem <- componecnt.children) {
      elem match {
        case fifo: StreamFifo[BaseType]=> {
          println(s"Start Check ${componecnt.getName()} ${fifo.getName()} ${fifo.io.pop.valid.getName} to ${port.getName()} connection")
          LatencyAnalysis(fifo.io.pop.valid,port)>=0
        }
        case _ => true
      }
      fifoPortCheck(elem,port)
    }
    true
  }
}

case class test1() extends Component{
  val io=new Bundle{
    val data0=out Bool()
  }
  noIoPrefix()
  val fifoInst=Array.fill(10)(StreamFifo(UInt(8 bits),16))
  fifoInst.foreach(fifo=>{
    fifo.io.push.valid.clear()
    fifo.io.push.payload.clearAll()
    fifo.io.pop.ready.clear()
  })
  val test2Inst=test2()
  io.data0:=fifoInst.map(_.io.pop.valid).reduce(_|_)|test2Inst.io.data0

  connectCheck.fifoPortCheck(this,io.data0)
}

case class test2() extends Component{
  val io=new Bundle{
    val data0=out Bool()
  }
  noIoPrefix()
  val fifoInst=Array.fill(10)(StreamFifo(UInt(8 bits),16))
  fifoInst.foreach(fifo=>{
    fifo.io.push.valid.clear()
    fifo.io.push.payload.clearAll()
    fifo.io.pop.ready.clear()
  })
  io.data0:=fifoInst.map(_.io.pop.valid).reduce(_|_)
}

    这里test2里面定义了10个StreamFifo,所有fifo的pop.valid通过或的形式连接到io.data0上。然后在test1里例化了test2和10个StreamFifo,将10个StreamFifo的pop.valid和test2的data0通过或的形式驱动io.data0。

    假定我们在设计里定义如下规则:

  • test1下面的所有模块的Stream Fifo的pop.valid都需要连接到test1的输出端口io.data0上。

    这里我们定义了一个fifoPortCheck函数用于做这件事,它会遍历指定component下面的所有StreamFifo,通过LatencyAnalysis判断其pop.valid是否与指定port之间是否存在连接关系。

    如此,在生成代码时便会有下面的检查信息显示:

寄存器

    这不比仿真来的快的多么,也无需发现错误自己挨个去找各模块的负责人,只需统一制定好规则,每个人自己就能检查,喝口水的功夫~。

    现在我们把test1里面的test2Inst的data0拿掉不让他驱动test1的io.data0:

case class test1() extends Component{
  val io=new Bundle{
    val data0=out Bool()
  }
  noIoPrefix()
  val fifoInst=Array.fill(10)(StreamFifo(UInt(8 bits),16))
  fifoInst.foreach(fifo=>{
    fifo.io.push.valid.clear()
    fifo.io.push.payload.clearAll()
    fifo.io.pop.ready.clear()
  })
  val test2Inst=test2()
  io.data0:=fifoInst.map(_.io.pop.valid).reduce(_|_)

  connectCheck.fifoPortCheck(this,io.data0)
}

    生成RTL代码时就会报错:

寄存器

    告知test2Inst中的StreamFifo并没有驱动test1中的io.data0,规则不过,根本不让你生成Verilog代码,仿真靠边站~

    效率就是这么提升的~

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分