Fix request shift queue not enqueuing when empty
The queue was enabling shifting of the registers whenever deq.ready was 1, even when the queue was empty. This caused `wen` to disable writing enq.bits to any of the entries in the queue. Fixed by setting `shift` to 0 when queue is empty.
This commit is contained in:
@@ -125,14 +125,13 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
|
|||||||
req.address := tlIn.a.bits.address
|
req.address := tlIn.a.bits.address
|
||||||
req.data := tlIn.a.bits.data
|
req.data := tlIn.a.bits.data
|
||||||
|
|
||||||
|
assert(reqQueue.io.enq.ready, "reqQueue is supposed to be always ready")
|
||||||
reqQueue.io.enq.valid := tlIn.a.valid
|
reqQueue.io.enq.valid := tlIn.a.valid
|
||||||
reqQueue.io.enq.bits := req
|
reqQueue.io.enq.bits := req
|
||||||
// TODO: deq.ready should respect downstream ready
|
// TODO: deq.ready should respect downstream ready
|
||||||
reqQueue.io.deq.ready := true.B
|
reqQueue.io.deq.ready := true.B
|
||||||
reqQueue.io.invalidate := 0.U
|
reqQueue.io.invalidate := 0.U
|
||||||
|
|
||||||
printf(s"reqQueue(${lane}).count=%d\n", reqQueue.io.count)
|
|
||||||
|
|
||||||
// Invalidate coalesced requests
|
// Invalidate coalesced requests
|
||||||
// FIXME: hardcoded lanes
|
// FIXME: hardcoded lanes
|
||||||
// val invalidate = coalReqValid && (lane == 0 || lane == 2).B
|
// val invalidate = coalReqValid && (lane == 0 || lane == 2).B
|
||||||
@@ -208,8 +207,9 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
|
|||||||
coalReqAddress := (0xabcd.U + coalSourceId) << 4
|
coalReqAddress := (0xabcd.U + coalSourceId) << 4
|
||||||
// FIXME: bogus coalescing logic: coalesce whenever all 4 lanes have valid
|
// FIXME: bogus coalescing logic: coalesce whenever all 4 lanes have valid
|
||||||
// queue head
|
// queue head
|
||||||
coalReqValid := reqQueues(0).io.deq.valid && reqQueues(1).io.deq.valid &&
|
// coalReqValid := reqQueues(0).io.deq.valid && reqQueues(1).io.deq.valid &&
|
||||||
reqQueues(2).io.deq.valid && reqQueues(3).io.deq.valid
|
// reqQueues(2).io.deq.valid && reqQueues(3).io.deq.valid
|
||||||
|
coalReqValid := false.B
|
||||||
when(coalReqValid) {
|
when(coalReqValid) {
|
||||||
// invalidate original requests due to coalescing
|
// invalidate original requests due to coalescing
|
||||||
// FIXME: bogus
|
// FIXME: bogus
|
||||||
@@ -245,7 +245,9 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
|
|||||||
val newEntry = Wire(
|
val newEntry = Wire(
|
||||||
new InflightCoalReqTableEntry(numLanes, numPerLaneReqs, sourceWidth, offsetBits, sizeBits)
|
new InflightCoalReqTableEntry(numLanes, numPerLaneReqs, sourceWidth, offsetBits, sizeBits)
|
||||||
)
|
)
|
||||||
|
|
||||||
println(s"=========== table sourceWidth: ${sourceWidth}")
|
println(s"=========== table sourceWidth: ${sourceWidth}")
|
||||||
|
|
||||||
newEntry.source := coalSourceId
|
newEntry.source := coalSourceId
|
||||||
newEntry.lanes.foreach { l =>
|
newEntry.lanes.foreach { l =>
|
||||||
l.reqs.zipWithIndex.foreach { case (r, i) =>
|
l.reqs.zipWithIndex.foreach { case (r, i) =>
|
||||||
@@ -535,11 +537,12 @@ 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(i)
|
def validAfterInv(i: Int) = valid(i) && !io.invalidate(i)
|
||||||
|
|
||||||
val shift = io.deq.ready || (used =/= 0.U) && !validAfterInv(0)
|
val shift = (used =/= 0.U) && (io.deq.ready || !validAfterInv(0))
|
||||||
for (i <- 0 until entries) {
|
for (i <- 0 until entries) {
|
||||||
val wdata = if (i == entries - 1) io.enq.bits else Mux(!used(i + 1), io.enq.bits, elts(i + 1))
|
val wdata = if (i == entries - 1) io.enq.bits else Mux(!used(i + 1), io.enq.bits, elts(i + 1))
|
||||||
val wen = Mux(
|
val wen = Mux(
|
||||||
shift,
|
shift,
|
||||||
|
// enqueue to the top entry which will be shifted down and make space
|
||||||
(io.enq.fire && !paddedUsed(i + 1) && used(i)) || pad(validAfterInv)(i + 1),
|
(io.enq.fire && !paddedUsed(i + 1) && used(i)) || pad(validAfterInv)(i + 1),
|
||||||
// enqueue to the first empty slot above the top
|
// enqueue to the first empty slot above the top
|
||||||
(io.enq.fire && paddedUsed(i - 1) && !used(i)) || !validAfterInv(i)
|
(io.enq.fire && paddedUsed(i - 1) && !used(i)) || !validAfterInv(i)
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class CoalShiftQueueTest extends AnyFlatSpec with ChiselScalatestTester {
|
|||||||
c.io.invalidate.poke(0.U)
|
c.io.invalidate.poke(0.U)
|
||||||
|
|
||||||
// prepare
|
// prepare
|
||||||
c.io.deq.ready.poke(false.B)
|
c.io.deq.ready.poke(true.B)
|
||||||
c.io.enq.ready.expect(true.B)
|
c.io.enq.ready.expect(true.B)
|
||||||
c.io.enq.valid.poke(true.B)
|
c.io.enq.valid.poke(true.B)
|
||||||
c.io.enq.bits.poke(0x12.U)
|
c.io.enq.bits.poke(0x12.U)
|
||||||
@@ -113,6 +113,45 @@ class CoalShiftQueueTest extends AnyFlatSpec with ChiselScalatestTester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it should "work when enqueing and dequeueing simultaneously to a full queue" in {
|
||||||
|
test(new CoalShiftQueue(UInt(8.W), 1)) { c =>
|
||||||
|
c.io.invalidate.poke(0.U)
|
||||||
|
|
||||||
|
// prepare
|
||||||
|
c.io.deq.ready.poke(true.B)
|
||||||
|
c.io.enq.ready.expect(true.B)
|
||||||
|
c.io.enq.valid.poke(true.B)
|
||||||
|
c.io.enq.bits.poke(0x12.U)
|
||||||
|
c.clock.step()
|
||||||
|
// enqueue and dequeue simultaneously
|
||||||
|
c.io.deq.ready.poke(true.B)
|
||||||
|
c.io.enq.ready.expect(true.B)
|
||||||
|
c.io.enq.valid.poke(true.B)
|
||||||
|
c.io.enq.bits.poke(0x34.U)
|
||||||
|
c.io.deq.valid.expect(true.B)
|
||||||
|
c.io.deq.bits.expect(0x12.U)
|
||||||
|
c.clock.step()
|
||||||
|
// enqueue and dequeue simultaneously once more
|
||||||
|
c.io.deq.ready.poke(true.B)
|
||||||
|
c.io.enq.ready.expect(true.B)
|
||||||
|
c.io.enq.valid.poke(true.B)
|
||||||
|
c.io.enq.bits.poke(0x56.U)
|
||||||
|
c.io.deq.valid.expect(true.B)
|
||||||
|
c.io.deq.bits.expect(0x34.U)
|
||||||
|
c.clock.step()
|
||||||
|
// dequeueing back-to-back should work without any holes in the middle
|
||||||
|
c.io.deq.ready.poke(true.B)
|
||||||
|
c.io.enq.valid.poke(false.B)
|
||||||
|
c.io.deq.valid.expect(true.B)
|
||||||
|
c.io.deq.bits.expect(0x56.U)
|
||||||
|
c.clock.step()
|
||||||
|
// make sure is empty
|
||||||
|
c.io.deq.ready.poke(true.B)
|
||||||
|
c.io.enq.valid.poke(false.B)
|
||||||
|
c.io.deq.valid.expect(false.B)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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.poke(0.U)
|
c.io.invalidate.poke(0.U)
|
||||||
|
|||||||
Reference in New Issue
Block a user