我是 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)
补充
- s2mPipe() is ready to accept new data when the internal data register does not contain valid data.
- 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