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