| // 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) |
| } |