MultiLaneQueue: a Queue which can enqueue variable-sized transactions

This commit is contained in:
Wesley W. Terpstra 2018-10-18 14:43:52 -07:00
parent 5744792f82
commit 1ab462e933
2 changed files with 92 additions and 1 deletions

View File

@ -132,7 +132,9 @@ class WithPowerQueueTests extends Config((site, here, up) => {
Module(new PositionedQueueTest(OnePortLanePositionedQueue(new IdentityCode), 3, 16, 10000)),
Module(new PositionedQueueTest(OnePortLanePositionedQueue(new IdentityCode), 5, 20, 10000)),
Module(new MultiPortQueueTest(3, 2, 10000)),
Module(new MultiPortQueueTest(5, 6, 10000))
Module(new MultiPortQueueTest(5, 6, 10000)),
Module(new MultiLaneQueueTest(3, 2, 10000)),
Module(new MultiLaneQueueTest(5, 6, 10000))
)}})
class AMBAUnitTestConfig extends Config(new WithAMBAUnitTests ++ new WithTestDuration(10) ++ new BaseSubsystemConfig)

View File

@ -0,0 +1,89 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.util
import chisel3._
import chisel3.util._
class MultiLaneQueue[T <: Data](gen: T, val lanes: Int, val rows: Int, storage: LanePositionedQueue = FloppedLanePositionedQueue) extends Module {
val laneBits1 = log2Ceil(lanes+1) // [0, lanes]
val io = IO(new Bundle {
val enq_ready = Output(Bool())
val enq_valid = Input(UInt(laneBits1.W))
val enq_bits = Input(Vec(lanes, gen))
// NOTE: deq_{valid,bits} depend on deq_ready
val deq_ready = Input(UInt(laneBits1.W))
val deq_valid = Output(Bool())
val deq_bits = Output(Vec(lanes, gen))
})
val queue = Module(storage(gen, lanes, rows))
io.enq_ready := io.enq_valid <= queue.io.enq.ready
queue.io.enq.valid := Mux(io.enq_ready, io.enq_valid, 0.U)
queue.io.enq.bits := RotateVector.left(io.enq_bits, queue.io.enq_0_lane)
io.deq_valid := io.deq_ready <= queue.io.deq.valid
queue.io.deq.ready := Mux(io.deq_valid, io.deq_ready, 0.U)
io.deq_bits := RotateVector.right(queue.io.deq.bits, queue.io.deq_0_lane)
}
object RotateVector {
def left[T <: Data](input: Seq[T], shift: UInt): Vec[T] = {
val bools = shift.toBools.toVector
def helper(bit: Int, offset: Int, x: Vector[T]): Vector[T] = {
if (offset >= input.size) {
x
} else {
helper(bit+1, offset+offset, Vector.tabulate(x.size) { i =>
Mux(bools(bit), x((i+x.size-offset) % x.size), x(i))
})
}
}
VecInit(helper(0, 1, input.toVector))
}
def right[T <: Data](input: Seq[T], shift: UInt): Vec[T] = {
val bools = shift.toBools.toVector
def helper(bit: Int, offset: Int, x: Vector[T]): Vector[T] = {
if (offset >= input.size) {
x
} else {
helper(bit+1, offset+offset, Vector.tabulate(x.size) { i =>
Mux(bools(bit), x((i+offset) % x.size), x(i))
})
}
}
VecInit(helper(0, 1, input.toVector))
}
}
import freechips.rocketchip.unittest._
import freechips.rocketchip.tilelink.LFSR64
class MultiLaneQueueTest(lanes: Int, rows: Int, cycles: Int, timeout: Int = 500000) extends UnitTest(timeout) {
val ids = (cycles+1) * lanes
val bits = log2Ceil(ids+1)
val q = Module(new MultiLaneQueue(UInt(bits.W), lanes, rows))
val enq = RegInit(0.U(bits.W))
val deq = RegInit(0.U(bits.W))
val done = RegInit(false.B)
when (enq >= (cycles*lanes).U) { done := true.B }
io.finished := done
q.io.enq_valid := (LFSR64() * (1+lanes).U) >> 64
q.io.deq_ready := (LFSR64() * (1+lanes).U) >> 64
when (q.io.enq_ready) { enq := enq + q.io.enq_valid }
when (q.io.deq_valid) { deq := deq + q.io.deq_ready }
for (i <- 0 until lanes) {
q.io.enq_bits(i) := enq + i.U
when (q.io.deq_valid) {
assert (i.U >= q.io.deq_ready || q.io.deq_bits(i) === deq + i.U)
}
}
}