diff options
Diffstat (limited to 'core/src/main/scala/chisel3/Module.scala')
| -rw-r--r-- | core/src/main/scala/chisel3/Module.scala | 85 |
1 files changed, 73 insertions, 12 deletions
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index b204be8d..8a914fbc 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -64,13 +64,18 @@ object Module extends SourceInfoDoc { Builder.currentClock = saveClock // Back to clock and reset scope Builder.currentReset = saveReset - val component = module.generateComponent() - Builder.components += component + // Only add the component if the module generates one + val componentOpt = module.generateComponent() + for (component <- componentOpt) { + Builder.components += component + } Builder.setPrefix(savePrefix) // Handle connections at enclosing scope - if(!Builder.currentModule.isEmpty) { + // We use _component because Modules that don't generate them may still have one + if (Builder.currentModule.isDefined && module._component.isDefined) { + val component = module._component.get pushCommand(DefInstance(sourceInfo, module, component.ports)) module.initializeInParent(compileOptions) } @@ -178,20 +183,73 @@ package internal { import chisel3.experimental.BaseModule object BaseModule { + // Private internal class to serve as a _parent for Data in cloned ports + private[chisel3] class ModuleClone(_proto: BaseModule) extends BaseModule { + // 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 = _ + // Don't generate a component, but point to the one for the cloned Module + private[chisel3] def generateComponent(): Option[Component] = { + _component = _proto._component + None + } + // This module doesn't acutally exist in the FIRRTL so no initialization to do + private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = () + + override def desiredName: String = _proto.name + + private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = { + val record = _portsRecord + // Use .forceName to re-use default name resolving behavior + record.forceName(None, default=this.desiredName, namespace) + // Now take the Ref that forceName set and convert it to the correct Arg + val instName = record.getRef match { + case Ref(name) => name + 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 + this.setRef(Ref(instName)) + } + } + + /** Record type returned by CloneModuleAsRecord + * + * @note These are not true Data (the Record doesn't correspond to anything in the emitted + * FIRRTL yet its elements *do*) so have some very specialized behavior. + */ private[chisel3] class ClonePorts (elts: Data*)(implicit compileOptions: CompileOptions) extends Record { val elements = ListMap(elts.map(d => d.instanceName -> d.cloneTypeFull): _*) def apply(field: String) = elements(field) override def cloneType = (new ClonePorts(elts: _*)).asInstanceOf[this.type] } + // Recursively set the parent of the start Data and any children (eg. in an Aggregate) + private def setAllParents(start: Data, parent: Option[BaseModule]): Unit = { + def rec(data: Data): Unit = { + data._parent = parent + data match { + case _: Element => + case agg: Aggregate => + agg.getElements.foreach(rec) + } + } + rec(start) + } + private[chisel3] def cloneIORecord(proto: BaseModule)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): ClonePorts = { require(proto.isClosed, "Can't clone a module before module close") + // Fake Module to serve as the _parent of the cloned ports + // We make this before clonePorts because we want it to come up first in naming in + // currentModule + val cloneParent = Module(new ModuleClone(proto)) + // 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: _*) - clonePorts.bind(WireBinding(Builder.forcedUserModule, Builder.currentWhen())) - val cloneInstance = new DefInstance(sourceInfo, proto, proto._component.get.ports) { - override def name = clonePorts.getRef.name - } - pushCommand(cloneInstance) + clonePorts.bind(PortBinding(cloneParent)) + setAllParents(clonePorts, Some(cloneParent)) + cloneParent._portsRecord = clonePorts + // Normally handled during Module construction but ClonePorts really lives in its parent's parent if (!compileOptions.explicitInvalidate) { pushCommand(DefInvalid(sourceInfo, clonePorts.ref)) } @@ -270,7 +328,7 @@ package experimental { /** Generates the FIRRTL Component (Module or Blackbox) of this Module. * Also closes the module so no more construction can happen inside. */ - private[chisel3] def generateComponent(): Component + private[chisel3] def generateComponent(): Option[Component] /** Sets up this module in the parent context */ @@ -308,9 +366,12 @@ package experimental { /** Legalized name of this module. */ final lazy val name = try { - // If this is a module aspect, it should share the same name as the original module - // Thus, the desired name should be returned without uniquification - if(this.isInstanceOf[ModuleAspect]) desiredName else Builder.globalNamespace.name(desiredName) + // ModuleAspects and ModuleClones are not "true modules" and thus should share + // their original modules names without uniquification + this match { + case (_: ModuleAspect | _: internal.BaseModule.ModuleClone) => desiredName + case _ => Builder.globalNamespace.name(desiredName) + } } catch { case e: NullPointerException => throwException( s"Error: desiredName of ${this.getClass.getName} is null. Did you evaluate 'name' before all values needed by desiredName were available?", e) |
