blob: abced7990628dabb9b83fdf1910a900d164a6410 [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package common
import chisel3._
import chisel3.util._
import _root_.circt.stage.ChiselStage
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 = RegInit(VecInit(Seq.fill(n)(0.U(t.getWidth.W).asTypeOf(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 {
ChiselStage.emitSystemVerilogFile(new Fifo(UInt(8.W), 11, false), args)
}
object EmitFifo_1 extends App {
ChiselStage.emitSystemVerilogFile(new Fifo(UInt(8.W), 11, true), args)
}