diff options
Diffstat (limited to 'core/src/main/scala/chisel3/Module.scala')
| -rw-r--r-- | core/src/main/scala/chisel3/Module.scala | 107 |
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 |
