summaryrefslogtreecommitdiff
path: root/chiselFrontend/src
diff options
context:
space:
mode:
Diffstat (limited to 'chiselFrontend/src')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala140
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala16
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Binding.scala6
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala2
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Data.scala4
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Module.scala2
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala12
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Builder.scala2
8 files changed, 109 insertions, 75 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index 559a55bc..732bf8fc 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -335,50 +335,93 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId {
SeqUtils.oneHotMux(indexWhereHelper(p))
}
-/** Base class for data types defined as a bundle of other data types.
+/** Base class for Aggregates based on key values pairs of String and Data
*
- * Usage: extend this class (either as an anonymous or named class) and define
- * members variables of [[Data]] subtypes to be elements in the Bundle.
+ * Record should only be extended by libraries and fairly sophisticated generators.
+ * RTL writers should use [[Bundle]].
*/
-class Bundle extends Aggregate {
- private val _namespace = Builder.globalNamespace.child
+abstract class Record extends Aggregate {
- // TODO: replace with better defined FIRRTL weak-connect operator
- /** Connect elements in this Bundle to elements in `that` on a best-effort
- * (weak) basis, matching by type, orientation, and name.
- *
- * @note unconnected elements will NOT generate errors or warnings
+ /** The collection of [[Data]]
*
- * @example
+ * This underlying datastructure is a ListMap because the elements must
+ * remain ordered for serialization/deserialization. Elements added later
+ * are higher order when serialized (this is similar to [[Vec]]). For example:
* {{{
- * // Pass through wires in this module's io to those mySubModule's io,
- * // matching by type, orientation, and name, and ignoring extra wires.
- * mySubModule.io <> io
+ * // Assume we have some type MyRecord that creates a Record from the ListMap
+ * val record = MyRecord(ListMap("fizz" -> UInt(16.W), "buzz" -> UInt(16.W)))
+ * // "buzz" is higher order because it was added later than "fizz"
+ * record("fizz") := "hdead".U
+ * record("buzz") := "hbeef".U
+ * val uint = record.asUInt
+ * assert(uint === "hbeefdead".U) // This will pass
* }}}
*/
+ val elements: ListMap[String, Data]
- lazy val elements: ListMap[String, Data] = ListMap(namedElts:_*)
+ /** Name for Pretty Printing */
+ def className: String = this.getClass.getSimpleName
- /** Returns a best guess at whether a field in this Bundle is a user-defined
- * Bundle element without looking at type signatures.
- */
- private def isBundleField(m: java.lang.reflect.Method) =
- m.getParameterTypes.isEmpty &&
- !java.lang.reflect.Modifier.isStatic(m.getModifiers) &&
- !(Bundle.keywords contains m.getName) && !(m.getName contains '$')
+ private[chisel3] def toType = {
+ def eltPort(elt: Data): String = {
+ val flipStr: String = if(Data.isFirrtlFlipped(elt)) "flip " else ""
+ s"${flipStr}${elt.getRef.name} : ${elt.toType}"
+ }
+ elements.toIndexedSeq.reverse.map(e => eltPort(e._2)).mkString("{", ", ", "}")
+ }
- /** Returns a field's contained user-defined Bundle element if it appears to
- * be one, otherwise returns None.
- */
- private def getBundleField(m: java.lang.reflect.Method): Option[Data] = m.invoke(this) match {
- case d: Data => Some(d)
- case Some(d: Data) => Some(d)
- case _ => None
+ private[chisel3] lazy val flatten = elements.toIndexedSeq.flatMap(_._2.flatten)
+
+ // NOTE: This sets up dependent references, it can be done before closing the Module
+ private[chisel3] override def _onModuleClose: Unit = { // scalastyle:ignore method.name
+ val _namespace = Builder.globalNamespace.child
+ for ((name, elt) <- elements) { elt.setRef(this, _namespace.name(name)) }
}
- /** Returns a list of elements in this Bundle.
+ private[chisel3] final def allElements: Seq[Element] = elements.toIndexedSeq.flatMap(_._2.allElements)
+
+ // Helper because Bundle elements are reversed before printing
+ private[chisel3] def toPrintableHelper(elts: Seq[(String, Data)]): Printable = {
+ val xs =
+ if (elts.isEmpty) List.empty[Printable] // special case because of dropRight below
+ else elts flatMap { case (name, data) =>
+ List(PString(s"$name -> "), data.toPrintable, PString(", "))
+ } dropRight 1 // Remove trailing ", "
+ PString(s"$className(") + Printables(xs) + PString(")")
+ }
+ /** Default "pretty-print" implementation
+ * Analogous to printing a Map
+ * Results in "$className(elt0.name -> elt0.value, ...)"
+ */
+ def toPrintable: Printable = toPrintableHelper(elements.toList)
+}
+
+/** Base class for data types defined as a bundle of other data types.
+ *
+ * Usage: extend this class (either as an anonymous or named class) and define
+ * members variables of [[Data]] subtypes to be elements in the Bundle.
+ */
+class Bundle extends Record {
+ override def className = "Bundle"
+
+ /** The collection of [[Data]]
+ *
+ * Elements defined earlier in the Bundle are higher order upon
+ * serialization. For example:
+ * {{{
+ * class MyBundle extends Bundle {
+ * val foo = UInt(16.W)
+ * val bar = UInt(16.W)
+ * }
+ * // Note that foo is higher order because its defined earlier in the Bundle
+ * val bundle = Wire(new MyBundle)
+ * bundle.foo := 0x1234.U
+ * bundle.bar := 0x5678.U
+ * val uint = bundle.asUInt
+ * assert(uint === "h12345678".U) // This will pass
+ * }}}
*/
- private[core] lazy val namedElts = {
+ final lazy val elements: ListMap[String, Data] = {
val nameMap = LinkedHashMap[String, Data]()
val seen = HashSet[Data]()
for (m <- getPublicFields(classOf[Bundle])) {
@@ -391,20 +434,17 @@ class Bundle extends Aggregate {
}
}
}
- ArrayBuffer(nameMap.toSeq:_*) sortWith {case ((an, a), (bn, b)) => (a._id > b._id) || ((a eq b) && (an > bn))}
- }
- private[chisel3] def toType = {
- def eltPort(elt: Data): String = {
- val flipStr: String = if(Data.isFirrtlFlipped(elt)) "flip " else ""
- s"${flipStr}${elt.getRef.name} : ${elt.toType}"
- }
- s"{${namedElts.reverse.map(e => eltPort(e._2)).mkString(", ")}}"
+ ListMap(nameMap.toSeq sortWith { case ((an, a), (bn, b)) => (a._id > b._id) || ((a eq b) && (an > bn)) }: _*)
}
- private[chisel3] lazy val flatten = namedElts.flatMap(_._2.flatten)
- private[chisel3] override def _onModuleClose: Unit = // scalastyle:ignore method.name
- for ((name, elt) <- namedElts) { elt.setRef(this, _namespace.name(name)) }
- private[chisel3] final def allElements: Seq[Element] = namedElts.flatMap(_._2.allElements)
+ /** Returns a field's contained user-defined Bundle element if it appears to
+ * be one, otherwise returns None.
+ */
+ private def getBundleField(m: java.lang.reflect.Method): Option[Data] = m.invoke(this) match {
+ case d: Data => Some(d)
+ case Some(d: Data) => Some(d)
+ case _ => None
+ }
override def cloneType : this.type = {
// If the user did not provide a cloneType method, try invoking one of
@@ -436,20 +476,14 @@ class Bundle extends Aggregate {
/** Default "pretty-print" implementation
* Analogous to printing a Map
* Results in "Bundle(elt0.name -> elt0.value, ...)"
+ * @note The order is reversed from the order of elements in order to print
+ * the fields in the order they were defined
*/
- def toPrintable: Printable = {
- val elts =
- if (elements.isEmpty) List.empty[Printable]
- else {
- elements.toList.reverse flatMap { case (name, data) =>
- List(PString(s"$name -> "), data.toPrintable, PString(", "))
- } dropRight 1 // Remove trailing ", "
- }
- PString("Bundle(") + Printables(elts) + PString(")")
- }
+ override def toPrintable: Printable = toPrintableHelper(elements.toList.reverse)
}
private[core] object Bundle {
val keywords = List("flip", "asInput", "asOutput", "cloneType", "chiselCloneType", "toBits",
"widthOption", "signalName", "signalPathName", "signalParent", "signalComponent")
}
+
diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
index 2599a20a..b17239e7 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
@@ -37,9 +37,9 @@ object BiConnect {
def MismatchedVecException =
BiConnectException(": Left and Right are different length Vecs.")
def MissingLeftFieldException(field: String) =
- BiConnectException(s".$field: Left Bundle missing field ($field).")
+ BiConnectException(s".$field: Left Record missing field ($field).")
def MissingRightFieldException(field: String) =
- BiConnectException(s": Right Bundle missing field ($field).")
+ BiConnectException(s": Right Record missing field ($field).")
def MismatchedException(left: String, right: String) =
BiConnectException(s": Left ($left) and Right ($right) have different types.")
@@ -67,20 +67,20 @@ object BiConnect {
}
}
}
- // Handle Bundle case
- case (left_b: Bundle, right_b: Bundle) => {
+ // Handle Record case
+ case (left_r: Record, right_r: Record) => {
// Verify right has no extra fields that left doesn't have
- for((field, right_sub) <- right_b.elements) {
- if(!left_b.elements.isDefinedAt(field)) {
+ for((field, right_sub) <- right_r.elements) {
+ if(!left_r.elements.isDefinedAt(field)) {
if (connectCompileOptions.connectFieldsMustMatch) {
throw MissingLeftFieldException(field)
}
}
}
// For each field in left, descend with right
- for((field, left_sub) <- left_b.elements) {
+ for((field, left_sub) <- left_r.elements) {
try {
- right_b.elements.get(field) match {
+ right_r.elements.get(field) match {
case Some(right_sub) => connect(sourceInfo, connectCompileOptions, left_sub, right_sub, context_mod)
case None => {
if (connectCompileOptions.connectFieldsMustMatch) {
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
index 3dfde7c2..71c441a7 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
@@ -33,7 +33,7 @@ import chisel3.internal.Builder.{forcedModule}
* Aggregate is considered bound via its elements. May be appropriate to allow
* Aggregates to be bound along with the Elements. However, certain literal and
* port direction information doesn't quite make sense in aggregates. This would
- * elegantly handle the empty Vec or Bundle problem though.
+ * elegantly handle the empty Vec or Record problem though.
*
* TODO(twigg): Binding is currently done via allElements. It may be more
* elegant if this was instead done as a more explicit tree walk as that allows
@@ -73,8 +73,8 @@ object Binding {
}
}
}
- case (bundle: Bundle) => {
- for((field, subelem) <- bundle.elements) {
+ case (record: Record) => {
+ for((field, subelem) <- record.elements) {
try walkToBinding(subelem, checker)
catch {
case BindingException(message) => throw BindingException(s".$field$message")
diff --git a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
index 4dea39b5..4aa3ad33 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
@@ -5,7 +5,7 @@ package chisel3.core
import scala.language.experimental.macros
trait CompileOptions {
- // Should Bundle connections require a strict match of fields.
+ // Should Record connections require a strict match of fields.
// If true and the same fields aren't present in both source and sink, a MissingFieldException,
// MissingLeftFieldException, or MissingRightFieldException will be thrown.
val connectFieldsMustMatch: Boolean
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
index 6e80f045..4f3e2268 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
@@ -66,7 +66,7 @@ object Data {
* Note that the current scheme only applies Flip to Elements or Vec chains of
* Elements.
*
- * A Bundle is never marked flip, instead preferring its root fields to be marked
+ * A Record is never marked flip, instead preferring its root fields to be marked
*
* The Vec check is due to the fact that flip must be factored out of the vec, ie:
* must have flip field: Vec(UInt) instead of field: Vec(flip UInt)
@@ -74,7 +74,7 @@ object Data {
private[chisel3] def isFlipped(target: Data): Boolean = target match {
case (element: Element) => element.binding.direction == Some(Direction.Input)
case (vec: Vec[Data @unchecked]) => isFlipped(vec.sample_element)
- case (bundle: Bundle) => false
+ case (record: Record) => false
}
/** This function returns the "firrtl" flipped-ness for the specified object.
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
index 76a3b240..609f2ccf 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
@@ -141,7 +141,7 @@ extends HasId {
/** IO for this Module. At the Scala level (pre-FIRRTL transformations),
* connections in and out of a Module may only go through `io` elements.
*/
- def io: Bundle
+ def io: Record
val clock = Port(Input(Clock()))
val reset = Port(Input(Bool()))
diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
index fcb14e6f..8b264801 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
@@ -15,7 +15,7 @@ import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfo
*
* The connect operation will recurse down the left Data (with the right Data).
* An exception will be thrown if a movement through the left cannot be matched
-* in the right. The right side is allowed to have extra Bundle fields.
+* in the right. The right side is allowed to have extra Record fields.
* Vecs must still be exactly the same size.
*
* See elemConnect for details on how the root connections are issued.
@@ -45,7 +45,7 @@ object MonoConnect {
def MismatchedVecException =
MonoConnectException(": Sink and Source are different length Vecs.")
def MissingFieldException(field: String) =
- MonoConnectException(s": Source Bundle missing field ($field).")
+ MonoConnectException(s": Source Record missing field ($field).")
def MismatchedException(sink: String, source: String) =
MonoConnectException(s": Sink ($sink) and Source ($source) have different types.")
@@ -73,12 +73,12 @@ object MonoConnect {
}
}
}
- // Handle Bundle case
- case (sink_b: Bundle, source_b: Bundle) => {
+ // Handle Record case
+ case (sink_r: Record, source_r: Record) => {
// For each field, descend with right
- for((field, sink_sub) <- sink_b.elements) {
+ for((field, sink_sub) <- sink_r.elements) {
try {
- source_b.elements.get(field) match {
+ source_r.elements.get(field) match {
case Some(source_sub) => connect(sourceInfo, connectCompileOptions, sink_sub, source_sub, context_mod)
case None => {
if (connectCompileOptions.connectFieldsMustMatch) {
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
index 6e463311..c93dbfc7 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
@@ -92,7 +92,7 @@ private[chisel3] trait HasId extends InstanceId {
// Uses a namespace to convert suggestion into a true name
// Will not do any naming if the reference already assigned.
- // (e.g. tried to suggest a name to part of a Bundle)
+ // (e.g. tried to suggest a name to part of a Record)
private[chisel3] def forceName(default: =>String, namespace: Namespace): Unit =
if(_ref.isEmpty) {
val candidate_name = suggested_name.getOrElse(default)