blob: f1efd98367302600b8891564616295ac8087b778 [file] [log] [blame]
package common
import chisel3._
import chisel3.util._
object Fifo {
def apply[T <: Data](t: T, n: Int, passReady: Boolean = false) = {
Module(new Fifo(t, n, passReady))
}
}
class Fifo[T <: Data](t: T, n: Int, passReady: Boolean) extends Module {
val io = IO(new Bundle {
val in = Flipped(Decoupled(t))
val out = Decoupled(t)
val count = Output(UInt(log2Ceil(n+1).W))
})
// An (n-1) queue with a registered output stage.
val m = n - 1 // n = Mem(n-1) + Out
val mem = Mem(m, t)
val rdata = Reg(t)
val rvalid = RegInit(false.B)
val wready = RegInit(false.B)
val raddr = RegInit(0.U(log2Ceil(m).W))
val waddr = RegInit(0.U(log2Ceil(m).W))
val count = RegInit(0.U(log2Ceil(n+1).W))
// ---------------------------------------------------------------------------
// Memory Addresses.
val winc = io.in.valid && io.in.ready
val rinc = (!rvalid || io.out.ready) && (winc || count > 1.U)
when (winc) {
waddr := Mux(waddr === (m - 1).U, 0.U, waddr + 1.U)
}
when (rinc) {
raddr := Mux(raddr === (m - 1).U, 0.U, raddr + 1.U)
}
val forward = rinc && winc && count <= 1.U
// ---------------------------------------------------------------------------
// FIFO Control.
val ien = io.in.valid && io.in.ready
val oen = io.out.valid && io.out.ready
when (ien && !oen) {
count := count + 1.U
} .elsewhen (!ien && oen) {
count := count - 1.U
}
when (ien) {
rvalid := true.B
} .elsewhen (io.out.ready && count === 1.U) {
rvalid := false.B
}
wready := count < (n - 1).U ||
count === (n - 1).U && !(ien && !oen) ||
(oen && !ien)
// ---------------------------------------------------------------------------
// Memory.
when (winc && !forward) {
mem(waddr) := io.in.bits
}
when (forward) {
rdata := io.in.bits
} .elsewhen (rinc) {
rdata := mem(raddr)
}
// ---------------------------------------------------------------------------
// Interface.
io.out.valid := rvalid
io.out.bits := rdata
if (passReady) {
io.in.ready := wready || io.out.ready // pass-through
} else {
io.in.ready := wready
}
io.count := count
assert(count <= n.U)
assert(!(!passReady.B && io.in.ready && count === n.U))
}
object EmitFifo extends App {
(new chisel3.stage.ChiselStage).emitVerilog(new Fifo(UInt(8.W), 11, false), args)
}
object EmitFifo_1 extends App {
(new chisel3.stage.ChiselStage).emitVerilog(new Fifo(UInt(8.W), 11, true), args)
}