From 23d8fa3be199079259ebe40c289da21ecd41ae35 Mon Sep 17 00:00:00 2001 From: Hansung Kim Date: Mon, 27 Mar 2023 15:21:01 -0700 Subject: [PATCH] Write simple test for MultiPortQueue ... and comment out old CAM-based inflight table test. --- src/main/scala/tilelink/Coalescing.scala | 2 +- src/test/scala/CoalescingUnitTest.scala | 250 ++++++++++++----------- 2 files changed, 127 insertions(+), 125 deletions(-) diff --git a/src/main/scala/tilelink/Coalescing.scala b/src/main/scala/tilelink/Coalescing.scala index 6e43a13..52252f9 100644 --- a/src/main/scala/tilelink/Coalescing.scala +++ b/src/main/scala/tilelink/Coalescing.scala @@ -253,7 +253,7 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule // Take [(off-1)*size:off*size] starting from MSB c := (data >> (dataWidth - (o + 1) * size)) & sizeMask } - chunks(offset) + chunks(offset) // MUX } // Un-coalesce responses back to individual lanes and queue them up diff --git a/src/test/scala/CoalescingUnitTest.scala b/src/test/scala/CoalescingUnitTest.scala index 6417753..afb1af4 100644 --- a/src/test/scala/CoalescingUnitTest.scala +++ b/src/test/scala/CoalescingUnitTest.scala @@ -2,30 +2,29 @@ import chisel3._ import chiseltest._ import org.scalatest.flatspec.AnyFlatSpec import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.MultiPortQueue -class MyModule extends Module { - val io = IO(new Bundle { - val in = Input(UInt(16.W)) - val out = Output(UInt(16.W)) - }) +class MultiPortQueueUnitTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "MultiPortQueue" - io.out := RegNext(io.in) -} - -class BasicTest extends AnyFlatSpec with ChiselScalatestTester { - // test class body here - it should "do something" in { - // test case body here - test(new MyModule) { c => - // test body here - c.io.in.poke(0.U) - c.clock.step() - c.io.out.expect(0.U) - c.io.in.poke(42.U) - c.clock.step() - c.io.out.expect(42.U) - println("Last output value :" + c.io.out.peek().litValue) - } + it should "serialize at dequeue end" in { + test(new MultiPortQueue(UInt(4.W), 3, 1, 3, 6)) + .withAnnotations(Seq(WriteVcdAnnotation)) { c => + c.io.enq(0).valid.poke(true.B) + c.io.enq(0).bits.poke(11.U) + c.io.enq(1).valid.poke(true.B) + c.io.enq(1).bits.poke(15.U) + c.io.enq(2).valid.poke(true.B) + c.io.enq(2).bits.poke(7.U) + c.io.deq(0).ready.poke(true.B) + c.clock.step() + // c.io.enq(0).valid.poke(false.B) + // c.io.enq(1).valid.poke(false.B) + for (_ <- 0 until 100) { + c.clock.step() + } + c.io.deq(0).valid.expect(false.B) + } } } @@ -35,121 +34,124 @@ class CoalescingUnitTest extends AnyFlatSpec with ChiselScalatestTester { val sourceWidth = 2 val entries = 4 + val offsetBits = 4 + val sizeBits = 2 + val inflightCoalReqTableEntry = - new InflightCoalReqTableEntry(numLanes, sourceWidth) + new InflightCoalReqTableEntry(numLanes, sourceWidth, offsetBits, sizeBits) - it should "stop enqueueing when full" in { - test(new InflightCoalReqTable(numLanes, sourceWidth, entries)) { c => - // fill up the table - for (i <- 0 until entries) { - val sourceId = i - c.io.enq.ready.expect(true.B) - c.io.enq.valid.poke(true.B) - c.io.enq.bits.fromLane.poke(0.U) - c.io.enq.bits.respSourceId.poke(sourceId.U) - c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } - c.io.lookup.ready.poke(false.B) - c.clock.step() - } + // it should "stop enqueueing when full" in { + // test(new InflightCoalReqTable(numLanes, sourceWidth, entries)) { c => + // // fill up the table + // for (i <- 0 until entries) { + // val sourceId = i + // c.io.enq.ready.expect(true.B) + // c.io.enq.valid.poke(true.B) + // c.io.enq.bits.fromLane.poke(0.U) + // c.io.enq.bits.respSourceId.poke(sourceId.U) + // c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } + // c.io.lookup.ready.poke(false.B) + // c.clock.step() + // } - // now cannot enqueue any more - c.io.enq.ready.expect(false.B) - c.io.enq.valid.poke(true.B) - c.io.enq.bits.fromLane.poke(0.U) - c.io.enq.bits.respSourceId.poke(0.U) - c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } + // // now cannot enqueue any more + // c.io.enq.ready.expect(false.B) + // c.io.enq.valid.poke(true.B) + // c.io.enq.bits.fromLane.poke(0.U) + // c.io.enq.bits.respSourceId.poke(0.U) + // c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } - c.clock.step() - c.io.enq.ready.expect(false.B) + // c.clock.step() + // c.io.enq.ready.expect(false.B) - // try to lookup all existing entries - for (i <- 0 until entries) { - val sourceId = i - c.io.enq.valid.poke(false.B) - c.io.lookup.ready.poke(true.B) - c.io.lookupSourceId.poke(sourceId) - c.io.lookup.valid.expect(true.B) - c.io.lookup.bits.expect(sourceId) - c.clock.step() - } + // // try to lookup all existing entries + // for (i <- 0 until entries) { + // val sourceId = i + // c.io.enq.valid.poke(false.B) + // c.io.lookup.ready.poke(true.B) + // c.io.lookupSourceId.poke(sourceId) + // c.io.lookup.valid.expect(true.B) + // c.io.lookup.bits.expect(sourceId) + // c.clock.step() + // } - // now the table should be empty - for (i <- 0 until entries) { - val sourceId = i - c.io.enq.valid.poke(false.B) - c.io.lookup.ready.poke(true.B) - c.io.lookupSourceId.poke(sourceId) - c.io.lookup.valid.expect(false.B) - c.clock.step() - } - } - } - it should "lookup matching entry" in { - test(new InflightCoalReqTable(numLanes, sourceWidth, entries)) - .withAnnotations(Seq(WriteVcdAnnotation)) { c => - c.reset.poke(true.B) - c.clock.step(10) - c.reset.poke(false.B) + // // now the table should be empty + // for (i <- 0 until entries) { + // val sourceId = i + // c.io.enq.valid.poke(false.B) + // c.io.lookup.ready.poke(true.B) + // c.io.lookupSourceId.poke(sourceId) + // c.io.lookup.valid.expect(false.B) + // c.clock.step() + // } + // } + // } + // it should "lookup matching entry" in { + // test(new InflightCoalReqTable(numLanes, sourceWidth, entries)) + // .withAnnotations(Seq(WriteVcdAnnotation)) { c => + // c.reset.poke(true.B) + // c.clock.step(10) + // c.reset.poke(false.B) - // enqueue one entry to not match at 0th index - c.io.enq.ready.expect(true.B) - c.io.enq.valid.poke(true.B) - c.io.enq.bits.fromLane.poke(0.U) - c.io.enq.bits.respSourceId.poke(0.U) - c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } + // // enqueue one entry to not match at 0th index + // c.io.enq.ready.expect(true.B) + // c.io.enq.valid.poke(true.B) + // c.io.enq.bits.fromLane.poke(0.U) + // c.io.enq.bits.respSourceId.poke(0.U) + // c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } - c.clock.step() + // c.clock.step() - val targetSourceId = 1.U - c.io.enq.ready.expect(true.B) - c.io.enq.valid.poke(true.B) - c.io.enq.bits.fromLane.poke(0.U) - c.io.enq.bits.respSourceId.poke(targetSourceId) - c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } + // val targetSourceId = 1.U + // c.io.enq.ready.expect(true.B) + // c.io.enq.valid.poke(true.B) + // c.io.enq.bits.fromLane.poke(0.U) + // c.io.enq.bits.respSourceId.poke(targetSourceId) + // c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } - c.clock.step() + // c.clock.step() - c.io.lookup.ready.poke(true.B) - c.io.lookupSourceId.poke(targetSourceId) - c.io.lookup.valid.expect(true.B) - c.io.lookup.bits.expect(targetSourceId) + // c.io.lookup.ready.poke(true.B) + // c.io.lookupSourceId.poke(targetSourceId) + // c.io.lookup.valid.expect(true.B) + // c.io.lookup.bits.expect(targetSourceId) - c.clock.step() + // c.clock.step() - // test if matching entry dequeues after 1 cycle - c.io.lookup.ready.poke(true.B) - c.io.lookupSourceId.poke(targetSourceId) - c.io.lookup.valid.expect(false.B) - } - } - it should "handle lookup and enqueue at the same time" in { - test(new InflightCoalReqTable(numLanes, sourceWidth, entries)) { c => - // fill up the table - val targetSourceId = 1.U - c.io.enq.ready.expect(true.B) - c.io.enq.valid.poke(true.B) - c.io.enq.bits.fromLane.poke(0.U) - c.io.enq.bits.respSourceId.poke(0.U) - c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } - c.clock.step() - c.io.enq.ready.expect(true.B) - c.io.enq.valid.poke(true.B) - c.io.enq.bits.fromLane.poke(0.U) - c.io.enq.bits.respSourceId.poke(targetSourceId) - c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } - c.clock.step() + // // test if matching entry dequeues after 1 cycle + // c.io.lookup.ready.poke(true.B) + // c.io.lookupSourceId.poke(targetSourceId) + // c.io.lookup.valid.expect(false.B) + // } + // } + // it should "handle lookup and enqueue at the same time" in { + // test(new InflightCoalReqTable(numLanes, sourceWidth, entries)) { c => + // // fill up the table + // val targetSourceId = 1.U + // c.io.enq.ready.expect(true.B) + // c.io.enq.valid.poke(true.B) + // c.io.enq.bits.fromLane.poke(0.U) + // c.io.enq.bits.respSourceId.poke(0.U) + // c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } + // c.clock.step() + // c.io.enq.ready.expect(true.B) + // c.io.enq.valid.poke(true.B) + // c.io.enq.bits.fromLane.poke(0.U) + // c.io.enq.bits.respSourceId.poke(targetSourceId) + // c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } + // c.clock.step() - // do both enqueue and lookup at the same cycle - val enqSourceId = 2.U - c.io.enq.ready.expect(true.B) - c.io.enq.valid.poke(true.B) - c.io.enq.bits.fromLane.poke(0.U) - c.io.enq.bits.respSourceId.poke(enqSourceId) - c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } - c.io.lookup.ready.poke(true.B) - c.io.lookupSourceId.poke(targetSourceId) + // // do both enqueue and lookup at the same cycle + // val enqSourceId = 2.U + // c.io.enq.ready.expect(true.B) + // c.io.enq.valid.poke(true.B) + // c.io.enq.bits.fromLane.poke(0.U) + // c.io.enq.bits.respSourceId.poke(enqSourceId) + // c.io.enq.bits.reqSourceIds.foreach { id => id.poke(0.U) } + // c.io.lookup.ready.poke(true.B) + // c.io.lookupSourceId.poke(targetSourceId) - c.clock.step() - } - } + // c.clock.step() + // } + // } }