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.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.bits := req
|
||||
// TODO: deq.ready should respect downstream ready
|
||||
reqQueue.io.deq.ready := true.B
|
||||
reqQueue.io.invalidate := 0.U
|
||||
|
||||
printf(s"reqQueue(${lane}).count=%d\n", reqQueue.io.count)
|
||||
|
||||
// Invalidate coalesced requests
|
||||
// FIXME: hardcoded lanes
|
||||
// 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
|
||||
// FIXME: bogus coalescing logic: coalesce whenever all 4 lanes have valid
|
||||
// queue head
|
||||
coalReqValid := reqQueues(0).io.deq.valid && reqQueues(1).io.deq.valid &&
|
||||
reqQueues(2).io.deq.valid && reqQueues(3).io.deq.valid
|
||||
// coalReqValid := reqQueues(0).io.deq.valid && reqQueues(1).io.deq.valid &&
|
||||
// reqQueues(2).io.deq.valid && reqQueues(3).io.deq.valid
|
||||
coalReqValid := false.B
|
||||
when(coalReqValid) {
|
||||
// invalidate original requests due to coalescing
|
||||
// FIXME: bogus
|
||||
@@ -245,7 +245,9 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
|
||||
val newEntry = Wire(
|
||||
new InflightCoalReqTableEntry(numLanes, numPerLaneReqs, sourceWidth, offsetBits, sizeBits)
|
||||
)
|
||||
|
||||
println(s"=========== table sourceWidth: ${sourceWidth}")
|
||||
|
||||
newEntry.source := coalSourceId
|
||||
newEntry.lanes.foreach { l =>
|
||||
l.reqs.zipWithIndex.foreach { case (r, i) =>
|
||||
@@ -535,11 +537,12 @@ class CoalShiftQueue[T <: Data](
|
||||
def paddedUsed = pad({ i: Int => used(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) {
|
||||
val wdata = if (i == entries - 1) io.enq.bits else Mux(!used(i + 1), io.enq.bits, elts(i + 1))
|
||||
val wen = Mux(
|
||||
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),
|
||||
// enqueue to the first empty slot above the top
|
||||
(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)
|
||||
|
||||
// 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.valid.poke(true.B)
|
||||
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 {
|
||||
test(new CoalShiftQueue(UInt(8.W), 4)) { c =>
|
||||
c.io.invalidate.poke(0.U)
|
||||
|
||||
Reference in New Issue
Block a user