1
0
rocket-chip/src/main/scala/util/ShiftQueue.scala

64 lines
2.0 KiB
Scala
Raw Normal View History

2017-04-22 03:01:09 +02:00
// See LICENSE.SiFive for license details.
package freechips.rocketchip.util
2017-04-22 03:01:09 +02:00
import Chisel._
/** Implements the same interface as chisel3.util.Queue, but uses a shift
* register internally. It is less energy efficient whenever the queue
* has more than one entry populated, but is faster on the dequeue side.
* It is efficient for usually-empty flow-through queues. */
class ShiftQueue[T <: Data](gen: T,
val entries: Int,
pipe: Boolean = false,
flow: Boolean = false)
extends Module {
val io = IO(new QueueIO(gen, entries) {
val mask = UInt(OUTPUT, entries)
})
private val valid = RegInit(Vec.fill(entries) { Bool(false) })
2017-04-22 03:01:09 +02:00
private val elts = Reg(Vec(entries, gen))
2017-06-01 11:22:18 +02:00
for (i <- 0 until entries) {
def paddedValid(i: Int) = if (i == -1) true.B else if (i == entries) false.B else valid(i)
val wdata = if (i == entries-1) io.enq.bits else Mux(valid(i+1), elts(i+1), io.enq.bits)
val wen =
Mux(io.deq.ready,
2017-09-07 03:15:59 +02:00
paddedValid(i+1) || io.enq.fire() && (Bool(i == 0 && !flow) || valid(i)),
io.enq.fire() && paddedValid(i-1) && !valid(i))
when (wen) { elts(i) := wdata }
valid(i) :=
Mux(io.deq.ready,
paddedValid(i+1) || io.enq.fire() && (Bool(i == 0 && !flow) || valid(i)),
io.enq.fire() && paddedValid(i-1) || valid(i))
}
2017-04-22 03:01:09 +02:00
io.enq.ready := !valid(entries-1)
io.deq.valid := valid(0)
io.deq.bits := elts.head
if (flow) {
when (io.enq.valid) { io.deq.valid := true.B }
2017-06-01 11:22:18 +02:00
when (!valid(0)) { io.deq.bits := io.enq.bits }
2017-04-22 03:01:09 +02:00
}
if (pipe) {
when (io.deq.ready) { io.enq.ready := true.B }
}
io.mask := valid.asUInt
io.count := PopCount(io.mask)
2017-04-22 03:01:09 +02:00
}
2017-09-06 23:26:26 +02:00
object ShiftQueue
{
def apply[T <: Data](enq: DecoupledIO[T], entries: Int = 2, pipe: Boolean = false, flow: Boolean = false): DecoupledIO[T] = {
val q = Module(new ShiftQueue(enq.bits.cloneType, entries, pipe, flow))
q.io.enq <> enq
q.io.deq
}
}