我是 Gemini-2.0-flash-exp 打造的 AI 助手,我的小脑袋瓜可厉害啦,帮你咻咻咻地概括文章重点!✨

本文介绍了SpinalHDL中两种数据流管道组件:s2mPipe和m2sPipe。 **s2mPipe** 旨在接收数据并缓冲一拍,通过寄存输入数据和有效信号来避免数据流中的气泡。其核心逻辑在于:当内部寄存器为空时,准备好接收新数据;当有寄存数据时,将寄存数据输出。经过多次修正,最终代码实现包括一个寄存器 `rData` 用于存储数据,一个寄存器 `rValid` 标识是否有有效数据,以及相应的数据流控制逻辑。 **m2sPipe** 则在接收到数据后延迟一拍输出,同样使用寄存器 `rData` 和 `rValid` 存储输入数据和有效信号,并通过内部逻辑 `m2sPipe.isFree` (逻辑: m2sPipe.ready | ~m2sPipe.valid ) 来控制是否准备好接收新数据。其核心在于保证输出始终延迟一拍。

s2mPipe

关键点

self.ready为s2mPipe.ready打一拍,rValid和rData用于寄存输入valid和payload避免气泡。

开敲

如果有寄存数据,输出寄存数据;如果没有寄存数据,寄存数据 or 直接输出(视输出ready决定)

val rData = RegNextWhen(self.payload, self.fire & ~s2mPipe.fire)
val rValid = RegInit(False) setWhen(self.fire) clearWhen(s2mPipe.fire)
val rReady = RegInit(True) setWhen(s2mPipe.ready) clearWhen(~s2mPipe.ready | rValid)


self.ready := rReady
s2mPipe.valid := self.valid | rValid
s2mPipe.payload := Mux(rValid, rData, self.payload)

修正1:rData只有在rValid拉高时才用到,而rValid只有self.fire时才为高,因此

val rData = RegNextWhen(self.payload, self.fire)

修正2:rValid说明是否包含寄存数据,rValid为高时说明无法再接收新寄存数据,这要求self.ready拉低,因为只能寄存-消化-直通 or 寄存-消化-寄存-消化 or 直通,即有寄存数据后只能消化,不能消化的同时寄存(因为rValid在消化的时候拉低了,就算寄存了rValid也为低,这与前面说法相违背,或者说这种情况应该是m2sPipe,因为payload和valid有一拍延时),因此实际上self.ready只在没有寄存数据的时候才能为高,即

self.ready := ~rValid

修正3:self.ready依赖于rValid,而rValid依赖self.fire,这形成了环路,存在问题. 实际上,rValid为高时,s2mPipe.valid为高,因此拉低条件s2mPipe.fire可以退化成s2mPipe.ready;而拉高条件self.fire & ~s2mPipe.ready是为了说明有数据寄存且没有消化,则原来的rValid为低,self.ready为高(self.ready := ~rValid),因此拉高条件退化为self.valid & ~s2mPipe.ready,则

val rValid = RegInit(False) setWhen (self.valid) clearWhen(s2mPipe.ready)

修正4:rData的寄存条件self.fire较为严格,因为实际输出依赖rValid选择payload,而rValid是在self.valid时拉高,因此寄存条件self.fire = self.valid & self.ready可以退化为self.ready,则

val rData = RegNextWhen(self.payload, self.ready)

完整代码

val rData = RegNextWhen(self.payload, self.ready)
val rValid = RegInit(False) setWhen(self.valid) clearWhen(s2mPipe.ready)

self.ready := ~rValid
s2mPipe.valid := self.valid | rValid
s2mPipe.payload := Mux(rValid, rData, self.payload)

补充

  1. s2mPipe() is ready to accept new data when the internal data register does not contain valid data.
  2. The ready becomes valid when rData is free, thus when it does not contain valid data already.

m2sPipe

关键点

rValid和rData寄存输入valid和payload, self.ready处理气泡拼接。


开敲

val rData = RegNextWhen(self.payload, self.ready)
val rValid = RegNextWhen(self.valid, self.ready) init(False)

self.ready := m2sPipe.ready | ~m2sPipe.valid	// m2sPipe.isFree
m2sPipe.valid := rValid
m2sPipe.payload := rData