十二 · 2023年11月24日

pipeline高端玩法—haltIt(九)

✎ 编 者 按 

来看下Pipeline中HaltIt的用法

HaltIt

看名字,就基本能猜到这个函数的大体功能是流水线暂停。

在Stage中,流水线暂停提供了这么几个API:

def haltIt()(implicit loc: Location) : Unit = haltIt(ConditionalContext.isTrue)def haltIt(cond : Bool)(implicit loc: Location) : Unit = internals.request.halts += nameFromLocation(CombInit(cond), "haltRequest")def haltWhen(cond : Bool)(implicit loc: Location) : Unit = haltIt(cond)

三个API最终所实现的都是往internals.request.halts中添加cond条件。那么就看下request.halts在Pipeline构建时所起的作用。

首先,在进行 connectionsWithoutSinks(没有驱动其他级Stage)往前遍历的函数propagateRequirements中:

if(stage.request.halts.nonEmpty){    stage.arbitration.propagateReady = true    stage.isReady //Force creation}

可以看到,如果stage中的internals.request.halts非空,这里做了两件事:

  • stage.arbitration.propagateReady设置为true,即需向前级Stage传递Ready信号
  • 为本级创建input.ready信号

随后在propagateRequirements中的代码片段:

stageDriver.get(stage) match {        case Some(c : ConnectionModel) => {          if(c.s.arbitration.propagateReady && c.m.output.ready == null){            c.m.output.ready = Bool()            if(c.m.input.ready == null){              c.m.input.ready = Bool()            }          }

这里在处理当前Stage中的ConnectionLogic时,因为当前stage.arbitration.propagateReady为true,如果驱动当前Stage的Master Stage的output.ready为空,那么这里就会确保Master Stage中具备input.ready以及output.ready,确保上级Stage具备这种握手机制。

而后在该函数中的递归调用:

for(m <- stageMasters(stage)){    if(stage.internals.arbitration.propagateReady) m.internals.arbitration.propagateReady = true    propagateRequirements(m)}

这里如果当前stage如果存在stage.arbitration.propagateReady为true,那么也会设置其Master Stage的.arbitration.propagateReady为true,通过递归调用,确保整个链路上ready信号一直向前传播,即确保反压一路到底。

最后,在处理Stage Internal Connection阶段时:

if(s.request.halts.nonEmpty){    val doHalt = s.request.halts.orR    when(doHalt){        s.input.ready := False        s.output.valid := False    }}

如果当前Stage中request.halts中条件满足,那么当前stage中的output.valid,input.ready信号将会统一拉低,从而暂停向下级传输。

Example

case class Test8() extends Component{  val io=new  Bundle{    val data_in=slave(Stream(UInt(8 bits)))    val data_out=master(Stream(UInt(8 bits)))    val cond=in Bool()  }  noIoPrefix()  val A=Stageable(UInt(8 bits))  val pip=new Pipeline{    val stage0=new Stage{      this.driveFrom(io.data_in)      A:=io.data_in.payload    }    val stage1=new Stage(Connection.M2S()){    }    val stage2=new Stage(Connection.M2S()){      io.data_out.valid:=this.internals.output.valid      io.data_out.payload:=A      internals.output.ready=Bool()      this.haltIt(io.cond)      internals.output.ready:=io.data_out.ready      this.internals.arbitration.propagateReady=true    }  }  pip.build()}

这里给出了一个haltIt的example。在staeg2阶段,如果cond为true,那么则流水线暂停。

这里需注意的是这里将stage2的output.ready由io.data_out.ready信号进行驱动,但output.ready信号是默认不会创建的,故这里显示创建internals.output.ready为Bool类型电路对象。

☆ END ☆

作者:玉骐
原文链接:Spinal FPGA
微信公众号:
 title=

推荐阅读

更多SpinalHDL技术干货请关注[Spinal FPGA]欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
1581
内容数
133
用SpinalHDL提升生产力
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息