来看看Pipeline中的flush操作

描述

编 者 按   

来看看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。

 

审核编辑:汤梓红

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

全部0条评论

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

×
20
完善资料,
赚取积分