summaryrefslogtreecommitdiff
path: root/chiselFrontend
diff options
context:
space:
mode:
authorAlbert Magyar2017-11-22 17:51:51 -0800
committerRichard Lin2018-01-02 13:41:32 -0800
commit11c1112661e04094bccfd805e737e0318eb91ebc (patch)
tree185ea171a05d289ea8ff2ed1525b40f14c50a3bb /chiselFrontend
parent7c3c18de2ffd56af51b99030c7ae7d3a321aed5f (diff)
Add auto clone implementation for inner Bundles (#722)
Diffstat (limited to 'chiselFrontend')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala25
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Data.scala7
2 files changed, 32 insertions, 0 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index d4d67018..da14cefd 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -5,6 +5,7 @@ package chisel3.core
import scala.collection.immutable.ListMap
import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap}
import scala.language.experimental.macros
+import scala.util.Try
import chisel3.internal._
import chisel3.internal.Builder.pushCommand
@@ -574,6 +575,30 @@ class Bundle(implicit compileOptions: CompileOptions) extends Record {
Builder.exception(s"Unable to automatically infer cloneType on $this: $desc")
}
+ // Check if the bundle is an instance of an inner class by examining
+ // whether it has one one-argument constructor taking a type matching the enclosing class
+ if (this.getClass.getConstructors.size == 1) {
+ val aggClass = this.getClass
+ val constr = aggClass.getConstructors.head
+ val argTypes = constr.getParameterTypes
+ val outerClass = aggClass.getEnclosingClass
+ if (argTypes.size == 1 && outerClass != null) {
+ // attempt to clone using "$outer"
+ var clone: Option[this.type] =
+ Try[this.type](constr.newInstance(aggClass.getDeclaredField("$outer").get(this)).asInstanceOf[this.type]).toOption
+ if (clone.isEmpty) {
+ // fall back to outerModule field
+ clone = Try[this.type](constr.newInstance(outerModule.get).asInstanceOf[this.type]).toOption
+ }
+ clone.foreach(_.outerModule = this.outerModule)
+ if (clone.isDefined) {
+ return clone.get
+ } else {
+ reflectError("non-trivial inner Bundle class")
+ }
+ }
+ }
+
// Try Scala reflection
import scala.reflect.runtime.universe._
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
index 19adf01b..d84a86e9 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
@@ -208,6 +208,13 @@ abstract class Data extends HasId {
}
}
+ // If this Data is an instance of an inner class, record enclosing class
+ // This is only used for cloneType!
+ private[core] var outerModule: Option[BaseModule] =
+ (Option(this.getClass.getEnclosingClass) zip Builder.currentModule)
+ .find({ case (c, m) => c.isAssignableFrom(m.getClass) })
+ .map({ case (_, m) => m })
+
// User-specified direction, local at this node only.
// Note that the actual direction of this node can differ from child and parent specifiedDirection.
private var _specifiedDirection: SpecifiedDirection = SpecifiedDirection.Unspecified