blob: 8ec1d606d0449e28b9a691abb84aa2a668a8b0b8 [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 FifoX {
def apply[T <: Data](t: T, x: Int, n: Int) = {
Module(new FifoX(t, x, n))
}
}
// Xway decode, used for FifoX style input controls.
object FifoXValid {
def apply(in: UInt): Seq[UInt] = {
val inx = new Array[UInt](in.getWidth)
for (i <- 0 until in.getWidth) {
inx(i) = Cat(
(0 until in.getWidth).reverse.map(x =>
if (x < i) { false.B } else {
(PopCount(in(x,0)) === (i + 1).U) && in(x)
}
)
)
}
inx
}
}
class FifoX[T <: Data](t: T, x: Int, n: Int) extends Module {
val io = IO(new Bundle {
val in = Flipped(Decoupled(Vec(x, Valid(t))))
val out = Decoupled(t)
val count = Output(UInt(log2Ceil(n+1).W))
})
val m = n - 1 // n = Mem(n-1) + Slice
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 = RegInit(VecInit(Seq.fill(n)(0.U(t.getWidth.W).asTypeOf(t))))
val mslice = Slice(t, false, true)
val inxpos = RegInit(VecInit((0 until x).map(x => x.U(log2Ceil(m).W))))
val outpos = RegInit(0.U(log2Ceil(m).W))
val mcount = RegInit(0.U(log2Ceil(n+1).W))
io.count := mcount + io.out.valid
val ivalid = io.in.valid && io.in.ready
val ovalid = mslice.io.in.valid && mslice.io.in.ready
val iactive = Cat((0 until x).reverse.map(x => io.in.bits(x).valid))
val icount = PopCount(iactive)
// ---------------------------------------------------------------------------
// Fifo Control.
when (ivalid) {
for (i <- 0 until x) {
inxpos(i) := Increment(inxpos(i), icount)
}
}
when (ovalid) {
outpos := Increment(outpos, 1.U)
}
val inc = MuxOR(ivalid, icount)
val dec = mslice.io.in.valid && mslice.io.in.ready
when (ivalid || ovalid) {
mcount := mcount + inc - dec
}
// ---------------------------------------------------------------------------
// Fifo Input.
val inxvalid = FifoXValid(iactive)
for (i <- 0 until m) {
val valid = Cat(
(0 until x).reverse.map(q =>
if (q == 0) { inxpos(0) === i.U && inxvalid(0)(0) } else {
(0 to q).map(y =>
inxpos(y) === i.U && inxvalid(y)(q)
).reduce(_ || _)
}
)
)
when (ivalid) {
when (PopCount(valid) >= 1.U) {
val idx = PriorityEncoder(valid)
mem(i) := io.in.bits(idx).bits
}
}
}
mslice.io.in.valid := false.B
mslice.io.in.bits := io.in.bits(0).bits // defaults
when (mcount > 0.U) {
when (io.out.ready) {
mslice.io.in.valid := true.B
}
} .otherwise {
when (ivalid && iactive =/= 0.U) {
mslice.io.in.valid := true.B
}
}
when (mcount > 0.U) {
mslice.io.in.bits := mem(outpos)
} .elsewhen (ivalid) {
when (iactive =/= 0.U) {
val idx = PriorityEncoder(iactive)
mslice.io.in.bits := io.in.bits(idx).bits
}
}
// ---------------------------------------------------------------------------
// Valid Entries.
val active = RegInit(0.U(m.W))
val activeSet = MuxOR(ivalid,
(0 until x).map(i => (icount >= (i + 1).U) << inxpos(i)).reduce(_ | _)
)
val activeClr = MuxOR(mslice.io.in.valid && mslice.io.in.ready, 1.U << outpos)
active := (active | activeSet) & ~activeClr
// ---------------------------------------------------------------------------
// Interface.
io.in.ready := mcount <= (m.U - icount)
io.out <> mslice.io.out
assert(mcount <= m.U)
}
object EmitFifoX extends App {
ChiselStage.emitSystemVerilogFile(new FifoX(UInt(8.W), 4, 11), args)
}