blob: 5be7dd6412adfe9a518ae068baecc1288ffb4201 [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 FifoIxO {
def apply[T <: Data](t: T, i: Int, o: Int, n: Int) = {
Module(new FifoIxO(t, i, o, n))
}
}
// Input accepted with a common handshake and per lane select.
// Outputs are transacted independently, and ordered {[0], [0,1], [0,1,2], [0,1,2,3]}.
// Outputs are not registered, assumes passes directly into shallow combinatorial.
class FifoIxO[T <: Data](t: T, i: Int, o: Int, n: Int /* depth */) extends Module {
val io = IO(new Bundle {
val in = Flipped(Decoupled(Vec(i, Valid(t))))
val out = Vec(o, Decoupled(t))
val count = Output(UInt(log2Ceil(n+1).W))
val nempty = Output(Bool())
})
val m = n
val mb = log2Ceil(m)
val n1b = log2Ceil(n + 1)
def Increment(a: UInt, b: UInt): UInt = {
val c = a +& b
val d = Mux(c < m.U, c, c - m.U)(a.getWidth - 1, 0)
d
}
val mem = Reg(Vec(n, t))
val inpos = Reg(Vec(i, UInt(mb.W))) // reset below
val outpos = Reg(Vec(o, UInt(mb.W))) // reset below
val mcount = RegInit(0.U(n1b.W))
val nempty = RegInit(false.B)
val inready = RegInit(false.B)
val outvalid = RegInit(0.U(o.W))
val ivalid = io.in.valid && io.in.ready
val iactive = Cat((0 until i).reverse.map(x => io.in.bits(x).valid)).asUInt
val icount = (io.in.bits.map(x => x.valid.asUInt).reduce(_ +& _))(log2Ceil(i),0)
val oactiveBits = Cat((0 until o).reverse.map(x => io.out(x).valid && io.out(x).ready))
val ovalid = oactiveBits =/= 0.U
val ocount = (0 until o).map(x => oactiveBits(x).asUInt).reduce(_ +& _)(log2Ceil(o),0)
for (n <- 1 until o) {
assert(!(oactiveBits(n) === 1.U && oactiveBits(n - 1,0) =/= ((1 << n) - 1).U))
}
val ovalidBits = Cat((0 until o).reverse.map(x => io.out(x).valid))
for (n <- 1 until o) {
assert(!(ovalidBits(n) === 1.U && ovalidBits(n - 1, 0) =/= ((1 << n) - 1).U))
}
val oreadyBits = Cat((0 until o).reverse.map(x => io.out(x).ready))
for (n <- 1 until o) {
assert(!(oreadyBits(n) === 1.U && oreadyBits(n - 1, 0) =/= ((1 << n) - 1).U))
}
// ---------------------------------------------------------------------------
// Fifo Control.
when (reset.asBool) {
for (i <- 0 until i) {
inpos(i) := i.U
}
} .elsewhen (ivalid) {
for (i <- 0 until i) {
inpos(i) := Increment(inpos(i), icount)
}
}
when (reset.asBool) {
for (i <- 0 until o) {
outpos(i) := i.U
}
} .elsewhen (ovalid) {
for (i <- 0 until o) {
outpos(i) := Increment(outpos(i), ocount)
}
}
val inc = MuxOR(ivalid, icount)
val dec = MuxOR(ovalid, ocount)
when (ivalid || ovalid) {
val nxtmcount = mcount + inc - dec
inready := nxtmcount <= (m.U - i.U)
mcount := nxtmcount
nempty := nxtmcount =/= 0.U
outvalid := Cat((0 until o).reverse.map(x => nxtmcount >= (x + 1).U))
} .otherwise {
inready := mcount <= (m.U - i.U)
outvalid := Cat((0 until o).reverse.map(x => mcount >= (x + 1).U))
}
// ---------------------------------------------------------------------------
// Fifo Input.
val inxvalid = FifoXValid(iactive)
for (q <- 0 until m) {
val valid = Cat(
(0 until i).reverse.map(x =>
if (x == 0) { inpos(0) === q.U && inxvalid(0)(0) } else {
(0 to x).map(y =>
inpos(y) === q.U && inxvalid(y)(x)
).reduce(_ || _)
}
)
)
if (true) {
val data = (0 until i).map(x => MuxOR(valid(x), io.in.bits(x).bits.asUInt)).reduce(_ | _)
when (ivalid && valid =/= 0.U) {
mem(q) := data.asTypeOf(t)
}
} else {
when (ivalid) {
when(PopCount(valid) >= 1.U) {
val idx = PriorityEncoder(valid)
mem(q) := io.in.bits(idx).bits
}
}
}
}
// ---------------------------------------------------------------------------
// Interface.
io.in.ready := inready
for (i <- 0 until o) {
io.out(i).valid := outvalid(i)
io.out(i).bits := mem(outpos(i)) // TODO: VecAt()
}
io.count := mcount
io.nempty := nempty
assert(io.count <= m.U)
}
object EmitFifoIxO extends App {
ChiselStage.emitSystemVerilogFile(new FifoIxO(UInt(32.W), 4, 4, 24), args)
}