diff options
| author | Jack Koenig | 2021-08-12 17:04:11 -0700 |
|---|---|---|
| committer | GitHub | 2021-08-12 17:04:11 -0700 |
| commit | 1ceb974c55c6785c21ab3934fa750ade0702e276 (patch) | |
| tree | bc8559e8ef558e3216ecc5612593f5904f9a6b60 /core/src/main/scala/chisel3/Module.scala | |
| parent | 713de6b823d8707246935b9e31ed2fbafeaeca32 (diff) | |
Add DataView (#1955)
DataView is a mechanism for "viewing" Scala objects as a subtype of
`Data`. Often, this is useful for viewing one subtype of `Data`, as
another. One can think about a DataView as a cross between a
customizable cast and an untagged union.
A DataView has a Target type `T`, and a View type `V`. DataView requires
that an implementation of `DataProduct` is available for Target types.
DataProduct is a type class that provides a way to iterate on `Data`
children of objects of implementing types.
If a DataView is provided for a type T to a type V, then the function
.viewAs[V] (of type T => V) is available. The object (of type T) returned
by .viewAs is called a "View" and can be used as both an rvalue and an
lvalue. Unlike when using an .asTypeOf cast, connecting to a "View" will
connect to the associated field or fields of the underlying Target.
DataView also enables .viewAsSupertype which is available for viewing
Bundles as a parent Bundle type. It is similar to .viewAs but requires
a prototype object of the Target type which will be cloned in order to
create the returned View. .viewAsSupertype maps between the
corresponding fields of the parent and child Bundle types.
Diffstat (limited to 'core/src/main/scala/chisel3/Module.scala')
| -rw-r--r-- | core/src/main/scala/chisel3/Module.scala | 42 |
1 files changed, 22 insertions, 20 deletions
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index 41fe4554..64065ec9 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -184,7 +184,7 @@ package internal { object BaseModule { // Private internal class to serve as a _parent for Data in cloned ports - private[chisel3] class ModuleClone(_proto: BaseModule) extends BaseModule { + private[chisel3] class ModuleClone(_proto: BaseModule) extends PseudoModule { // 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 = _ @@ -195,7 +195,7 @@ package internal { _component = _proto._component None } - // This module doesn't acutally exist in the FIRRTL so no initialization to do + // This module doesn't actually exist in the FIRRTL so no initialization to do private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = () override def desiredName: String = _proto.name @@ -226,19 +226,6 @@ package internal { 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 @@ -249,7 +236,7 @@ package internal { // currentModule (and not clonePorts) val clonePorts = new ClonePorts(proto.getModulePorts: _*) clonePorts.bind(PortBinding(cloneParent)) - setAllParents(clonePorts, Some(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) { @@ -303,7 +290,15 @@ package experimental { } } - protected def getIds = { + // Returns the last id contained within a Module + private[chisel3] def _lastId: Long = _ids.last match { + case mod: BaseModule => mod._lastId + case _ => + // Ideally we could just take last._id, but Records store and thus bind their Data in reverse order + _ids.maxBy(_._id)._id + } + + private[chisel3] def getIds = { require(_closed, "Can't get ids before module close") _ids.toSeq } @@ -368,10 +363,10 @@ package experimental { /** Legalized name of this module. */ final lazy val name = try { - // ModuleAspects and ModuleClones are not "true modules" and thus should share + // PseudoModules are not "true modules" and thus should share // their original modules names without uniquification this match { - case (_: ModuleAspect | _: internal.BaseModule.ModuleClone) => desiredName + case _: PseudoModule => desiredName case _ => Builder.globalNamespace.name(desiredName) } } catch { @@ -399,7 +394,14 @@ package experimental { final def toAbsoluteTarget: IsModule = { _parent match { case Some(parent) => parent.toAbsoluteTarget.instOf(this.instanceName, toTarget.module) - case None => toTarget + 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 toTarget } } |
