summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3/Module.scala
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/scala/chisel3/Module.scala')
-rw-r--r--core/src/main/scala/chisel3/Module.scala107
1 files changed, 101 insertions, 6 deletions
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index 64065ec9..d0171693 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -121,7 +121,8 @@ abstract class Module(implicit moduleCompileOptions: CompileOptions) extends Raw
private[chisel3] def mkReset: Reset = {
// Top module and compatibility mode use Bool for reset
- val inferReset = _parent.isDefined && moduleCompileOptions.inferModuleReset
+ // Note that a Definition elaboration will lack a parent, but still not be a Top module
+ val inferReset = (_parent.isDefined || Builder.inDefinition) && moduleCompileOptions.inferModuleReset
if (inferReset) Reset() else Bool()
}
@@ -181,13 +182,31 @@ package experimental {
package internal {
import chisel3.experimental.BaseModule
+ import chisel3.experimental.hierarchy.IsInstantiable
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] {
+ // 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 internal class to serve as a _parent for Data in cloned ports
- private[chisel3] class ModuleClone(_proto: BaseModule) extends PseudoModule {
+ private[chisel3] class ModuleClone[T <: BaseModule] (val _proto: T) extends PseudoModule with IsClone[T] {
+ override def toString = s"ModuleClone(${_proto})"
+ def getPorts = _portsRecord
// ClonePorts that hold the bound ports for this module
// Used for setting the refs of both this module and the Record
private[BaseModule] var _portsRecord: Record = _
+ // This is necessary for correctly supporting .toTarget on a Module Clone. If it is made from the
+ // Instance/Definition API, it should return an instanceTarget. If made from CMAR, it should return a
+ // ModuleTarget.
+ private[chisel3] var _madeFromDefinition: Boolean = false
// Don't generate a component, but point to the one for the cloned Module
private[chisel3] def generateComponent(): Option[Component] = {
require(!_closed, "Can't generate module more than once")
@@ -195,9 +214,15 @@ package internal {
_component = _proto._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
+ }
// 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
private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = {
@@ -215,6 +240,53 @@ package internal {
}
}
+ /** Represents a module viewed from a different instance context.
+ *
+ * @note Why do we need both ModuleClone and InstanceClone? If we are annotating a reference in a module-clone,
+ * all submodules must be also be 'cloned' so the toTarget can be computed properly. However, we don't need separate
+ * connectable ports for this instance; all that's different from the proto is the parent.
+ *
+ * @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})"
+ // No addition components are generated
+ private[chisel3] def generateComponent(): Option[Component] = None
+ // Necessary for toTarget to work
+ private[chisel3] def setAsInstanceRef(): Unit = { this.setRef(Ref(instName())) }
+ // This module doesn't acutally exist in the FIRRTL so no initialization to do
+ private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = ()
+ // 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
+ }
+
+ /** Represents a Definition root module, when accessing something from a definition
+ *
+ * @note This is necessary to distinguish between the toTarget behavior for a Module returned from a Definition,
+ * versus a normal Module. A normal Module.toTarget will always return a local target. If calling toTarget
+ * on a Module returned from a Definition (and thus wrapped in an Instance), we need to return the non-local
+ * 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})"
+ // 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
+ }
+
+ /** @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
+ }
+
/** Record type returned by CloneModuleAsRecord
*
* @note These are not true Data (the Record doesn't correspond to anything in the emitted
@@ -232,6 +304,9 @@ package internal {
// We make this before clonePorts because we want it to come up first in naming in
// currentModule
val cloneParent = Module(new ModuleClone(proto))
+ require(proto.isClosed, "Can't clone a module before module close")
+ require(cloneParent.getOptionRef.isEmpty, "Can't have ref set already!")
+ // Fake Module to serve as the _parent of the cloned ports
// We don't create this inside the ModuleClone because we need the ref to be set by the
// currentModule (and not clonePorts)
val clonePorts = new ClonePorts(proto.getModulePorts: _*)
@@ -253,10 +328,19 @@ package internal {
package experimental {
+ import chisel3.experimental.hierarchy.IsInstantiable
+
+ 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))
+ }
+ }
/** Abstract base class for Modules, an instantiable organizational unit for RTL.
*/
// TODO: seal this?
- abstract class BaseModule extends HasId {
+ abstract class BaseModule extends HasId with IsInstantiable {
_parent.foreach(_.addId(this))
//
@@ -379,13 +463,24 @@ package experimental {
*
* @note Should not be called until circuit elaboration is complete
*/
- final def toNamed: ModuleName = toTarget.toNamed
+ final def toNamed: ModuleName = ModuleTarget(this.circuitName, this.name).toNamed
/** Returns a FIRRTL ModuleTarget that references this object
*
* @note Should not be called until circuit elaboration is complete
*/
- final def toTarget: ModuleTarget = ModuleTarget(this.circuitName, this.name)
+ final def toTarget: IsModule = {
+ this match {
+ case m: internal.BaseModule.InstanceClone[_] if m._parent.nonEmpty => m._parent.get.toTarget.instOf(instanceName, name)
+ case m: internal.BaseModule.InstanceClone[_] => ModuleTarget(this.circuitName, this.name)
+ case m: internal.BaseModule.ModuleClone[_] if m._madeFromDefinition => m._parent.get.toTarget.instOf(instanceName, name)
+ case m: internal.BaseModule.ModuleClone[_] => ModuleTarget(this.circuitName, this.name)
+ // Without this, we get the wrong CircuitName for the Definition
+ case m: internal.BaseModule.DefinitionClone[_] if m._circuit.nonEmpty => ModuleTarget(this._circuit.get.circuitName, this.name)
+ case m: internal.BaseModule.DefinitionClone[_] => ModuleTarget(this.circuitName, this.name)
+ case m => ModuleTarget(this.circuitName, this.name)
+ }
+ }
/** Returns a FIRRTL ModuleTarget that references this object
*
@@ -393,7 +488,7 @@ package experimental {
*/
final def toAbsoluteTarget: IsModule = {
_parent match {
- case Some(parent) => parent.toAbsoluteTarget.instOf(this.instanceName, toTarget.module)
+ case Some(parent) => parent.toAbsoluteTarget.instOf(this.instanceName, name)
case None =>
// FIXME Special handling for Views - evidence of "weirdness" of .toAbsoluteTarget
// In theory, .toAbsoluteTarget should not be necessary, .toTarget combined with the