| // 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 Fifo4 { |
| def apply[T <: Data](t: T, n: Int) = { |
| Module(new Fifo4(t, n)) |
| } |
| } |
| |
| // 4way decode, used for Fifo4 style input controls. |
| object Fifo4Valid { |
| def apply(in: UInt): (UInt, UInt, UInt, UInt) = { |
| assert(in.getWidth == 4) |
| |
| val in0 = Cat(in(3,0) === 8.U, // 8 |
| in(2,0) === 4.U, // 4, 12 |
| in(1,0) === 2.U, // 2, 6, 10, 14 |
| in(0)) // 1, 3, 5, 7, 9, 11, 13, 15 |
| |
| val in1 = Cat(in(3,0) === 12.U || |
| in(3,0) === 10.U || |
| in(3,0) === 9.U, // 9, 10, 12 |
| in(2,0) === 6.U || |
| in(2,0) === 5.U, // 5, 6, 13, 14 |
| in(1,0) === 3.U, // 3, 7, 11, 15 |
| false.B) |
| |
| val in2 = Cat(in(3,0) === 14.U || |
| in(3,0) === 13.U || |
| in(3,0) === 11.U, // 11, 13, 14 |
| in(2,0) === 15.U || |
| in(2,0) === 7.U, // 7, 15 |
| false.B, false.B) |
| |
| val in3 = Cat(in(3,0) === 15.U, // 15 |
| false.B, false.B, false.B) |
| |
| (in0.asUInt, in1.asUInt, in2.asUInt, in3.asUInt) |
| } |
| } |
| |
| class Fifo4[T <: Data](t: T, n: Int) extends Module { |
| val io = IO(new Bundle { |
| val in = Flipped(Decoupled(Vec(4, 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 = Mem(m, t) |
| val mslice = Slice(t, false, true) |
| |
| val in0pos = RegInit(0.U(log2Ceil(m).W)) |
| val in1pos = RegInit(1.U(log2Ceil(m).W)) |
| val in2pos = RegInit(2.U(log2Ceil(m).W)) |
| val in3pos = RegInit(3.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(io.in.bits(3).valid, io.in.bits(2).valid, |
| io.in.bits(1).valid, io.in.bits(0).valid).asUInt |
| |
| val icount = PopCount(iactive) |
| |
| // --------------------------------------------------------------------------- |
| // Fifo Control. |
| when (ivalid) { |
| in0pos := Increment(in0pos, icount) |
| in1pos := Increment(in1pos, icount) |
| in2pos := Increment(in2pos, icount) |
| in3pos := Increment(in3pos, 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 (in0valid, in1valid, in2valid, in3valid) = Fifo4Valid(iactive) |
| |
| for (i <- 0 until m) { |
| val valid = Cat(in0pos === i.U && in0valid(3) || |
| in1pos === i.U && in1valid(3) || |
| in2pos === i.U && in2valid(3) || |
| in3pos === i.U && in3valid(3), |
| in0pos === i.U && in0valid(2) || |
| in1pos === i.U && in1valid(2) || |
| in2pos === i.U && in2valid(2), |
| in0pos === i.U && in0valid(1) || |
| in1pos === i.U && in1valid(1), |
| in0pos === i.U && in0valid(0)) |
| |
| when (ivalid) { |
| when (valid(0)) { |
| mem(i) := io.in.bits(0).bits |
| } .elsewhen (valid(1)) { |
| mem(i) := io.in.bits(1).bits |
| } .elsewhen (valid(2)) { |
| mem(i) := io.in.bits(2).bits |
| } .elsewhen (valid(3)) { |
| mem(i) := io.in.bits(3).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)) { |
| mslice.io.in.bits := io.in.bits(0).bits |
| } .elsewhen (iactive(1)) { |
| mslice.io.in.bits := io.in.bits(1).bits |
| } .elsewhen (iactive(2)) { |
| mslice.io.in.bits := io.in.bits(2).bits |
| } .elsewhen (iactive(3)) { |
| mslice.io.in.bits := io.in.bits(3).bits |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Valid Entries. |
| val active = RegInit(0.U(m.W)) |
| |
| val activeSet = MuxOR(ivalid, |
| ((icount >= 1.U) << in0pos) | ((icount >= 2.U) << in1pos) | |
| ((icount >= 3.U) << in2pos) | ((icount >= 4.U) << in3pos)) |
| |
| 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 EmitFifo4 extends App { |
| ChiselStage.emitSystemVerilogFile(new Fifo4(UInt(8.W), 11), args) |
| } |