diff options
Diffstat (limited to 'core/src/main/scala/chisel3/Module.scala')
| -rw-r--r-- | core/src/main/scala/chisel3/Module.scala | 309 |
1 files changed, 8 insertions, 301 deletions
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index a2d5cec6..794d1bf4 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -172,7 +172,7 @@ abstract class Module(implicit moduleCompileOptions: CompileOptions) extends Raw private[chisel3] def mkReset: Reset = { // Top module and compatibility mode use Bool for reset // Note that a Definition elaboration will lack a parent, but still not be a Top module - val inferReset = (_parent.isDefined || Builder.inDefinition) && moduleCompileOptions.inferModuleReset + val inferReset = (_parent.isDefined) && moduleCompileOptions.inferModuleReset if (moduleCompileOptions.migrateInferModuleReset && !moduleCompileOptions.inferModuleReset) { this match { case _: RequireSyncReset => // Good! It's been migrated. @@ -210,215 +210,16 @@ package experimental { package internal { import chisel3.experimental.BaseModule - import chisel3.experimental.hierarchy.{Clone, IsInstantiable, Proto} - 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 - */ - trait IsClone[+T] { - // Underlying object of which this is a clone of - 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 getProto: T) extends PseudoModule with IsClone[T] { - override def toString = s"ModuleClone(${getProto})" - // Do not call default addId function, which may modify a module that is already "closed" - override def addId(d: HasId): Unit = () - 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") - _closed = true - _component = getProto._component - None - } - // Maps proto ports to module clone's ports - private[chisel3] lazy val ioMap: Map[Data, Data] = { - getProto match { - // BlackBox needs special handling for its pseduo-io Bundle - case protoBB: BlackBox => - Map(protoBB._io.get -> getPorts.elements("io")) - case _ => - val name2Port = getPorts.elements - 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 = getProto.name - - private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = { - val record = _portsRecord - // Use .forceName to re-use default name resolving behavior - record.forceName(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 - val ref = ModuleCloneIO(getProto, instName) - record.setRef(ref, force = true) // force because we did .forceName first - getProto match { - // BlackBox needs special handling for its pseduo-io Bundle - case _: BlackBox => - // Override the io Bundle's ref so that it thinks it is the top for purposes of - // generating FIRRTL - record.elements("io").setRef(ref, force = true) - case _ => // Do nothing - } - - this.setRef(Ref(instName)) - } - } - - /** 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 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 - 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 = getProto.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 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 - // Do not call default addId function, which may modify a module that is already "closed" - override def addId(d: HasId): Unit = () - // 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 = getProto.name - } - - /** @note If we are cloning a non-module, we need another object which has the proper _parent set! - */ - 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 - * - * @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: (String, Data)*)(implicit compileOptions: CompileOptions) extends Record { - val elements = ListMap(elts.map { case (name, d) => name -> d.cloneTypeFull }: _*) - def apply(field: String) = elements(field) - override def cloneType = (new ClonePorts(elts: _*)).asInstanceOf[this.type] - } - - 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)) - 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 = proto match { - // BlackBox needs special handling for its pseduo-io Bundle - case b: BlackBox => - new ClonePorts(proto.getChiselPorts :+ ("io" -> b._io.get): _*) - case _ => new ClonePorts(proto.getChiselPorts: _*) - } - // getChiselPorts (nor cloneTypeFull in general) - // does not recursively copy the right specifiedDirection, - // still need to fix it up here. - Module.assignCompatDir(clonePorts) - clonePorts.bind(PortBinding(cloneParent)) - clonePorts.setAllParents(Some(cloneParent)) - cloneParent._portsRecord = clonePorts - // Normally handled during Module construction but ClonePorts really lives in its parent's parent - if (!compileOptions.explicitInvalidate || Builder.currentModule.get.isInstanceOf[ImplicitInvalidate]) { - // FIXME This almost certainly doesn't work since clonePorts is not a real thing... - pushCommand(DefInvalid(sourceInfo, clonePorts.ref)) - } - if (proto.isInstanceOf[Module]) { - clonePorts("clock") := Module.clock - clonePorts("reset") := Module.reset - } - clonePorts - } - } + object BaseModule {} } package experimental { - import chisel3.experimental.hierarchy.{IsInstantiable, Proto} - - object BaseModule { - implicit class BaseModuleExtensions[T <: BaseModule](b: T) { - import chisel3.experimental.hierarchy.{Definition, Instance} - 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. */ // TODO: seal this? - abstract class BaseModule extends HasId with IsInstantiable { + abstract class BaseModule extends HasId { _parent.foreach(_.addId(this)) // @@ -450,12 +251,8 @@ package experimental { private[chisel3] val _namespace = Namespace.empty private val _ids = ArrayBuffer[HasId]() private[chisel3] def addId(d: HasId) { - if (Builder.aspectModule(this).isDefined) { - aspectModule(this).get.addId(d) - } else { - require(!_closed, "Can't write to module after module close") - _ids += d - } + require(!_closed, "Can't write to module after module close") + _ids += d } // Returns the last id contained within a Module @@ -471,25 +268,6 @@ package experimental { _ids.toSeq } - private val _ports = new ArrayBuffer[Data]() - - // getPorts unfortunately already used for tester compatibility - protected[chisel3] def getModulePorts = { - require(_closed, "Can't get ports before module close") - _ports.toSeq - } - - // These methods allow checking some properties of ports before the module is closed, - // mainly for compatibility purposes. - protected def portsContains(elem: Data): Boolean = _ports contains elem - - // This is dangerous because it can be called before the module is closed and thus there could - // be more ports and names have not yet been finalized. - // This should only to be used during the process of closing when it is safe to do so. - private[chisel3] def findPort(name: String): Option[Data] = _ports.find(_.seedOpt.contains(name)) - - protected def portsSize: Int = _ports.size - /** Generates the FIRRTL Component (Module or Blackbox) of this Module. * Also closes the module so no more construction can happen inside. */ @@ -499,27 +277,6 @@ package experimental { */ private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit - private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = { - for (port <- getModulePorts) { - port._computeName(None).orElse(names.get(port)) match { - case Some(name) => - if (_namespace.contains(name)) { - Builder.error( - s"""Unable to name port $port to "$name" in $this,""" + - " name is already taken by another port!" - ) - } - port.setRef(ModuleIO(this, _namespace.name(name))) - case None => - Builder.error( - s"Unable to name port $port in $this, " + - "try making it a public field of the Module" - ) - port.setRef(ModuleIO(this, "<UNNAMED>")) - } - } - } - // // Chisel Internals // @@ -578,35 +335,9 @@ package experimental { * * @note Should not be called until circuit elaboration is complete */ - final def toTarget: ModuleTarget = this match { - case m: internal.BaseModule.InstanceClone[_] => - throwException(s"Internal Error! It's not legal to call .toTarget on an InstanceClone. $m") - case m: internal.BaseModule.DefinitionClone[_] => - throwException(s"Internal Error! It's not legal to call .toTarget on an DefinitionClone. $m") - case _ => ModuleTarget(this.circuitName, this.name) - } + final def toTarget: ModuleTarget = ModuleTarget(this.circuitName, this.name) - /** Returns the real target of a Module which may be an [[InstanceTarget]] - * - * BaseModule.toTarget returns a ModuleTarget because the classic Module(new MyModule) API elaborates - * Modules in a way that there is a 1:1 relationship between instances and elaborated definitions - * - * Instance/Definition introduced special internal modules [[InstanceClone]] and [[ModuleClone]] that - * do not have this 1:1 relationship so need the ability to return [[InstanceTarget]]s. - * Because users can never actually get references to these underlying objects, we can maintain - * BaseModule.toTarget's API returning [[ModuleTarget]] while providing an internal API for getting - * the correct [[InstanceTarget]]s whenever using the Definition/Instance API. - */ - private[chisel3] def getTarget: IsModule = this match { - case m: internal.BaseModule.InstanceClone[_] if m._parent.nonEmpty => - m._parent.get.getTarget.instOf(instanceName, name) - case m: internal.BaseModule.ModuleClone[_] if m._madeFromDefinition => - m._parent.get.getTarget.instOf(instanceName, 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 _ => this.toTarget - } + private[chisel3] def getTarget: IsModule = this.toTarget /** Returns a FIRRTL ModuleTarget that references this object * @@ -615,30 +346,7 @@ package experimental { final def toAbsoluteTarget: IsModule = { _parent match { 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 - // target disambiguation in FIRRTL's deduplication transform should ensure that .toTarget - // is always unambigous. However, legacy workarounds for Chisel's lack of an instance API - // have lead some to use .toAbsoluteTarget as a workaround. A proper instance API will make - // it possible to deprecate and remove .toAbsoluteTarget - if (this == ViewParent) ViewParent.absoluteTarget else getTarget - } - } - - /** - * Internal API. Returns a list of this module's generated top-level ports as a map of a String - * (FIRRTL name) to the IO object. Only valid after the module is closed. - * - * Note: for BlackBoxes (but not ExtModules), this returns the contents of the top-level io - * object, consistent with what is emitted in FIRRTL. - * - * TODO: Use SeqMap/VectorMap when those data structures become available. - */ - private[chisel3] def getChiselPorts: Seq[(String, Data)] = { - require(_closed, "Can't get ports before module close") - _component.get.ports.map { port => - (port.id.getRef.asInstanceOf[ModuleIO].name, port.id) + case None => getTarget } } @@ -699,7 +407,6 @@ package experimental { Module.assignCompatDir(iodef) iodef.bind(PortBinding(this)) - _ports += iodef } /** Private accessor for _bindIoInPlace */ |
