Add allowShift to CoalShiftQueue IO to synchronize shifting
This commit is contained in:
@@ -153,10 +153,14 @@ class ReqSourceGen(sourceWidth: Int) extends Module {
|
|||||||
// A shift-register queue implementation that supports invalidating entries
|
// A shift-register queue implementation that supports invalidating entries
|
||||||
// and exposing queue contents as output IO. (TODO: support deadline)
|
// and exposing queue contents as output IO. (TODO: support deadline)
|
||||||
// Initially copied from freechips.rocketchip.util.ShiftQueue.
|
// Initially copied from freechips.rocketchip.util.ShiftQueue.
|
||||||
// If `pipe` is true, support enqueueing to a full queue when also dequeueing.
|
// The queue only shifts down when `allowShift` is given true. Dequeueing
|
||||||
|
// works normally, but if allowShift was false, the queue head will stay
|
||||||
|
// invalid after dequeueing. This option is added in order to synchronize the
|
||||||
|
// shifting of the queues between lanes to model the SIMD behavior.
|
||||||
|
// If `pipe` is true, support enqueueing to a full queue when head is being
|
||||||
|
// dequeued at the next cycle.
|
||||||
// Software model: window.py
|
// Software model: window.py
|
||||||
class CoalShiftQueue[T <: Data](
|
class CoalShiftQueue[T <: Data]( gen: T,
|
||||||
gen: T,
|
|
||||||
val entries: Int,
|
val entries: Int,
|
||||||
pipe: Boolean = true,
|
pipe: Boolean = true,
|
||||||
flow: Boolean = false
|
flow: Boolean = false
|
||||||
@@ -164,6 +168,7 @@ class CoalShiftQueue[T <: Data](
|
|||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val queue = new QueueIO(gen, entries)
|
val queue = new QueueIO(gen, entries)
|
||||||
val invalidate = Input(Valid(UInt(entries.W)))
|
val invalidate = Input(Valid(UInt(entries.W)))
|
||||||
|
val allowShift = Input(Bool())
|
||||||
val mask = Output(UInt(entries.W))
|
val mask = Output(UInt(entries.W))
|
||||||
val elts = Output(Vec(entries, gen))
|
val elts = Output(Vec(entries, gen))
|
||||||
// 'QueueIO' provides io.count, but we might not want to use it in the
|
// 'QueueIO' provides io.count, but we might not want to use it in the
|
||||||
@@ -192,7 +197,7 @@ class CoalShiftQueue[T <: Data](
|
|||||||
def paddedUsed = pad({ i: Int => used(i) })
|
def paddedUsed = pad({ i: Int => used(i) })
|
||||||
def validAfterInv(i: Int) = valid(i) && (!io.invalidate.valid || !io.invalidate.bits(i))
|
def validAfterInv(i: Int) = valid(i) && (!io.invalidate.valid || !io.invalidate.bits(i))
|
||||||
|
|
||||||
val shift = (used =/= 0.U) && (io.queue.deq.ready || !validAfterInv(0))
|
val shift = io.allowShift && (used =/= 0.U) && (io.queue.deq.fire || !validAfterInv(0))
|
||||||
for (i <- 0 until entries) {
|
for (i <- 0 until entries) {
|
||||||
val wdata = if (i == entries - 1) io.queue.enq.bits else Mux(!used(i + 1), io.queue.enq.bits, elts(i + 1))
|
val wdata = if (i == entries - 1) io.queue.enq.bits else Mux(!used(i + 1), io.queue.enq.bits, elts(i + 1))
|
||||||
val wen = Mux(
|
val wen = Mux(
|
||||||
@@ -540,12 +545,13 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig) extends
|
|||||||
assert(reqQueue.io.queue.enq.ready, "reqQueue is supposed to be always ready")
|
assert(reqQueue.io.queue.enq.ready, "reqQueue is supposed to be always ready")
|
||||||
reqQueue.io.queue.enq.valid := tlIn.a.valid
|
reqQueue.io.queue.enq.valid := tlIn.a.valid
|
||||||
reqQueue.io.queue.enq.bits := req
|
reqQueue.io.queue.enq.bits := req
|
||||||
// TODO: deq.ready should respect downstream ready
|
// TODO: deq.ready should respect downstream arbiter
|
||||||
reqQueue.io.queue.deq.ready := true.B
|
reqQueue.io.queue.deq.ready := true.B
|
||||||
// invalidate queue entries that contain original core requests that got
|
// invalidate queue entries that contain original core requests that got
|
||||||
// coalesced into a wider one
|
// coalesced into a wider one
|
||||||
reqQueue.io.invalidate.bits := coalescer.io.invalidate.bits(lane)
|
reqQueue.io.invalidate.bits := coalescer.io.invalidate.bits(lane)
|
||||||
reqQueue.io.invalidate.valid := coalescer.io.invalidate.valid
|
reqQueue.io.invalidate.valid := coalescer.io.invalidate.valid
|
||||||
|
reqQueue.io.allowShift := true.B
|
||||||
|
|
||||||
// NOTE: this relies on CoalShiftQueue's behavior combinationally
|
// NOTE: this relies on CoalShiftQueue's behavior combinationally
|
||||||
// deasserting deq.valid in the same cycle that the head invalidate
|
// deasserting deq.valid in the same cycle that the head invalidate
|
||||||
|
|||||||
@@ -224,6 +224,7 @@ class CoalShiftQueueTest extends AnyFlatSpec with ChiselScalatestTester {
|
|||||||
it should "work like normal shiftqueue when no invalidate" in {
|
it should "work like normal shiftqueue when no invalidate" in {
|
||||||
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
||||||
c.io.queue.deq.ready.poke(false.B)
|
c.io.queue.deq.ready.poke(false.B)
|
||||||
|
c.io.allowShift.poke(true.B)
|
||||||
|
|
||||||
c.io.queue.enq.ready.expect(true.B)
|
c.io.queue.enq.ready.expect(true.B)
|
||||||
c.io.queue.enq.valid.poke(true.B)
|
c.io.queue.enq.valid.poke(true.B)
|
||||||
@@ -272,6 +273,7 @@ class CoalShiftQueueTest extends AnyFlatSpec with ChiselScalatestTester {
|
|||||||
it should "work when enqueing and dequeueing simultaneously" in {
|
it should "work when enqueing and dequeueing simultaneously" in {
|
||||||
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
||||||
c.io.invalidate.valid.poke(false.B)
|
c.io.invalidate.valid.poke(false.B)
|
||||||
|
c.io.allowShift.poke(true.B)
|
||||||
|
|
||||||
// prepare
|
// prepare
|
||||||
c.io.queue.deq.ready.poke(true.B)
|
c.io.queue.deq.ready.poke(true.B)
|
||||||
@@ -303,6 +305,7 @@ class CoalShiftQueueTest extends AnyFlatSpec with ChiselScalatestTester {
|
|||||||
it should "work when enqueing and dequeueing simultaneously to a full queue" in {
|
it should "work when enqueing and dequeueing simultaneously to a full queue" in {
|
||||||
test(new CoalShiftQueue(UInt(8.W), 1)) { c =>
|
test(new CoalShiftQueue(UInt(8.W), 1)) { c =>
|
||||||
c.io.invalidate.valid.poke(false.B)
|
c.io.invalidate.valid.poke(false.B)
|
||||||
|
c.io.allowShift.poke(true.B)
|
||||||
|
|
||||||
// prepare
|
// prepare
|
||||||
c.io.queue.deq.ready.poke(true.B)
|
c.io.queue.deq.ready.poke(true.B)
|
||||||
@@ -342,6 +345,7 @@ class CoalShiftQueueTest extends AnyFlatSpec with ChiselScalatestTester {
|
|||||||
it should "invalidate head being dequeued" in {
|
it should "invalidate head being dequeued" in {
|
||||||
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
||||||
c.io.invalidate.valid.poke(false.B)
|
c.io.invalidate.valid.poke(false.B)
|
||||||
|
c.io.allowShift.poke(true.B)
|
||||||
|
|
||||||
// prepare
|
// prepare
|
||||||
c.io.queue.deq.ready.poke(false.B)
|
c.io.queue.deq.ready.poke(false.B)
|
||||||
@@ -374,6 +378,7 @@ class CoalShiftQueueTest extends AnyFlatSpec with ChiselScalatestTester {
|
|||||||
it should "dequeue invalidated entries by itself" in {
|
it should "dequeue invalidated entries by itself" in {
|
||||||
test(new CoalShiftQueue(gen = UInt(8.W), entries = 4)) { c =>
|
test(new CoalShiftQueue(gen = UInt(8.W), entries = 4)) { c =>
|
||||||
c.io.invalidate.valid.poke(false.B)
|
c.io.invalidate.valid.poke(false.B)
|
||||||
|
c.io.allowShift.poke(true.B)
|
||||||
|
|
||||||
// prepare
|
// prepare
|
||||||
c.io.queue.deq.ready.poke(false.B)
|
c.io.queue.deq.ready.poke(false.B)
|
||||||
@@ -414,6 +419,7 @@ class CoalShiftQueueTest extends AnyFlatSpec with ChiselScalatestTester {
|
|||||||
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
||||||
c.io.invalidate.valid.poke(false.B)
|
c.io.invalidate.valid.poke(false.B)
|
||||||
c.io.invalidate.bits.poke(0.U)
|
c.io.invalidate.bits.poke(0.U)
|
||||||
|
c.io.allowShift.poke(true.B)
|
||||||
|
|
||||||
// prepare
|
// prepare
|
||||||
c.io.queue.deq.ready.poke(false.B)
|
c.io.queue.deq.ready.poke(false.B)
|
||||||
|
|||||||
Reference in New Issue
Block a user