summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authormergify[bot]2021-11-21 05:45:01 +0000
committerGitHub2021-11-21 05:45:01 +0000
commit7adc8063570994dc87a9bfe151b6800d45e26bbc (patch)
treea69854ddb53c1b6540d78e3eb2b50d589168ccfe /core/src
parentaadd08e1e88947b615749be139ce36f4fbbbedf0 (diff)
parent0a8bc71dde53f45672eb249454262a6a31c27e93 (diff)
Merge branch 'master' into update/sbt-mdoc-2.2.24
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/scala/chisel3/Bits.scala6
-rw-r--r--core/src/main/scala/chisel3/Module.scala81
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala21
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala112
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala54
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala2
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala31
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala102
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala14
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala8
10 files changed, 303 insertions, 128 deletions
diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala
index 81b43483..58ec2585 100644
--- a/core/src/main/scala/chisel3/Bits.scala
+++ b/core/src/main/scala/chisel3/Bits.scala
@@ -310,12 +310,6 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
/** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */
- final def toBools: Seq[Bool] = macro SourceInfoTransform.noArg
-
- @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
- final def toBools(dummy: Int*): Seq[Bool] = macro SourceInfoWhiteboxTransform.noArgDummy
-
- /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */
final def asBools: Seq[Bool] = macro SourceInfoTransform.noArg
@deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index 56dce4d5..7ba24585 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -88,6 +88,16 @@ object Module extends SourceInfoDoc {
def reset: Reset = Builder.forcedReset
/** Returns the current Module */
def currentModule: Option[BaseModule] = Builder.currentModule
+
+ private[chisel3] def do_pseudo_apply[T <: BaseModule](bc: => T)
+ (implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): T = {
+ val parent = Builder.currentModule
+
+ val module: T = bc // bc is actually evaluated here
+
+ module
+ }
}
/** Abstract base class for Modules, which behave much like Verilog modules.
@@ -182,23 +192,33 @@ package experimental {
package internal {
import chisel3.experimental.BaseModule
- import chisel3.experimental.hierarchy.IsInstantiable
+ import chisel3.experimental.hierarchy.{IsInstantiable, Proto, Clone}
object BaseModule {
/** Represents a clone of an underlying object. This is used to support CloneModuleAsRecord and Instance/Definition.
*
* @note We don't actually "clone" anything in the traditional sense but is a placeholder so we lazily clone internal state
*/
- private [chisel3] trait IsClone[+T] {
+ trait IsClone[+T] {
// Underlying object of which this is a clone of
- val _proto: T
- def getProto: T = _proto
- def isACloneOf(a: Any): Boolean = this == a || _proto == a
+ private[chisel3] def getProto: T
+
+ /** Determines whether another object is a clone of the same underlying proto
+ *
+ * @param a
+ */
+ def hasSameProto(a: Any): Boolean = {
+ val aProto = a match {
+ case x: IsClone[BaseModule] => x.getProto
+ case o => o
+ }
+ this == aProto || getProto == aProto
+ }
}
// Private internal class to serve as a _parent for Data in cloned ports
- private[chisel3] class ModuleClone[T <: BaseModule] (val _proto: T) extends PseudoModule with IsClone[T] {
- override def toString = s"ModuleClone(${_proto})"
+ private[chisel3] class ModuleClone[T <: BaseModule] (val getProto: T) extends PseudoModule with IsClone[T] {
+ override def toString = s"ModuleClone(${getProto})"
def getPorts = _portsRecord
// ClonePorts that hold the bound ports for this module
// Used for setting the refs of both this module and the Record
@@ -211,19 +231,19 @@ package internal {
private[chisel3] def generateComponent(): Option[Component] = {
require(!_closed, "Can't generate module more than once")
_closed = true
- _component = _proto._component
+ _component = getProto._component
None
}
// Maps proto ports to module clone's ports
private[chisel3] lazy val ioMap: Map[Data, Data] = {
val name2Port = getPorts.elements
- _proto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap
+ getProto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap
}
// This module doesn't actually exist in the FIRRTL so no initialization to do
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = ()
// Name of this instance's module is the same as the proto's name
- override def desiredName: String = _proto.name
+ override def desiredName: String = getProto.name
private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = {
val record = _portsRecord
@@ -235,7 +255,7 @@ package internal {
case bad => throwException(s"Internal Error! Cloned-module Record $record has unexpected ref $bad")
}
// Set both the record and the module to have the same instance name
- record.setRef(ModuleCloneIO(_proto, instName), force=true) // force because we did .forceName first
+ record.setRef(ModuleCloneIO(getProto, instName), force=true) // force because we did .forceName first
this.setRef(Ref(instName))
}
}
@@ -249,8 +269,8 @@ package internal {
* @note In addition, the instance name of an InstanceClone is going to be the SAME as the proto, but this is not true
* for ModuleClone.
*/
- private[chisel3] final class InstanceClone[T <: BaseModule] (val _proto: T, val instName: () => String) extends PseudoModule with IsClone[T] {
- override def toString = s"InstanceClone(${_proto})"
+ private[chisel3] final class InstanceClone[T <: BaseModule] (val getProto: T, val instName: () => String) extends PseudoModule with IsClone[T] {
+ override def toString = s"InstanceClone(${getProto})"
// No addition components are generated
private[chisel3] def generateComponent(): Option[Component] = None
// Necessary for toTarget to work
@@ -260,7 +280,7 @@ package internal {
// Instance name is the same as proto's instance name
override def instanceName = instName()
// Module name is the same as proto's module name
- override def desiredName: String = _proto.name
+ override def desiredName: String = getProto.name
}
/** Represents a Definition root module, when accessing something from a definition
@@ -271,20 +291,21 @@ package internal {
* target whose root is the Definition. This DefinitionClone is used to represent the root parent of the
* InstanceClone (which represents the returned module).
*/
- private[chisel3] class DefinitionClone[T <: BaseModule] (val _proto: T) extends PseudoModule with IsClone[T] {
- override def toString = s"DefinitionClone(${_proto})"
+ private[chisel3] class DefinitionClone[T <: BaseModule] (val getProto: T) extends PseudoModule with IsClone[T] {
+ override def toString = s"DefinitionClone(${getProto})"
// No addition components are generated
private[chisel3] def generateComponent(): Option[Component] = None
// Necessary for toTarget to work
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = ()
// Module name is the same as proto's module name
- override def desiredName: String = _proto.name
+ override def desiredName: String = getProto.name
}
/** @note If we are cloning a non-module, we need another object which has the proper _parent set!
*/
- private[chisel3] final class InstantiableClone[T <: IsInstantiable] (val _proto: T) extends IsClone[T] {
- private[chisel3] var _parent: Option[BaseModule] = internal.Builder.currentModule
+ trait InstantiableClone[T <: IsInstantiable] extends IsClone[T] {
+ private[chisel3] def _innerContext: experimental.hierarchy.Hierarchy[_]
+ private[chisel3] def getInnerContext: Option[BaseModule] = _innerContext.getInnerDataContext
}
/** Record type returned by CloneModuleAsRecord
@@ -328,13 +349,13 @@ package internal {
package experimental {
- import chisel3.experimental.hierarchy.IsInstantiable
+ import chisel3.experimental.hierarchy.{IsInstantiable, Proto}
object BaseModule {
implicit class BaseModuleExtensions[T <: BaseModule](b: T) {
import chisel3.experimental.hierarchy.{Instance, Definition}
- def toInstance: Instance[T] = new Instance(Left(b))
- def toDefinition: Definition[T] = new Definition(Left(b))
+ def toInstance: Instance[T] = new Instance(Proto(b))
+ def toDefinition: Definition[T] = new Definition(Proto(b))
}
}
/** Abstract base class for Modules, an instantiable organizational unit for RTL.
@@ -346,13 +367,19 @@ package experimental {
//
// Builder Internals - this tracks which Module RTL construction belongs to.
//
- if (!Builder.readyForModuleConstr) {
- throwException("Error: attempted to instantiate a Module without wrapping it in Module().")
+ this match {
+ case _: PseudoModule =>
+ case other =>
+ if (!Builder.readyForModuleConstr) {
+ throwException("Error: attempted to instantiate a Module without wrapping it in Module().")
+ }
}
- readyForModuleConstr = false
+ if (Builder.hasDynamicContext) {
+ readyForModuleConstr = false
- Builder.currentModule = Some(this)
- Builder.whenStack = Nil
+ Builder.currentModule = Some(this)
+ Builder.whenStack = Nil
+ }
//
// Module Construction Internals
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
index 0cc3d131..2ac61807 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
@@ -18,13 +18,9 @@ import firrtl.annotations.{IsModule, ModuleTarget}
*
* These definitions are then used to create multiple [[Instance]]s.
*
- * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object
+ * @param underlying The internal representation of the definition, which may be either be directly the object, or a clone of an object
*/
-case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends IsLookupable {
- private[chisel3] def proto: A = cloned match {
- case Left(value: A) => value
- case Right(i: IsClone[A]) => i._proto
- }
+final case class Definition[+A] private[chisel3] (private[chisel3] underlying: Underlying[A]) extends IsLookupable with SealedHierarchy[A] {
/** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
* Instead, mark the field you are accessing with [[@public]]
*
@@ -43,20 +39,20 @@ case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, I
lookup.definitionLookup(that, this)
}
- /** Updated by calls to [[apply]], to avoid recloning returned Data's */
- private [chisel3] val cache = HashMap[Data, Data]()
-
-
/** @return the context of any Data's return from inside the instance */
private[chisel3] def getInnerDataContext: Option[BaseModule] = proto match {
case value: BaseModule =>
- val newChild = Module.do_apply(new internal.BaseModule.DefinitionClone(value))(chisel3.internal.sourceinfo.UnlocatableSourceInfo, chisel3.ExplicitCompileOptions.Strict)
+ val newChild = Module.do_pseudo_apply(new internal.BaseModule.DefinitionClone(value))(chisel3.internal.sourceinfo.UnlocatableSourceInfo, chisel3.ExplicitCompileOptions.Strict)
newChild._circuit = value._circuit.orElse(Some(value))
newChild._parent = None
Some(newChild)
case value: IsInstantiable => None
}
+ override def toDefinition: Definition[A] = this
+ override def toInstance: Instance[A] = new Instance(underlying)
+
+
}
/** Factory methods for constructing [[Definition]]s */
@@ -95,6 +91,7 @@ object Definition extends SourceInfoDoc {
Builder.annotations ++= ir.annotations
module._circuit = Builder.currentModule
dynamicContext.globalNamespace.copyTo(Builder.globalNamespace)
- new Definition(Left(module))
+ new Definition(Proto(module))
}
+
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala
new file mode 100644
index 00000000..503e437b
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental.hierarchy
+
+import chisel3._
+import scala.collection.mutable.{HashMap, HashSet}
+import scala.reflect.runtime.universe.TypeTag
+import chisel3.internal.BaseModule.IsClone
+import chisel3.experimental.BaseModule
+import _root_.firrtl.annotations.IsModule
+import scala.annotation.implicitNotFound
+
+/** Super-trait for Instance and Definition
+ *
+ * Enables writing functions which are Instance/Definition agnostic
+ */
+sealed trait Hierarchy[+A] {
+ private[chisel3] def underlying: Underlying[A]
+ private[chisel3] def proto: A = underlying match {
+ case Proto(value: A) => value
+ case Clone(i: IsClone[A]) => i.getProto
+ }
+
+ /** Updated by calls to [[_lookup]], to avoid recloning returned Data's */
+ private[chisel3] val cache = HashMap[Data, Data]()
+ private[chisel3] def getInnerDataContext: Option[BaseModule]
+
+ /** Determine whether underlying proto is of type provided.
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class.
+ * @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure.
+ * @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type
+ *
+ * E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String]
+ * @return Whether underlying proto is of provided type (with caveats outlined above)
+ */
+ def isA[B : TypeTag]: Boolean = {
+ val tptag = implicitly[TypeTag[B]]
+ val name = tptag.tpe.toString
+ inBaseClasses(name)
+ }
+
+
+ // This code handles a special-case where, within an mdoc context, the type returned from
+ // scala reflection (typetag) looks different than when returned from java reflection.
+ // This function detects this case and reshapes the string to match.
+ private def modifyReplString(clz: String): String = {
+ if(clz != null) {
+ clz.split('.').toList match {
+ case "repl" :: "MdocSession" :: app :: rest => s"$app.this." + rest.mkString(".")
+ case other => clz
+ }
+ } else clz
+ }
+ private lazy val superClasses = calculateSuperClasses(proto.getClass())
+ private def calculateSuperClasses(clz: Class[_]): Set[String] = {
+ if(clz != null) {
+ Set(modifyReplString(clz.getCanonicalName())) ++
+ clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++
+ calculateSuperClasses(clz.getSuperclass())
+ } else {
+ Set.empty[String]
+ }
+ }
+ private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz)
+
+
+ /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
+ * Instead, mark the field you are accessing with [[@public]]
+ *
+ * Given a selector function (that) which selects a member from the original, return the
+ * corresponding member from the hierarchy.
+ *
+ * Our @instantiable and @public macros generate the calls to this apply method
+ *
+ * By calling this function, we summon the proper Lookupable typeclass from our implicit scope.
+ *
+ * @param that a user-specified lookup function
+ * @param lookup typeclass which contains the correct lookup function, based on the types of A and B
+ * @param macroGenerated a value created in the macro, to make it harder for users to use this API
+ */
+ def _lookup[B, C](that: A => B)(implicit lookup: Lookupable[B], macroGenerated: chisel3.internal.MacroGenerated): lookup.C
+
+ /** @return Return the underlying Definition[A] of this Hierarchy[A] */
+ def toDefinition: Definition[A]
+
+ /** @return Convert this Hierarchy[A] as a top-level Instance[A] */
+ def toInstance: Instance[A]
+}
+
+// Used to effectively seal Hierarchy, without requiring Definition and Instance to be in this file.
+private[chisel3] trait SealedHierarchy[+A] extends Hierarchy[A]
+
+object Hierarchy {
+ implicit class HierarchyBaseModuleExtensions[T <: BaseModule](i: Hierarchy[T]) {
+ /** Returns the toTarget of this hierarchy
+ * @return target of this hierarchy
+ */
+ def toTarget: IsModule = i match {
+ case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toTarget
+ case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toTarget
+ }
+
+ /** Returns the toAbsoluteTarget of this hierarchy
+ * @return absoluteTarget of this Hierarchy
+ */
+ def toAbsoluteTarget: IsModule = i match {
+ case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toAbsoluteTarget
+ case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toAbsoluteTarget
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
index 9b17bfce..97b62c23 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
@@ -14,38 +14,29 @@ import firrtl.annotations.IsModule
* Represents a unique instance of type [[A]] which are marked as @instantiable
* Can be created using Instance.apply method.
*
- * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object
+ * @param underlying The internal representation of the instance, which may be either be directly the object, or a clone of an object
*/
-case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) {
-
- /** Returns the original object which is instantiated here.
- * If this is an instance of a clone, return that clone's original proto
- *
- * @return the original object which was instantiated
- */
- private[chisel3] def proto: A = cloned match {
- case Left(value: A) => value
- case Right(i: IsClone[A]) => i._proto
+final case class Instance[+A] private [chisel3] (private[chisel3] underlying: Underlying[A]) extends SealedHierarchy[A] {
+ underlying match {
+ case Proto(p: IsClone[_]) => chisel3.internal.throwException("Cannot have a Proto with a clone!")
+ case other => //Ok
}
/** @return the context of any Data's return from inside the instance */
- private[chisel3] def getInnerDataContext: Option[BaseModule] = cloned match {
- case Left(value: BaseModule) => Some(value)
- case Left(value: IsInstantiable) => None
- case Right(i: BaseModule) => Some(i)
- case Right(i: InstantiableClone[_]) => i._parent
+ private[chisel3] def getInnerDataContext: Option[BaseModule] = underlying match {
+ case Proto(value: BaseModule) => Some(value)
+ case Proto(value: IsInstantiable) => None
+ case Clone(i: BaseModule) => Some(i)
+ case Clone(i: InstantiableClone[_]) => i.getInnerContext
}
/** @return the context this instance. Note that for non-module clones, getInnerDataContext will be the same as getClonedParent */
- private[chisel3] def getClonedParent: Option[BaseModule] = cloned match {
- case Left(value: BaseModule) => value._parent
- case Right(i: BaseModule) => i._parent
- case Right(i: InstantiableClone[_]) => i._parent
+ private[chisel3] def getClonedParent: Option[BaseModule] = underlying match {
+ case Proto(value: BaseModule) => value._parent
+ case Clone(i: BaseModule) => i._parent
+ case Clone(i: InstantiableClone[_]) => i.getInnerContext
}
- /** Updated by calls to [[apply]], to avoid recloning returned Data's */
- private [chisel3] val cache = HashMap[Data, Data]()
-
/** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
* Instead, mark the field you are accessing with [[@public]]
*
@@ -65,7 +56,8 @@ case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, Is
}
/** Returns the definition of this Instance */
- def toDefinition: Definition[A] = new Definition(Left(proto))
+ override def toDefinition: Definition[A] = new Definition(Proto(proto))
+ override def toInstance: Instance[A] = this
}
@@ -75,17 +67,17 @@ object Instance extends SourceInfoDoc {
/** If this is an instance of a Module, returns the toTarget of this instance
* @return target of this instance
*/
- def toTarget: IsModule = i.cloned match {
- case Left(x: BaseModule) => x.getTarget
- case Right(x: IsClone[_] with BaseModule) => x.getTarget
+ def toTarget: IsModule = i.underlying match {
+ case Proto(x: BaseModule) => x.getTarget
+ case Clone(x: IsClone[_] with BaseModule) => x.getTarget
}
/** If this is an instance of a Module, returns the toAbsoluteTarget of this instance
* @return absoluteTarget of this instance
*/
- def toAbsoluteTarget: IsModule = i.cloned match {
- case Left(x) => x.toAbsoluteTarget
- case Right(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget
+ def toAbsoluteTarget: IsModule = i.underlying match {
+ case Proto(x) => x.toAbsoluteTarget
+ case Clone(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget
}
}
@@ -105,7 +97,7 @@ object Instance extends SourceInfoDoc {
val ports = experimental.CloneModuleAsRecord(definition.proto)
val clone = ports._parent.get.asInstanceOf[ModuleClone[T]]
clone._madeFromDefinition = true
- new Instance(Right(clone))
+ new Instance(Clone(clone))
}
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala
index 26ba0286..4f3c2d42 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala
@@ -12,6 +12,6 @@ trait IsInstantiable
object IsInstantiable {
implicit class IsInstantiableExtensions[T <: IsInstantiable](i: T) {
- def toInstance: Instance[T] = new Instance(Left(i))
+ def toInstance: Instance[T] = new Instance(Proto(i))
}
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala
new file mode 100644
index 00000000..c16cc633
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental.hierarchy
+
+import scala.annotation.implicitNotFound
+
+@implicitNotFound("These functions are only for building hierarchy-compatible Chisel libraries! Users beware!")
+// DO NOT extend unless you know what you are doing!!!!!! Not for the casual user!
+trait InsideHierarchyLibraryExtension
+
+// Collection of public functions to give non-core-Chisel libraries the ability to build integrations with
+// the experimental hierarchy package
+object LibraryHooks {
+
+ /** Builds a new instance given a definition and function to create a new instance-specific Underlying, from the
+ * definition's Underlying
+ * @note Implicitly requires being inside a Hierarchy Library Extension
+ */
+ def buildInstance[A](definition: Definition[A],
+ createUnderlying: Underlying[A] => Underlying[A]
+ )(implicit inside: InsideHierarchyLibraryExtension): Instance[A] = {
+ new Instance(createUnderlying(definition.underlying))
+ }
+
+ /** Builds a new definition given an Underlying implementation
+ * @note Implicitly requires being inside a Hierarchy Library Extension
+ */
+ def buildDefinition[A](underlying: Underlying[A])(implicit inside: InsideHierarchyLibraryExtension): Definition[A] = {
+ new Definition(underlying)
+ }
+}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
index b9617723..ff4d676c 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
@@ -19,7 +19,7 @@ import chisel3.internal.{AggregateViewBinding, Builder, ChildBinding, ViewBindin
*/
@implicitNotFound("@public is only legal within a class marked @instantiable and only on vals of type" +
" Data, BaseModule, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable or Option")
-sealed trait Lookupable[-B] {
+trait Lookupable[-B] {
type C // Return type of the lookup
/** Function called to modify the returned value of type B from A, into C
*
@@ -36,9 +36,11 @@ sealed trait Lookupable[-B] {
* @return
*/
def definitionLookup[A](that: A => B, definition: Definition[A]): C
+ protected def getProto[A](h: Hierarchy[A]): A = h.proto
+ protected def getUnderlying[A](h: Hierarchy[A]): Underlying[A] = h.underlying
}
-private[chisel3] object Lookupable {
+object Lookupable {
/** Clones a data and sets its internal references to its parent module to be in a new context.
*
@@ -52,10 +54,10 @@ private[chisel3] object Lookupable {
data._parent match {
case None => data
case Some(parent) =>
- val newParent = cloneModuleToContext(Left(parent), context)
+ val newParent = cloneModuleToContext(Proto(parent), context)
newParent match {
- case Left(p) if p == parent => data
- case Right(m: BaseModule) =>
+ case Proto(p) if p == parent => data
+ case Clone(m: BaseModule) =>
val newChild = data.cloneTypeFull
newChild.setRef(data.getRef, true)
newChild.bind(internal.CrossModuleBinding)
@@ -145,7 +147,7 @@ private[chisel3] object Lookupable {
val result = data.cloneTypeFull
- // We have to lookup the target(s) of the view since they may need to be cloned into the current context
+ // We have to lookup the target(s) of the view since they may need to be underlying into the current context
val newBinding = data.topBinding match {
case ViewBinding(target) => ViewBinding(lookupData(reify(target)))
case avb @ AggregateViewBinding(map, targetOpt) => data match {
@@ -199,51 +201,51 @@ private[chisel3] object Lookupable {
* This function effectively recurses up the parents of module to find whether:
* (1) A parent is already in the context; then we do nothing and return module
* (2) A parent is in a different clone of the context; then we clone all the parents up
- * to that parent and set their parents to be in this cloned context
+ * to that parent and set their parents to be in this underlying context
* (3) A parent has no root; in that case, we do nothing and return the module.
*
- * @param module original or clone to be cloned into a new context
+ * @param module original or clone to be underlying into a new context
* @param context new context
* @return original or clone in the new context
*/
- private[chisel3] def cloneModuleToContext[T <: BaseModule](module: Either[T, IsClone[T]], context: BaseModule)
- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Either[T, IsClone[T]] = {
+ private[chisel3] def cloneModuleToContext[T <: BaseModule](module: Underlying[T], context: BaseModule)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Underlying[T] = {
// Recursive call
- def rec[A <: BaseModule](m: A): Either[A, IsClone[A]] = {
- def clone(x: A, p: Option[BaseModule], name: () => String): Either[A, IsClone[A]] = {
- val newChild = Module.do_apply(new internal.BaseModule.InstanceClone(x, name))
+ def rec[A <: BaseModule](m: A): Underlying[A] = {
+ def clone(x: A, p: Option[BaseModule], name: () => String): Underlying[A] = {
+ val newChild = Module.do_pseudo_apply(new internal.BaseModule.InstanceClone(x, name))
newChild._parent = p
- Right(newChild)
+ Clone(newChild)
}
(m, context) match {
- case (c, ctx) if ctx == c => Left(c)
- case (c, ctx: IsClone[_]) if ctx.isACloneOf(c) => Right(ctx.asInstanceOf[IsClone[A]])
- case (c, ctx) if c._parent.isEmpty => Left(c)
+ case (c, ctx) if ctx == c => Proto(c)
+ case (c, ctx: IsClone[_]) if ctx.hasSameProto(c) => Clone(ctx.asInstanceOf[IsClone[A]])
+ case (c, ctx) if c._parent.isEmpty => Proto(c)
case (_, _) =>
- cloneModuleToContext(Left(m._parent.get), context) match {
- case Left(p) => Left(m)
- case Right(p: BaseModule) =>
+ cloneModuleToContext(Proto(m._parent.get), context) match {
+ case Proto(p) => Proto(m)
+ case Clone(p: BaseModule) =>
clone(m, Some(p), () => m.instanceName)
}
}
}
module match {
- case Left(m) => rec(m)
- case Right(m: ModuleClone[_]) =>
+ case Proto(m) => rec(m)
+ case Clone(m: ModuleClone[_]) =>
rec(m) match {
- case Left(mx) => Right(mx)
- case Right(i: InstanceClone[_]) =>
- val newChild = Module.do_apply(new InstanceClone(m._proto, () => m.instanceName))
+ case Proto(mx) => Clone(mx)
+ case Clone(i: InstanceClone[_]) =>
+ val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName))
newChild._parent = i._parent
- Right(newChild)
+ Clone(newChild)
}
- case Right(m: InstanceClone[_]) =>
+ case Clone(m: InstanceClone[_]) =>
rec(m) match {
- case Left(mx) => Right(mx)
- case Right(i: InstanceClone[_]) =>
- val newChild = Module.do_apply(new InstanceClone(m._proto, () => m.instanceName))
+ case Proto(mx) => Clone(mx)
+ case Clone(i: InstanceClone[_]) =>
+ val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName))
newChild._parent = i._parent
- Right(newChild)
+ Clone(newChild)
}
}
}
@@ -259,14 +261,14 @@ private[chisel3] object Lookupable {
type C = Instance[B]
def definitionLookup[A](that: A => Instance[B], definition: Definition[A]): C = {
val ret = that(definition.proto)
- new Instance(cloneModuleToContext(ret.cloned, definition.getInnerDataContext.get))
+ new Instance(cloneModuleToContext(ret.underlying, definition.getInnerDataContext.get))
}
def instanceLookup[A](that: A => Instance[B], instance: Instance[A]): C = {
val ret = that(instance.proto)
- instance.cloned match {
+ instance.underlying match {
// If instance is just a normal module, no changing of context is necessary
- case Left(_) => new Instance(ret.cloned)
- case Right(_) => new Instance(cloneModuleToContext(ret.cloned, instance.getInnerDataContext.get))
+ case Proto(_) => new Instance(ret.underlying)
+ case Clone(_) => new Instance(cloneModuleToContext(ret.underlying, instance.getInnerDataContext.get))
}
}
}
@@ -275,14 +277,14 @@ private[chisel3] object Lookupable {
type C = Instance[B]
def definitionLookup[A](that: A => B, definition: Definition[A]): C = {
val ret = that(definition.proto)
- new Instance(cloneModuleToContext(Left(ret), definition.getInnerDataContext.get))
+ new Instance(cloneModuleToContext(Proto(ret), definition.getInnerDataContext.get))
}
def instanceLookup[A](that: A => B, instance: Instance[A]): C = {
val ret = that(instance.proto)
- instance.cloned match {
+ instance.underlying match {
// If instance is just a normal module, no changing of context is necessary
- case Left(_) => new Instance(Left(ret))
- case Right(_) => new Instance(cloneModuleToContext(Left(ret), instance.getInnerDataContext.get))
+ case Proto(_) => new Instance(Proto(ret))
+ case Clone(_) => new Instance(cloneModuleToContext(Proto(ret), instance.getInnerDataContext.get))
}
}
}
@@ -299,9 +301,9 @@ private[chisel3] object Lookupable {
}
def instanceLookup[A](that: A => B, instance: Instance[A]): C = {
val ret = that(instance.proto)
- val ioMap: Option[Map[Data, Data]] = instance.cloned match {
- case Right(x: ModuleClone[_]) => Some(x.ioMap)
- case Left(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap)
+ val ioMap: Option[Map[Data, Data]] = instance.underlying match {
+ case Clone(x: ModuleClone[_]) => Some(x.ioMap)
+ case Proto(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap)
case _ => None
}
if (isView(ret)) {
@@ -342,15 +344,19 @@ private[chisel3] object Lookupable {
type C = Instance[B]
def definitionLookup[A](that: A => B, definition: Definition[A]): C = {
val ret = that(definition.proto)
- val cloned = new InstantiableClone(ret)
- cloned._parent = definition.getInnerDataContext
- new Instance(Right(cloned))
+ val underlying = new InstantiableClone[B] {
+ val getProto = ret
+ lazy val _innerContext = definition
+ }
+ new Instance(Clone(underlying))
}
def instanceLookup[A](that: A => B, instance: Instance[A]): C = {
val ret = that(instance.proto)
- val cloned = new InstantiableClone(ret)
- cloned._parent = instance.getInnerDataContext
- new Instance(Right(cloned))
+ val underlying = new InstantiableClone[B] {
+ val getProto = ret
+ lazy val _innerContext = instance
+ }
+ new Instance(Clone(underlying))
}
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala
new file mode 100644
index 00000000..864cc8af
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental.hierarchy
+
+import chisel3.internal.BaseModule.IsClone
+
+/** Represents the underlying implementation of a Definition or Instance */
+sealed trait Underlying[+T]
+
+/** A clone of a real implementation */
+final case class Clone[+T](isClone: IsClone[T]) extends Underlying[T]
+
+/** An actual implementation */
+final case class Proto[+T](proto: T) extends Underlying[T]
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index 57e7578a..55f89ae7 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -6,7 +6,7 @@ import scala.util.DynamicVariable
import scala.collection.mutable.ArrayBuffer
import chisel3._
import chisel3.experimental._
-import chisel3.experimental.hierarchy.Instance
+import chisel3.experimental.hierarchy.{Instance, Clone}
import chisel3.internal.firrtl._
import chisel3.internal.naming._
import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
@@ -561,6 +561,8 @@ private[chisel3] object Builder extends LazyLogging {
// A bare api call is, e.g. calling Wire() from the scala console).
)
}
+ def hasDynamicContext: Boolean = dynamicContextVar.value.isDefined
+
def readyForModuleConstr: Boolean = dynamicContext.readyForModuleConstr
def readyForModuleConstr_=(target: Boolean): Unit = {
dynamicContext.readyForModuleConstr = target
@@ -670,8 +672,8 @@ private[chisel3] object Builder extends LazyLogging {
* (Note: Map is Iterable[Tuple2[_,_]] and thus excluded)
*/
def nameRecursively(prefix: String, nameMe: Any, namer: (HasId, String) => Unit): Unit = nameMe match {
- case (id: Instance[_]) => id.cloned match {
- case Right(m: internal.BaseModule.ModuleClone[_]) => namer(m.getPorts, prefix)
+ case (id: Instance[_]) => id.underlying match {
+ case Clone(m: internal.BaseModule.ModuleClone[_]) => namer(m.getPorts, prefix)
case _ =>
}
case (id: HasId) => namer(id, prefix)