编 者 按
来看看Pipeline中的flush操作
flush
在Stage中,对于Flush有提供这两个函数:
def flushIt() : Unit = flushIt(ConditionalContext.isTrue) def flushIt(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。
def isFlushed : 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 { case null => clFlushNext(l) && clFlushNextHit(l) case _ => flush || clFlushNext(l) && clFlushNextHit(l) } flushNext = l.alwasContainsSlaveToken match { case true => null case false => 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 { case true => null case false => 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.valid clearWhen(s.internals.arbitration.isFlushingRoot)
也就意味着output.valid会立即清空。
而在处理InterConnection时,会用到上面的clFlush:
val area = 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:
case class Test5() extends Component{ val io=new Bundle{ val data_in=slave(Flow(UInt(8 bits))) val data_out=master(Flow(UInt(8 bits))) val cond=in Bool() } noIoPrefix() val A=Stageable(UInt(8 bits)) val pip=new Pipeline{ val stage0=new Stage{ internals.input.valid:=io.data_in.valid A:=io.data_in.payload } val stage1=new Stage(Connection.M2S()){} val stage2=new Stage(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。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !