編 者 按
之前在玩FPGA時(shí),對(duì)于一個(gè)系統(tǒng)工程,當(dāng)邏輯電路設(shè)計(jì)完成之后,一般會(huì)先拿給Vivado/Quartus先去跑一般綜合,然后去獲取所有的跨時(shí)鐘路徑,在ASIC里,基本也是拿EDA工具去分析獲取。今兒個(gè)搞個(gè)小demo,看在SpinalHDL當(dāng)設(shè)計(jì)做完后,如何一鍵提取整個(gè)工程里所有的跨時(shí)鐘路徑。
這個(gè)Demo會(huì)依賴spinal.lib.tools.DataAnalyzer,此次測試在1.9.3版本上進(jìn)行。
獲取跨時(shí)鐘路徑
得益于SpinalHDL對(duì)時(shí)鐘域嚴(yán)格的劃分,在SpinalHDL中,如果存在跨時(shí)鐘域,那么必須顯示的添加Tag進(jìn)行標(biāo)示,否則在生成電路時(shí)將會(huì)直接報(bào)錯(cuò)。以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 = newBundle {
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 <- 1until finalBufferDepth) {
buffers(i) := buffers(i - 1)
buffers(i).addTag(crossClockBuffer)
}
io.dataOut := buffers.last
}
因?yàn)槭强鐣r(shí)鐘域,所以buffers(0)必須添加Tag標(biāo)簽crossClockDomain,那么基于此,我們完全可以找出整個(gè)工程里的所有跨時(shí)鐘路徑的源節(jié)點(diǎn),目的節(jié)點(diǎn)。
下面給出一個(gè)demo:
importspinal.core._
importspinal.lib._
importspinal.lib.tools.DataAnalyzer
importscala.collection.mutable.ArrayBuffer
object Test extendsApp {
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 {
casesignal: 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(newStreamFifoCC[UInt](UInt(8bits), 512, ClockDomain.external("clka"), ClockDomain.external("clkb")))
reportCrossClockSignal(report.toplevel)
val report1 = SpinalSystemVerilog(newStreamCCByToggle[Stream[UInt]](Stream(UInt(8bits)), ClockDomain.external("clka"), ClockDomain.external("clkb")))
reportCrossClockSignal(report1.toplevel)
}
在這個(gè)Demo中,采用了StreamFifoCC以及StreamCCByToggle來做演示。兩個(gè)模塊的跨時(shí)鐘域路徑分析結(jié)果如下:
StreamFifoCC
srcreg:popCC_ptrToPushhierarchy:toplevelsrcclock:clkb_clkdstreg:buffers_0hierarchy:toplevel.popToPushGray_bufferccdstclock:clka_clk
srcreg:pushCC_pushPtrGrayhierarchy:toplevelsrcclock:clka_clkdstreg:buffers_0hierarchy:toplevel.pushToPopGray_bufferccdstclock:clkb_clk
StreamCCByToggle
srcreg:pushArea_data_validhierarchy:toplevelsrcclock:clka_clkdstreg:popArea_stream_rData_validhierarchy:topleveldstclock:clkb_clk
srcreg:pushArea_data_readyhierarchy:toplevelsrcclock:clka_clkdstreg:popArea_stream_rData_readyhierarchy:topleveldstclock:clkb_clk
srcreg:pushArea_data_payloadhierarchy:toplevelsrcclock:clka_clkdstreg:popArea_stream_rData_payloadhierarchy:topleveldstclock:clkb_clk
srcreg:popArea_hithierarchy:toplevelsrcclock:clkb_clkdstreg:buffers_0hierarchy:toplevel.outHitSignal_bufferccdstclock:clka_clk
srcreg:pushArea_targethierarchy:toplevelsrcclock:clka_clkdstreg:buffers_0hierarchy:toplevel.pushArea_target_bufferccdstclock:clkb_clk
完全符合預(yù)期~
getCrossClockFanIn
該函數(shù)的作用用于針對(duì)指定信號(hào)其所有的扇入驅(qū)動(dòng)中不在一個(gè)時(shí)鐘域的寄存器。輸入參數(shù)有兩個(gè):
-
signal:待搜索信號(hào)
-
clockDomain:signal信號(hào)對(duì)應(yīng)的時(shí)鐘域
這里面存在一個(gè)遞歸調(diào)用,通過調(diào)用DataAnalyzer中的getFanIn,獲取signal信號(hào)的所有扇入,對(duì)于其扇入信號(hào)類型,存在以下三種情況:
-
扇入類型為寄存器,和signal不屬于同一個(gè)時(shí)鐘域,那么將信號(hào)添加到匹配列表中
-
扇入類型為寄存器,但和signal屬于同一個(gè)時(shí)鐘域,則不做任何處理
-
扇入類型為非寄存器,那么遞歸調(diào)用getCrossClockFanIn進(jìn)一步搜索
reportCrossClockSignal
該函數(shù)的作用是對(duì)于傳入的toplevel模塊,會(huì)便利搜索其中所有帶有crossClockDomain標(biāo)簽的信號(hào),通過調(diào)用getCrossClockFanIn進(jìn)一步得到其相應(yīng)的跨時(shí)鐘域路徑。在得到跨時(shí)鐘域路徑后,這里僅做了信息打印,讀者有需要可自行擴(kuò)展,比如生成針對(duì)單bit信號(hào)的約束,對(duì)于多比特信號(hào)的約束等。
寫在最后
這里僅能針對(duì)SpinalHDL代碼中的電路進(jìn)行分析。
-
FPGA
+關(guān)注
關(guān)注
1629文章
21736瀏覽量
603387 -
邏輯電路
+關(guān)注
關(guān)注
13文章
494瀏覽量
42621 -
時(shí)鐘
+關(guān)注
關(guān)注
10文章
1733瀏覽量
131481 -
邏輯設(shè)計(jì)
+關(guān)注
關(guān)注
1文章
41瀏覽量
11574 -
Vivado
+關(guān)注
關(guān)注
19文章
812瀏覽量
66538
原文標(biāo)題:一鍵獲取邏輯設(shè)計(jì)中的所有跨時(shí)鐘路徑
文章出處:【微信號(hào):Spinal FPGA,微信公眾號(hào):Spinal FPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論