编 者 按
之前在玩FPGA时,对于一个系统工程,当逻辑电路设计完成之后,一般会先拿给Vivado/Quartus先去跑一般综合,然后去获取所有的跨时钟路径,在ASIC里,基本也是拿EDA工具去分析获取。今儿个搞个小demo,看在SpinalHDL当设计做完后,如何一键提取整个工程里所有的跨时钟路径。
这个Demo会依赖spinal.lib.tools.DataAnalyzer,此次测试在1.9.3版本上进行。
获取跨时钟路径
得益于SpinalHDL对时钟域严格的划分,在SpinalHDL中,如果存在跨时钟域,那么必须显示的添加Tag进行标示,否则在生成电路时将会直接报错。以BufferCC为例:
class BufferCC[T <: Data](val dataType: T, init : => T, val bufferDepth: Option[Int], val randBoot : Boolean = false) extends Component {
def getInit() : T = init
val finalBufferDepth = BufferCC.defaultDepthOptioned(ClockDomain.current, bufferDepth)
assert(finalBufferDepth >= 1)
val io = new Bundle {
val dataIn = in(cloneOf(dataType))
val dataOut = out(cloneOf(dataType))
}
val buffers = Vec(Reg(dataType, init),finalBufferDepth)
if(randBoot) buffers.foreach(_.randBoot())
buffers(0) := io.dataIn
buffers(0).addTag(crossClockDomain)
for (i <- 1 until finalBufferDepth) {
buffers(i) := buffers(i - 1)
buffers(i).addTag(crossClockBuffer)
}
io.dataOut := buffers.last
}
因为是跨时钟域,所以buffers(0)必须添加Tag标签crossClockDomain,那么基于此,我们完全可以找出整个工程里的所有跨时钟路径的源节点,目的节点。
下面给出一个demo:
import spinal.core._
import spinal.lib._
import spinal.lib.tools.DataAnalyzer
import scala.collection.mutable.ArrayBuffer
object Test extends App {
def getCrossClockFanIn(signal: BaseType, clockDomain: ClockDomain): ArrayBuffer[BaseType] = {
val signalList = ArrayBuffer[BaseType]()
for (srcSignal <- DataAnalyzer.toAnalyzer(signal).getFanIn) {
if (srcSignal.isReg) {
if (srcSignal.clockDomain != clockDomain) {
signalList.append(srcSignal)
}
} else {
signalList ++= getCrossClockFanIn(srcSignal, clockDomain)
}
}
signalList
}
def reportCrossClockSignal(toplevel: Component) = {
toplevel.walkComponents { c =>
c.dslBody.walkDeclarations {
case signal: BaseType => {
if (signal.hasTag(crossClockDomain)) {
val fanInRegList = getCrossClockFanIn(signal, signal.clockDomain)
for (reg <- fanInRegList) {
println(s"src reg:${reg.getDisplayName()} hierarchy:${reg.component.getPath(".")} src clock:${reg.clockDomain.clock.getDisplayName()} dst reg:${signal.getDisplayName} hierarchy:${signal.component.getPath(".")} dst clock:${signal.clockDomain.clock.getDisplayName()}")
}
}
}
case _ =>
}
}
}
val report = SpinalSystemVerilog(new StreamFifoCC[UInt](UInt(8 bits), 512, ClockDomain.external("clka"), ClockDomain.external("clkb")))
reportCrossClockSignal(report.toplevel)
val report1 = SpinalSystemVerilog(new StreamCCByToggle[Stream[UInt]](Stream(UInt(8 bits)), ClockDomain.external("clka"), ClockDomain.external("clkb")))
reportCrossClockSignal(report1.toplevel)
}
在这个Demo中,采用了StreamFifoCC以及StreamCCByToggle来做演示。两个模块的跨时钟域路径分析结果如下:
StreamFifoCC
src reg:popCC_ptrToPush hierarchy:toplevel src clock:clkb_clk dst reg:buffers_0 hierarchy:toplevel.popToPushGray_buffercc dst clock:clka_clk
src reg:pushCC_pushPtrGray hierarchy:toplevel src clock:clka_clk dst reg:buffers_0 hierarchy:toplevel.pushToPopGray_buffercc dst clock:clkb_clk
StreamCCByToggle
src reg:pushArea_data_valid hierarchy:toplevel src clock:clka_clk dst reg:popArea_stream_rData_valid hierarchy:toplevel dst clock:clkb_clk
src reg:pushArea_data_ready hierarchy:toplevel src clock:clka_clk dst reg:popArea_stream_rData_ready hierarchy:toplevel dst clock:clkb_clk
src reg:pushArea_data_payload hierarchy:toplevel src clock:clka_clk dst reg:popArea_stream_rData_payload hierarchy:toplevel dst clock:clkb_clk
src reg:popArea_hit hierarchy:toplevel src clock:clkb_clk dst reg:buffers_0 hierarchy:toplevel.outHitSignal_buffercc dst clock:clka_clk
src reg:pushArea_target hierarchy:toplevel src clock:clka_clk dst reg:buffers_0 hierarchy:toplevel.pushArea_target_buffercc dst clock:clkb_clk
完全符合预期~
getCrossClockFanIn
该函数的作用用于针对指定信号其所有的扇入驱动中不在一个时钟域的寄存器。输入参数有两个:
signal:待搜索信号
clockDomain:signal信号对应的时钟域
这里面存在一个递归调用,通过调用DataAnalyzer中的getFanIn,获取signal信号的所有扇入,对于其扇入信号类型,存在以下三种情况:
扇入类型为寄存器,和signal不属于同一个时钟域,那么将信号添加到匹配列表中
扇入类型为寄存器,但和signal属于同一个时钟域,则不做任何处理
扇入类型为非寄存器,那么递归调用getCrossClockFanIn进一步搜索
reportCrossClockSignal
该函数的作用是对于传入的toplevel模块,会便利搜索其中所有带有crossClockDomain标签的信号,通过调用getCrossClockFanIn进一步得到其相应的跨时钟域路径。在得到跨时钟域路径后,这里仅做了信息打印,读者有需要可自行扩展,比如生成针对单bit信号的约束,对于多比特信号的约束等。
写在最后
这里仅能针对SpinalHDL代码中的电路进行分析。
全部0条评论
快来发表一下你的评论吧 !