編 者 按
來看看Pipeline中的flush操作
flush
在Stage中,對于Flush有提供這兩個函數:
defflushIt(): Unit = flushIt(ConditionalContext.isTrue) defflushIt(cond : Bool, root : Boolean = true): Unit = { internals.request.flush += cond if(root) internals.request.flushRoot += cond }
可以看出,調用flush函數,會牽涉到internals.request中的fulsh以及flushRoot兩個元素:
val flush = ArrayBuffer[Bool]() val flushRoot = ArrayBuffer[Bool]()
那么來分別看下這兩個元素在Pipeline的build函數中都起了什么作用。
在build函數中,對于處于pipeline中沒有驅動其他Stage的Stage,會調用propagateRequirements函數:
for(end<- connectionsWithoutSinks){ ??propagateRequirements(end) }
同時,build函數中有定義:
val clFlush = mutable.LinkedHashMap[ConnectionLogic, Bool]()
在函數propagateRequirements中:
var flush= stage.internals.request.flush.nonEmpty generate orR(stage.internals.request.flush)
也就意味著如果當前stage中若flush非空,則會將flush中的所有信號進行或操作得到一個flush信號。
(stage.internals.arbitration.isFlushed, flush) match { case(null, null) => case(x, null) =>stage.isFlushed := False case(_, x) =>stage.isFlushed := flush }
若flush非空,那么就會驅動賦值給stage中的internals.arbitration.
isFlushed。
defisFlushed:Bool = { if(internals.arbitration.isFlushed == null) internals.arbitration.isFlushed = ContextSwapper.outsideCondScope(Bool()) internals.arbitration.isFlushed }
對于驅動當前stage的Connection Logic,也會對flush有進行檢測:
c.logics.reverseIterator.foreach{ l => clFlush(l) = flush clFlushNext(l) = flushNext clFlushNextHit(l) = null if(flushNext != null){ clFlushNextHit(l) = Bool() flush = flush match { casenull=> clFlushNext(l) && clFlushNextHit(l) case_ => flush || clFlushNext(l) && clFlushNextHit(l) } flushNext = l.alwasContainsSlaveToken match { casetrue=> null casefalse=> clFlushNext(l) && !clFlushNextHit(l) } } if(flush != null) c.m.flushIt(flush, false) if(flushNext != null) c.m.flushNext(flushNext) clThrowOne(l) = throwOne clThrowOneHit(l) = null if(throwOne != null){ clThrowOneHit(l) = Bool() throwOne = l.alwasContainsSlaveToken match { casetrue=> null casefalse=> clThrowOne(l) && !clThrowOneHit(l) } } }
我們著重關注和flush相關的邏輯。首先會講flush注冊到驅動當前Stage的Conntection Logic中的clFlush中:
clFlush(l) = flush
此處flushNext我們先不用管,為null。而flush為非空,故對于驅動當前Stage的master側Stage,會調用其flush函數以flush為變量為其注冊flush動作(注意,root參數傳輸的為false)。也就具備了前向傳播的特性:
c.m.flushIt(flush, false)
隨后通過遞歸,flush動作也就回一直向前傳播:
for(m <- stageMasters(stage)){ ??if(stage.internals.arbitration.propagateReady) m.internals.arbitration.propagateReady = true ??propagateRequirements(m) }
在每一級的Stage關系里,默認情況下:
s.output.valid := s.input.valid
而當flushRoot非空時,則會:
if(s.internals.request.flushRoot.nonEmpty) s.output.validclearWhen(s.internals.arbitration.isFlushingRoot)
也就意味著output.valid會立即清空。
而在處理InterConnection時,會用到上面的clFlush:
valarea = l.on(m, s, clFlush(l), clFlushNext(l), clFlushNextHit(l), clThrowOne(l), clThrowOneHit(l))
我們以M2S為例,其中定義了:
if (flush!= null&& !flushPreserveInput) s.valid clearWhen(flush)
s.valid為寄存器,也就意味著當flush為true時,s.valid將會在下一拍驅動為0,即下一級的Stage的input.valid將會在下一拍清零。
功能總結
結合Pipeline中的源代碼,可以總結下flushIt的作用。
調用flushIt函數,會想request.flush中添加cond,若root 為true,則會向request.flushRoot中同時添加cond。
request.flush作用:
對StageN調用flushIt,在pipeline.build函數中會向其所有的前級Stage中同樣添加調用相應的flushIt函數(root為false)
request.flush主要在conntecion Logic中起作用,用于清除s.valid,即下一級的input.valid。
request.flushRoot的作用:
request.flushRoot用于清除當前級的output.valid
默認情況下,每一級的output.valid:=input.valid
當flushRoot.orR為True時,會立即清除當前Stage的output.valid
flushRoot中的元素并不會向前級傳輸
flushRoot的作用區分:
當在StageN調用flushIt時如果希望cond為true時下一拍不希望Stage(N+1)input.valid拉起,則需將root設置為true。否則因為output.valid:=input.valid,stageN的output.valid會驅動下一級的input.valid為True(之所以前向傳輸調用flushIt時root=false,原因在于flush會作用于Connection Logic確保下一拍valid清零)。
example
給一個簡單的example:
caseclassTest5() extendsComponent{ val io=newBundle{ val data_in=slave(Flow(UInt(8bits))) val data_out=master(Flow(UInt(8bits))) val cond=inBool() } noIoPrefix() val A=Stageable(UInt(8bits)) val pip=newPipeline{ val stage0=newStage{ internals.input.valid:=io.data_in.valid A:=io.data_in.payload } val stage1=newStage(Connection.M2S()){} val stage2=newStage(Connection.M2S()){ io.data_out.valid:=internals.output.valid io.data_out.payload:=A this.flushIt(io.cond) } } }
這里在stage2調用flushIt函數,當io.cond為true時,整個流水線都將會清空。而由于root默認為true,故io.cond為true時,io.data_out.valid會立即為0,即等效于:
io.data_out.valid:=internals.output.valid&(~io.cond)
如果root設置為false,那么io.cond為true時io.data_out.valid仍可能為True。
審核編輯:湯梓紅
-
函數
+關注
關注
3文章
4327瀏覽量
62573 -
Pipeline
+關注
關注
0文章
28瀏覽量
9361 -
FLUSH
+關注
關注
0文章
4瀏覽量
5426
原文標題:pipeline高端玩法(七)—flush
文章出處:【微信號:Spinal FPGA,微信公眾號:Spinal FPGA】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論