|
import chisel3._
import chisel3.util._
class FifoIO[T <: Data](private val gen:T) extends Bundle {
val enq = Flipped(new DecoupledIO[T](gen)) //DecoupledIO-->>ReadyValidIO-->>Bundle 是带有valid和ready的复杂信号 Flipped则将bits,ready和valid信号切换方向
val deq = new DecoupledIO[T](gen) //deq是正常的bits,ready,valid方向
}
abstract class Fifo[T <: Data](gen:T,depth:Int) extends Module { //带有valid和ready的FIFO,并且有二个“group”,一个是enq,一个是deq
val io = IO(new FifoIO[T](gen))
assert(depth > 0,"Number of buffer elements needs to be larger than 0")
}
import chisel3._
import chisel3.util._
/**
* FIFO with memory and read and write pointers.
* Extra shadow register to handle the one cycle latency of the synchronous memory.
*/
class MemFifo[T <: Data](gen:T,depth:Int) extends Fifo(gen,depth){outer=>
def counter(depth:Int,incr:Bool): (UInt,UInt) = {
val cntReg = RegInit(0.U(log2Ceil(depth))) //depth-1值所需要的bit位数量
val nextVal = Mux(cntReg === (depth - 1).U,0.U,cntReg + 1.U)
when(incr) {
cntReg := nextVal
}
(cntReg,nextVal)
}
val mem = SyncReadMem(depth,gen) //SyncReadMem同步读/写 上升沿数据有效
val incrRead = WireInit(false.B)
val incrWrite = WireInit(false.B)
val (readPtr,nextRead) = counter(depth,incrRead)
val (writePtr,nextWrite) = counter(depth,incrWrite)
val emptyReg = RegInit(true.B)
val fullReg = RegInit(false.B)
val idle :: valid :: full :: Nil = Enum(3) //用Enum定义有几个状态枚举量
val stateReg = RegInit(idle)
val shadowReg = Reg(gen)
when(io.enq.valid && !fullReg) {
mem.write(writePtr,io.enq.bits) //将io.enq.bits数据按writePtr指针指标写入内存
emptyReg := false.B
fullReg := nextWrite === readPtr //下次写指针等于读指针则表示满
incrWrite := true.B //写启动 注意:即使写启动了,但如果是full,则cntReg依然不会变,nextVal也不会变
}
val data = mem.read(readPtr) //读数据
// 数据输出延迟一个时钟周期
switch(stateReg) {
is(idle) {
when(!emptyReg) { //不空
stateReg := valid //状态迁移到valid
fullReg := false.B //满标志 清
emptyReg := nextRead === writePtr //如果下次读指针与写指针相等则表示空
incrRead := true.B //启动读
}
}
is(valid) {
when(io.deq.ready) { //deq收到了ready数据准备好 指示
when(!emptyReg) { //不空
stateReg := valid //继续valid状态 只要不空且一直收到ready指示则一直要发数据
fullReg := false.B //清 满标志
emptyReg := nextRead === writePtr //下次读指针与写指针相等说明空
incrRead := true.B //启动读
} otherwise {
//说明是空
stateReg := idle //状态回到idle
}
} otherwise {
//说明io.deq.ready 数据准备好还没有指示
shadowReg := data //影子寄存器保存数据
stateReg := full
}
}
is(full) {
when(io.deq.ready) { //io.deq.ready收到数据准备好指示
when(!emptyReg) {
stateReg := valid //状态回迁到valid 发完一个数据就回到valid???
fullReg := false.B //只要是发数据当然满标志就要清空
emptyReg := nextRead === writePtr //只要是下次读指针与写指针相等就说明空了
incrRead := true.B //启动读
} otherwise {
//说明虽然收到了io.deq.ready数据已准备好可以发了,但因为是空,所以回到idle状态
stateReg := idle
}
}
}
}
io.deq.bits := Mux(stateReg === valid,data,shadowReg) //valid状态数据才有效,其它状态将上次所发的数据shadowReg放到数据总线上
io.enq.ready := !fullReg //io.enq.ready是output,表示enq端口的数据已经准备好了(只要不满),类似AXI SLAVE的READY
io.deq.valid := stateReg === valid || stateReg === full //在valid或full状态时发出数据有效指示
}
|
|