blob: a01963f8165ba19b6310b6c76a23cbd3dee9072d [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 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)
}