summaryrefslogtreecommitdiff
path: root/src/main/scala
diff options
context:
space:
mode:
authoranniej-sifive2021-08-03 16:09:19 -0700
committerGitHub2021-08-03 16:09:19 -0700
commitda923f317ff325a93cee6289552ccfa413c35f98 (patch)
tree59f30f6d3e11bc5fb533eafe163c255525885915 /src/main/scala
parent1e7829eb674eed85a4cd537896d9fd9ee0bc5ff4 (diff)
Added flush capability to Queue (#2030)
Co-authored-by: Megan Wachs <megan@sifive.com> Co-authored-by: Deborah Soung <debs@sifive.com>
Diffstat (limited to 'src/main/scala')
-rw-r--r--src/main/scala/chisel3/util/Decoupled.scala29
1 files changed, 21 insertions, 8 deletions
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala
index 33682020..8909ffe3 100644
--- a/src/main/scala/chisel3/util/Decoupled.scala
+++ b/src/main/scala/chisel3/util/Decoupled.scala
@@ -163,8 +163,9 @@ object DeqIO {
/** An I/O Bundle for Queues
* @param gen The type of data to queue
* @param entries The max number of entries in the queue.
+ * @param hasFlush A boolean for whether the generated Queue is flushable
*/
-class QueueIO[T <: Data](private val gen: T, val entries: Int) extends Bundle
+class QueueIO[T <: Data](private val gen: T, val entries: Int, val hasFlush: Boolean = false) extends Bundle
{ // See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs.
/* These may look inverted, because the names (enq/deq) are from the perspective of the client,
@@ -177,6 +178,9 @@ class QueueIO[T <: Data](private val gen: T, val entries: Int) extends Bundle
val deq = Flipped(DeqIO(gen))
/** The current amount of data in the queue */
val count = Output(UInt(log2Ceil(entries + 1).W))
+ /** When asserted, reset the enqueue and dequeue pointers, effectively flushing the queue (Optional IO for a flushable Queue)*/
+ val flush = if (hasFlush) Some(Input(Bool())) else None
+
}
/** A hardware module implementing a Queue
@@ -187,7 +191,7 @@ class QueueIO[T <: Data](private val gen: T, val entries: Int) extends Bundle
* @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.
- *
+ * @param hasFlush True if generated queue requires a flush feature
* @example {{{
* val q = Module(new Queue(UInt(), 16))
* q.io.enq <> producer.io.out
@@ -199,7 +203,8 @@ class Queue[T <: Data](val gen: T,
val entries: Int,
val pipe: Boolean = false,
val flow: Boolean = false,
- val useSyncReadMem: Boolean = false)
+ val useSyncReadMem: Boolean = false,
+ val hasFlush: Boolean = false)
(implicit compileOptions: chisel3.CompileOptions)
extends Module() {
require(entries > -1, "Queue must have non-negative number of entries")
@@ -215,19 +220,20 @@ class Queue[T <: Data](val gen: T,
}
}
- val io = IO(new QueueIO(genType, entries))
-
+ val io = IO(new QueueIO(genType, entries, hasFlush))
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)
-
val ptr_match = enq_ptr.value === deq_ptr.value
val empty = ptr_match && !maybe_full
val full = ptr_match && maybe_full
val do_enq = WireDefault(io.enq.fire())
val do_deq = WireDefault(io.deq.fire())
+ val flush = io.flush.getOrElse(false.B)
+ // when flush is high, empty the queue
+ // Semantically, any enqueues happen before the flush.
when (do_enq) {
ram(enq_ptr.value) := io.enq.bits
enq_ptr.inc()
@@ -238,6 +244,11 @@ class Queue[T <: Data](val gen: T,
when (do_enq =/= do_deq) {
maybe_full := do_enq
}
+ when(flush) {
+ enq_ptr.reset()
+ deq_ptr.reset()
+ maybe_full := false.B
+ }
io.deq.valid := !empty
io.enq.ready := !full
@@ -265,6 +276,7 @@ class Queue[T <: Data](val gen: T,
}
val ptr_diff = enq_ptr.value - deq_ptr.value
+
if (isPow2(entries)) {
io.count := Mux(maybe_full && ptr_match, entries.U, 0.U) | ptr_diff
} else {
@@ -296,7 +308,8 @@ object Queue
entries: Int = 2,
pipe: Boolean = false,
flow: Boolean = false,
- useSyncReadMem: Boolean = false): DecoupledIO[T] = {
+ useSyncReadMem: Boolean = false,
+ hasFlush: Boolean = false): DecoupledIO[T] = {
if (entries == 0) {
val deq = Wire(new DecoupledIO(chiselTypeOf(enq.bits)))
deq.valid := enq.valid
@@ -304,7 +317,7 @@ object Queue
enq.ready := deq.ready
deq
} else {
- val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem))
+ val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem, hasFlush))
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