| package common |
| |
| import chisel3._ |
| import chisel3.util._ |
| |
| object Fifo4x4 { |
| def apply[T <: Data](t: T, n: Int) = { |
| Module(new Fifo4x4(t, 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 Fifo4x4[T <: Data](t: T, n: Int) extends Module { |
| val io = IO(new Bundle { |
| val in = Flipped(Decoupled(Vec(4, Valid(t)))) |
| val out = Vec(4, 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(4, UInt(mb.W))) // reset below |
| val outpos = Reg(Vec(4, 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(4.W)) |
| |
| val ivalid = io.in.valid && 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 = (io.in.bits(0).valid +& io.in.bits(1).valid +& |
| io.in.bits(2).valid +& io.in.bits(3).valid)(2,0) |
| |
| val oactiveBits = Cat(io.out(3).valid && io.out(3).ready, |
| io.out(2).valid && io.out(2).ready, |
| io.out(1).valid && io.out(1).ready, |
| io.out(0).valid && io.out(0).ready) |
| |
| val ovalid = oactiveBits =/= 0.U |
| |
| val ocount = (oactiveBits(0) +& oactiveBits(1) +& |
| oactiveBits(2) +& oactiveBits(3))(2,0) |
| |
| assert(!(oactiveBits(1) === 1.U && oactiveBits(0,0) =/= 1.U)) |
| assert(!(oactiveBits(2) === 1.U && oactiveBits(1,0) =/= 3.U)) |
| assert(!(oactiveBits(3) === 1.U && oactiveBits(2,0) =/= 7.U)) |
| |
| val ovalidBits = Cat(io.out(3).valid, io.out(2).valid, |
| io.out(1).valid, io.out(0).valid) |
| |
| assert(!(ovalidBits(1) === 1.U && ovalidBits(0,0) =/= 1.U)) |
| assert(!(ovalidBits(2) === 1.U && ovalidBits(1,0) =/= 3.U)) |
| assert(!(ovalidBits(3) === 1.U && ovalidBits(2,0) =/= 7.U)) |
| |
| val oreadyBits = Cat(io.out(3).ready, io.out(2).ready, |
| io.out(1).ready, io.out(0).ready) |
| |
| assert(!(oreadyBits(1) === 1.U && oreadyBits(0,0) =/= 1.U)) |
| assert(!(oreadyBits(2) === 1.U && oreadyBits(1,0) =/= 3.U)) |
| assert(!(oreadyBits(3) === 1.U && oreadyBits(2,0) =/= 7.U)) |
| |
| // --------------------------------------------------------------------------- |
| // Fifo Control. |
| when (reset.asBool) { |
| for (i <- 0 until 4) { |
| inpos(i) := i.U |
| } |
| } .elsewhen (ivalid) { |
| for (i <- 0 until 4) { |
| inpos(i) := Increment(inpos(i), icount) |
| } |
| } |
| |
| when (reset.asBool) { |
| for (i <- 0 until 4) { |
| outpos(i) := i.U |
| } |
| } .elsewhen (ovalid) { |
| for (i <- 0 until 4) { |
| 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 - 4.U) |
| mcount := nxtmcount |
| nempty := nxtmcount =/= 0.U |
| outvalid := Cat(nxtmcount >= 4.U, |
| nxtmcount >= 3.U, |
| nxtmcount >= 2.U, |
| nxtmcount >= 1.U) |
| } .otherwise { |
| inready := mcount <= (m.U - 4.U) |
| outvalid := Cat(mcount >= 4.U, |
| mcount >= 3.U, |
| mcount >= 2.U, |
| mcount >= 1.U) |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Fifo Input. |
| val (in0valid, in1valid, in2valid, in3valid) = Fifo4Valid(iactive) |
| |
| for (i <- 0 until m) { |
| val valid = Cat(inpos(0) === i.U && in0valid(3) || |
| inpos(1) === i.U && in1valid(3) || |
| inpos(2) === i.U && in2valid(3) || |
| inpos(3) === i.U && in3valid(3), |
| |
| inpos(0) === i.U && in0valid(2) || |
| inpos(1) === i.U && in1valid(2) || |
| inpos(2) === i.U && in2valid(2), |
| |
| inpos(0) === i.U && in0valid(1) || |
| inpos(1) === i.U && in1valid(1), |
| |
| inpos(0) === i.U && in0valid(0)) |
| |
| if (true) { |
| val data = MuxOR(valid(0), io.in.bits(0).bits.asUInt) | |
| MuxOR(valid(1), io.in.bits(1).bits.asUInt) | |
| MuxOR(valid(2), io.in.bits(2).bits.asUInt) | |
| MuxOR(valid(3), io.in.bits(3).bits.asUInt) |
| |
| when (ivalid && valid =/= 0.U) { |
| mem(i) := data.asTypeOf(t) |
| } |
| } else { |
| 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 |
| } |
| } |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Interface. |
| io.in.ready := inready |
| |
| for (i <- 0 until 4) { |
| 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 EmitFifo4x4 extends App { |
| (new chisel3.stage.ChiselStage).emitVerilog(new Fifo4x4(UInt(32.W), 24), args) |
| } |