summaryrefslogtreecommitdiff
path: root/src/main/scala/chisel3/util/Decoupled.scala
diff options
context:
space:
mode:
authorJack2022-01-12 04:27:19 +0000
committerJack2022-01-12 04:27:19 +0000
commit29df513e348cc809876893f650af8180f0190496 (patch)
tree06daaea954b4e5af7113f06e4bdbb78b33515cb3 /src/main/scala/chisel3/util/Decoupled.scala
parent5242ce90659decb9058ee75db56e5c188029fbf9 (diff)
parent747d16311bdf185d2e98e452b14cb5d8ccca004c (diff)
Merge branch 'master' into 3.5-release
Diffstat (limited to 'src/main/scala/chisel3/util/Decoupled.scala')
-rw-r--r--src/main/scala/chisel3/util/Decoupled.scala157
1 files changed, 87 insertions, 70 deletions
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala
index 4b8b3eeb..5c71a4ea 100644
--- a/src/main/scala/chisel3/util/Decoupled.scala
+++ b/src/main/scala/chisel3/util/Decoupled.scala
@@ -6,8 +6,8 @@
package chisel3.util
import chisel3._
-import chisel3.experimental.{DataMirror, Direction, requireIsChiselType}
-import chisel3.internal.naming._ // can't use chisel3_ version because of compile order
+import chisel3.experimental.{requireIsChiselType, DataMirror, Direction}
+import chisel3.internal.naming._ // can't use chisel3_ version because of compile order
/** An I/O Bundle containing 'valid' and 'ready' signals that handshake
* the transfer of data stored in the 'bits' subfield.
@@ -18,40 +18,41 @@ import chisel3.internal.naming._ // can't use chisel3_ version because of compi
* @param gen the type of data to be wrapped in Ready/Valid
* @groupdesc Signals The actual hardware fields of the Bundle
*/
-abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle
-{
+abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle {
// Compatibility hack for rocket-chip
private val genType = (DataMirror.internal.isSynthesizable(gen), chisel3.internal.Builder.currentModule) match {
- case (true, Some(module: Module))
- if !module.compileOptions.declaredTypeMustBeUnbound => chiselTypeOf(gen)
+ case (true, Some(module: Module)) if !module.compileOptions.declaredTypeMustBeUnbound => chiselTypeOf(gen)
case _ => gen
}
-/** Indicates that the consumer is ready to accept the data this cycle
- * @group Signals
- */
+ /** Indicates that the consumer is ready to accept the data this cycle
+ * @group Signals
+ */
val ready = Input(Bool())
-
-/** Indicates that the producer has put valid data in 'bits'
- * @group Signals
- */
+
+ /** Indicates that the producer has put valid data in 'bits'
+ * @group Signals
+ */
val valid = Output(Bool())
-
-/** The data to be transferred when ready and valid are asserted at the same cycle
- * @group Signals
- */
- val bits = Output(genType)
+
+ /** The data to be transferred when ready and valid are asserted at the same cycle
+ * @group Signals
+ */
+ val bits = Output(genType)
}
object ReadyValidIO {
- implicit class AddMethodsToReadyValid[T<:Data](target: ReadyValidIO[T]) {
+ implicit class AddMethodsToReadyValid[T <: Data](target: ReadyValidIO[T]) {
/** Indicates if IO is both ready and valid
- */
+ */
def fire: Bool = target.ready && target.valid
- @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ @deprecated(
+ "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead",
+ "Chisel 3.5"
+ )
def fire(dummy: Int = 0): Bool = fire
/** Push dat onto the output bits of this interface to let the consumer know it has happened.
@@ -99,8 +100,8 @@ object ReadyValidIO {
class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen)
/** This factory adds a decoupled handshaking protocol to a data bundle. */
-object Decoupled
-{
+object Decoupled {
+
/** Wraps some Data with a DecoupledIO interface. */
def apply[T <: Data](gen: T): DecoupledIO[T] = new DecoupledIO(gen)
@@ -110,6 +111,7 @@ object Decoupled
// Both of these methods return DecoupledIO parameterized by the most generic type: Data
/** Returns a [[DecoupledIO]] inteface with no payload */
def apply(): DecoupledIO[Data] = apply(new EmptyBundle)
+
/** Returns a [[DecoupledIO]] inteface with no payload */
def empty: DecoupledIO[Data] = Decoupled()
@@ -119,7 +121,10 @@ object Decoupled
*/
@chiselName
def apply[T <: Data](irr: IrrevocableIO[T]): DecoupledIO[T] = {
- require(DataMirror.directionOf(irr.bits) == Direction.Output, "Only safe to cast produced Irrevocable bits to Decoupled.")
+ require(
+ DataMirror.directionOf(irr.bits) == Direction.Output,
+ "Only safe to cast produced Irrevocable bits to Decoupled."
+ )
val d = Wire(new DecoupledIO(chiselTypeOf(irr.bits)))
d.bits := irr.bits
d.valid := irr.valid
@@ -138,8 +143,7 @@ object Decoupled
class IrrevocableIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen)
/** Factory adds an irrevocable handshaking protocol to a data bundle. */
-object Irrevocable
-{
+object Irrevocable {
def apply[T <: Data](gen: T): IrrevocableIO[T] = new IrrevocableIO(gen)
/** Upconverts a DecoupledIO input to an IrrevocableIO, allowing an IrrevocableIO to be used
@@ -148,7 +152,10 @@ object Irrevocable
* @note unsafe (and will error) on the consumer (output) side of an DecoupledIO
*/
def apply[T <: Data](dec: DecoupledIO[T]): IrrevocableIO[T] = {
- require(DataMirror.directionOf(dec.bits) == Direction.Input, "Only safe to cast consumed Decoupled bits to Irrevocable.")
+ require(
+ DataMirror.directionOf(dec.bits) == Direction.Input,
+ "Only safe to cast consumed Decoupled bits to Irrevocable."
+ )
val i = Wire(new IrrevocableIO(chiselTypeOf(dec.bits)))
dec.bits := i.bits
dec.valid := i.valid
@@ -161,13 +168,14 @@ object Irrevocable
* @param gen The type of data to enqueue
*/
object EnqIO {
- def apply[T<:Data](gen: T): DecoupledIO[T] = Decoupled(gen)
+ def apply[T <: Data](gen: T): DecoupledIO[T] = Decoupled(gen)
}
+
/** Consumer - drives (outputs) ready, inputs valid and bits.
* @param gen The type of data to dequeue
*/
object DeqIO {
- def apply[T<:Data](gen: T): DecoupledIO[T] = Flipped(Decoupled(gen))
+ def apply[T <: Data](gen: T): DecoupledIO[T] = Flipped(Decoupled(gen))
}
/** An I/O Bundle for Queues
@@ -176,28 +184,34 @@ object DeqIO {
* @param hasFlush A boolean for whether the generated Queue is flushable
* @groupdesc Signals The hardware fields of the 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.
+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,
* but internally, the queue implementation itself sits on the other side
* of the interface so uses the flipped instance.
*/
- /** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped.
+ /** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped.
* @group Signals
*/
val enq = Flipped(EnqIO(gen))
+
/** I/O to dequeue data (client is consumer and Queue object is producer), is [[Chisel.DecoupledIO]]
* @group Signals
*/
val deq = Flipped(DeqIO(gen))
- /** The current amount of data in the queue
+
+ /** The current amount of data in the queue
* @group Signals
*/
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)
* @group Signals
- */
+ */
val flush = if (hasFlush) Some(Input(Bool())) else None
}
@@ -218,13 +232,15 @@ class QueueIO[T <: Data](private val gen: T, val entries: Int, val hasFlush: Boo
* }}}
*/
@chiselName
-class Queue[T <: Data](val gen: T,
- val entries: Int,
- val pipe: Boolean = false,
- val flow: Boolean = false,
- val useSyncReadMem: Boolean = false,
- val hasFlush: Boolean = false)
- (implicit compileOptions: chisel3.CompileOptions)
+class Queue[T <: Data](
+ val gen: T,
+ val entries: Int,
+ val pipe: Boolean = false,
+ val flow: 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")
require(entries != 0, "Use companion object Queue.apply for zero entries")
@@ -253,21 +269,21 @@ class Queue[T <: Data](val gen: T,
// when flush is high, empty the queue
// Semantically, any enqueues happen before the flush.
- when (do_enq) {
+ when(do_enq) {
ram(enq_ptr.value) := io.enq.bits
enq_ptr.inc()
}
- when (do_deq) {
+ when(do_deq) {
deq_ptr.inc()
}
- when (do_enq =/= do_deq) {
+ 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
@@ -276,22 +292,21 @@ class Queue[T <: Data](val gen: T,
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 {
+ } else {
io.deq.bits := ram(deq_ptr.value)
}
if (flow) {
- when (io.enq.valid) { io.deq.valid := true.B }
- when (empty) {
+ when(io.enq.valid) { io.deq.valid := true.B }
+ when(empty) {
io.deq.bits := io.enq.bits
do_deq := false.B
- when (io.deq.ready) { do_enq := false.B }
+ when(io.deq.ready) { do_enq := false.B }
}
}
if (pipe) {
- when (io.deq.ready) { io.enq.ready := true.B }
+ when(io.deq.ready) { io.enq.ready := true.B }
}
val ptr_diff = enq_ptr.value - deq_ptr.value
@@ -299,17 +314,17 @@ class Queue[T <: Data](val gen: T,
if (isPow2(entries)) {
io.count := Mux(maybe_full && ptr_match, entries.U, 0.U) | ptr_diff
} else {
- io.count := Mux(ptr_match,
- Mux(maybe_full,
- entries.asUInt, 0.U),
- Mux(deq_ptr.value > enq_ptr.value,
- entries.asUInt + ptr_diff, ptr_diff))
+ io.count := Mux(
+ ptr_match,
+ Mux(maybe_full, entries.asUInt, 0.U),
+ Mux(deq_ptr.value > enq_ptr.value, entries.asUInt + ptr_diff, ptr_diff)
+ )
}
}
/** Factory for a generic hardware queue. */
-object Queue
-{
+object Queue {
+
/** Create a [[Queue]] and supply a [[DecoupledIO]] containing the product.
*
* @param enq input (enqueue) interface to the queue, also determines type of queue elements.
@@ -329,12 +344,13 @@ object Queue
*/
@chiselName
def apply[T <: Data](
- enq: ReadyValidIO[T],
- entries: Int = 2,
- pipe: Boolean = false,
- flow: Boolean = false,
- useSyncReadMem: Boolean = false,
- flush: Option[Bool] = None): DecoupledIO[T] = {
+ enq: ReadyValidIO[T],
+ entries: Int = 2,
+ pipe: Boolean = false,
+ flow: Boolean = false,
+ useSyncReadMem: Boolean = false,
+ flush: Option[Bool] = None
+ ): DecoupledIO[T] = {
if (entries == 0) {
val deq = Wire(new DecoupledIO(chiselTypeOf(enq.bits)))
deq.valid := enq.valid
@@ -373,12 +389,13 @@ object Queue
*/
@chiselName
def irrevocable[T <: Data](
- enq: ReadyValidIO[T],
- entries: Int = 2,
- pipe: Boolean = false,
- flow: Boolean = false,
- useSyncReadMem: Boolean = false,
- flush: Option[Bool] = None): IrrevocableIO[T] = {
+ enq: ReadyValidIO[T],
+ entries: Int = 2,
+ pipe: Boolean = false,
+ flow: Boolean = false,
+ useSyncReadMem: Boolean = false,
+ flush: Option[Bool] = None
+ ): IrrevocableIO[T] = {
val deq = apply(enq, entries, pipe, flow, useSyncReadMem, flush)
require(entries > 0, "Zero-entry queues don't guarantee Irrevocability")
val irr = Wire(new IrrevocableIO(chiselTypeOf(deq.bits)))