summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Milovanović2021-02-08 20:55:48 +0100
committerGitHub2021-02-08 19:55:48 +0000
commit2ed343e2305b7c22000f3f46fa81d73a369907eb (patch)
treecbd5c95160efd1c180f89c29e1b1ca5a40d32e65
parente3b6cf4e7230ce12174832fca48d1384553b02f6 (diff)
Parametrized Mem- & SyncReadMem-based implementation of the Queue class (#1740)
* Added SyncReadMem-based implementation of the Queue class * Rework of the parametrized Queue class SyncReadMem-based implementation * Modification of the parametrized Queue class SyncReadMem-based implementation * Limiting the visibility of the read address for SyncReadMem-based Queue Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
-rw-r--r--src/main/scala/chisel3/util/Decoupled.scala26
-rw-r--r--src/test/scala/chiselTests/QueueSpec.scala56
2 files changed, 47 insertions, 35 deletions
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala
index 032d731d..006001ec 100644
--- a/src/main/scala/chisel3/util/Decoupled.scala
+++ b/src/main/scala/chisel3/util/Decoupled.scala
@@ -186,6 +186,7 @@ class QueueIO[T <: Data](private val gen: T, val entries: Int) extends Bundle
* combinationally coupled.
* @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately).
* The ''valid'' signals are coupled.
+ * @param useSyncReadMem True uses SyncReadMem instead of Mem as an internal memory element.
*
* @example {{{
* val q = Module(new Queue(UInt(), 16))
@@ -197,7 +198,8 @@ class QueueIO[T <: Data](private val gen: T, val entries: Int) extends Bundle
class Queue[T <: Data](val gen: T,
val entries: Int,
val pipe: Boolean = false,
- val flow: Boolean = false)
+ val flow: Boolean = false,
+ val useSyncReadMem: Boolean = false)
(implicit compileOptions: chisel3.CompileOptions)
extends Module() {
require(entries > -1, "Queue must have non-negative number of entries")
@@ -215,7 +217,7 @@ class Queue[T <: Data](val gen: T,
val io = IO(new QueueIO(genType, entries))
- val ram = Mem(entries, genType)
+ val ram = if (useSyncReadMem) SyncReadMem(entries, genType, SyncReadMem.WriteFirst) else Mem(entries, genType)
val enq_ptr = Counter(entries)
val deq_ptr = Counter(entries)
val maybe_full = RegInit(false.B)
@@ -239,7 +241,15 @@ class Queue[T <: Data](val gen: T,
io.deq.valid := !empty
io.enq.ready := !full
- io.deq.bits := ram(deq_ptr.value)
+
+ if (useSyncReadMem) {
+ val deq_ptr_next = Mux(deq_ptr.value === (entries.U - 1.U), 0.U, deq_ptr.value + 1.U)
+ val r_addr = WireDefault(Mux(do_deq, deq_ptr_next, deq_ptr.value))
+ io.deq.bits := ram.read(r_addr)
+ }
+ else {
+ io.deq.bits := ram(deq_ptr.value)
+ }
if (flow) {
when (io.enq.valid) { io.deq.valid := true.B }
@@ -285,7 +295,8 @@ object Queue
enq: ReadyValidIO[T],
entries: Int = 2,
pipe: Boolean = false,
- flow: Boolean = false): DecoupledIO[T] = {
+ flow: Boolean = false,
+ useSyncReadMem: Boolean = false): DecoupledIO[T] = {
if (entries == 0) {
val deq = Wire(new DecoupledIO(chiselTypeOf(enq.bits)))
deq.valid := enq.valid
@@ -293,7 +304,7 @@ object Queue
enq.ready := deq.ready
deq
} else {
- val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow))
+ val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem))
q.io.enq.valid := enq.valid // not using <> so that override is allowed
q.io.enq.bits := enq.bits
enq.ready := q.io.enq.ready
@@ -311,8 +322,9 @@ object Queue
enq: ReadyValidIO[T],
entries: Int = 2,
pipe: Boolean = false,
- flow: Boolean = false): IrrevocableIO[T] = {
- val deq = apply(enq, entries, pipe, flow)
+ flow: Boolean = false,
+ useSyncReadMem: Boolean = false): IrrevocableIO[T] = {
+ val deq = apply(enq, entries, pipe, flow, useSyncReadMem)
require(entries > 0, "Zero-entry queues don't guarantee Irrevocability")
val irr = Wire(new IrrevocableIO(chiselTypeOf(deq.bits)))
irr.bits := deq.bits
diff --git a/src/test/scala/chiselTests/QueueSpec.scala b/src/test/scala/chiselTests/QueueSpec.scala
index 9dc7f120..3555a13c 100644
--- a/src/test/scala/chiselTests/QueueSpec.scala
+++ b/src/test/scala/chiselTests/QueueSpec.scala
@@ -9,8 +9,8 @@ import chisel3.testers.BasicTester
import chisel3.util._
import chisel3.util.random.LFSR
-class ThingsPassThroughTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int) extends BasicTester {
- val q = Module(new Queue(UInt(bitWidth.W), queueDepth))
+class ThingsPassThroughTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int, useSyncReadMem: Boolean) extends BasicTester {
+ val q = Module(new Queue(UInt(bitWidth.W), queueDepth, useSyncReadMem = useSyncReadMem))
val elems = VecInit(elements.map {
_.asUInt()
})
@@ -34,8 +34,8 @@ class ThingsPassThroughTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int
}
}
-class QueueReasonableReadyValid(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int) extends BasicTester {
- val q = Module(new Queue(UInt(bitWidth.W), queueDepth))
+class QueueReasonableReadyValid(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int, useSyncReadMem: Boolean) extends BasicTester {
+ val q = Module(new Queue(UInt(bitWidth.W), queueDepth, useSyncReadMem = useSyncReadMem))
val elems = VecInit(elements.map {
_.asUInt()
})
@@ -62,8 +62,8 @@ class QueueReasonableReadyValid(elements: Seq[Int], queueDepth: Int, bitWidth: I
}
}
-class CountIsCorrectTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int) extends BasicTester {
- val q = Module(new Queue(UInt(bitWidth.W), queueDepth))
+class CountIsCorrectTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int, useSyncReadMem: Boolean) extends BasicTester {
+ val q = Module(new Queue(UInt(bitWidth.W), queueDepth, useSyncReadMem = useSyncReadMem))
val elems = VecInit(elements.map {
_.asUInt(bitWidth.W)
})
@@ -89,8 +89,8 @@ class CountIsCorrectTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, t
}
}
-class QueueSinglePipeTester(elements: Seq[Int], bitWidth: Int, tap: Int) extends BasicTester {
- val q = Module(new Queue(UInt(bitWidth.W), 1, pipe = true))
+class QueueSinglePipeTester(elements: Seq[Int], bitWidth: Int, tap: Int, useSyncReadMem: Boolean) extends BasicTester {
+ val q = Module(new Queue(UInt(bitWidth.W), 1, pipe = true, useSyncReadMem = useSyncReadMem))
val elems = VecInit(elements.map {
_.asUInt(bitWidth.W)
})
@@ -115,8 +115,8 @@ class QueueSinglePipeTester(elements: Seq[Int], bitWidth: Int, tap: Int) extends
}
}
-class QueuePipeTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int) extends BasicTester {
- val q = Module(new Queue(UInt(bitWidth.W), queueDepth, pipe = true))
+class QueuePipeTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int, useSyncReadMem: Boolean) extends BasicTester {
+ val q = Module(new Queue(UInt(bitWidth.W), queueDepth, pipe = true, useSyncReadMem = useSyncReadMem))
val elems = VecInit(elements.map {
_.asUInt(bitWidth.W)
})
@@ -141,8 +141,8 @@ class QueuePipeTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: I
}
}
-class QueueFlowTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int) extends BasicTester {
- val q = Module(new Queue(UInt(bitWidth.W), queueDepth, flow = true))
+class QueueFlowTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int, useSyncReadMem: Boolean) extends BasicTester {
+ val q = Module(new Queue(UInt(bitWidth.W), queueDepth, flow = true, useSyncReadMem = useSyncReadMem))
val elems = VecInit(elements.map {
_.asUInt()
})
@@ -169,9 +169,9 @@ class QueueFlowTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: I
}
}
-class QueueFactoryTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int) extends BasicTester {
+class QueueFactoryTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: Int, useSyncReadMem: Boolean) extends BasicTester {
val enq = Wire(Decoupled(UInt(bitWidth.W)))
- val deq = Queue(enq, queueDepth)
+ val deq = Queue(enq, queueDepth, useSyncReadMem = useSyncReadMem)
val elems = VecInit(elements.map {
_.asUInt()
@@ -202,70 +202,70 @@ class QueueSpec extends ChiselPropSpec {
implicit val noShrinkInt = Shrink[Int](_ => Stream.empty)
property("Queue should have things pass through") {
- forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15)) { (depth, se, tap) =>
+ forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15), Gen.oneOf(true, false)) { (depth, se, tap, isSync) =>
whenever(se._1 >= 1 && depth >= 1 && se._2.nonEmpty) {
assertTesterPasses {
- new ThingsPassThroughTester(se._2, depth, se._1, tap)
+ new ThingsPassThroughTester(se._2, depth, se._1, tap, isSync)
}
}
}
}
property("Queue should have reasonable ready/valid") {
- forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15)) { (depth, se, tap) =>
+ forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15), Gen.oneOf(true, false)) { (depth, se, tap, isSync) =>
whenever(se._1 >= 1 && depth >= 1 && se._2.nonEmpty) {
assertTesterPasses {
- new QueueReasonableReadyValid(se._2, depth, se._1, tap)
+ new QueueReasonableReadyValid(se._2, depth, se._1, tap, isSync)
}
}
}
}
property("Queue should have correct count") {
- forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15)) { (depth, se, tap) =>
+ forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15), Gen.oneOf(true, false)) { (depth, se, tap, isSync) =>
whenever(se._1 >= 1 && depth >= 1 && se._2.nonEmpty) {
assertTesterPasses {
- new CountIsCorrectTester(se._2, depth, se._1, tap)
+ new CountIsCorrectTester(se._2, depth, se._1, tap, isSync)
}
}
}
}
property("Queue pipe should work for 1-element queues") {
- forAll(safeUIntN(20), Gen.choose(0, 15)) { (se, tap) =>
+ forAll(safeUIntN(20), Gen.choose(0, 15), Gen.oneOf(true, false)) { (se, tap, isSync) =>
whenever(se._1 >= 1 && se._2.nonEmpty) {
assertTesterPasses {
- new QueueSinglePipeTester(se._2, se._1, tap)
+ new QueueSinglePipeTester(se._2, se._1, tap, isSync)
}
}
}
}
property("Queue pipe should work for more general queues") {
- forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15)) { (depth, se, tap) =>
+ forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15), Gen.oneOf(true, false)) { (depth, se, tap, isSync) =>
whenever(se._1 >= 1 && depth >= 1 && se._2.nonEmpty) {
assertTesterPasses {
- new QueuePipeTester(se._2, depth, se._1, tap)
+ new QueuePipeTester(se._2, depth, se._1, tap, isSync)
}
}
}
}
property("Queue flow should work") {
- forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15)) { (depth, se, tap) =>
+ forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15), Gen.oneOf(true, false)) { (depth, se, tap, isSync) =>
whenever(se._1 >= 1 && depth >= 1 && se._2.nonEmpty) {
assertTesterPasses {
- new QueueFlowTester(se._2, depth, se._1, tap)
+ new QueueFlowTester(se._2, depth, se._1, tap, isSync)
}
}
}
}
property("Queue companion object factory method should work") {
- forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15)) { (depth, se, tap) =>
+ forAll(vecSizes, safeUIntN(20), Gen.choose(0, 15), Gen.oneOf(true, false)) { (depth, se, tap, isSync) =>
whenever(se._1 >= 1 && se._2.nonEmpty) {
assertTesterPasses {
- new QueueFactoryTester(se._2, depth, se._1, tap)
+ new QueueFactoryTester(se._2, depth, se._1, tap, isSync)
}
}
}