Skip to content

Commit

Permalink
Support separately elaborating definition and instance in ChiselStage…
Browse files Browse the repository at this point in the history
… (backport #2512) (#2520)

* Support separately elaborating definition and instance in ChiselStage (#2512)

(cherry picked from commit a0aa4d1)

# Conflicts:
#	core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
#	core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
#	core/src/main/scala/chisel3/internal/Builder.scala

* fixing imports (#2522)

Co-authored-by: Deborah Soung <debs@sifive.com>
  • Loading branch information
mergify[bot] and debs-sifive authored May 12, 2022
1 parent d5a964f commit 1ee9adb
Show file tree
Hide file tree
Showing 4 changed files with 408 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import chisel3.internal.sourceinfo.{DefinitionTransform, DefinitionWrapTransform
import chisel3.experimental.BaseModule
import chisel3.internal.BaseModule.IsClone
import firrtl.annotations.{IsModule, ModuleTarget}
import firrtl.annotations.{IsModule, ModuleTarget, NoTargetAnnotation}

/** User-facing Definition type.
* Represents a definition of an object of type [[A]] which are marked as @instantiable
Expand Down Expand Up @@ -112,3 +113,9 @@ object Definition extends SourceInfoDoc {
}

}

/** Stores a [[Definition]] that is imported so that its Instances can be
* compiled separately.
*/
case class ImportDefinitionAnnotation[T <: BaseModule with IsInstantiable](definition: Definition[T])
extends NoTargetAnnotation
29 changes: 27 additions & 2 deletions core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

package chisel3.experimental.hierarchy

import scala.collection.mutable.{ArrayBuffer, HashMap}
import scala.language.experimental.macros
import chisel3._
import chisel3.internal.BaseModule.{InstantiableClone, IsClone, ModuleClone}
import chisel3.internal.Builder
import chisel3.internal.sourceinfo.{InstanceTransform, SourceInfo}
import chisel3.experimental.BaseModule
import chisel3.experimental.{BaseModule, ExtModule}
import chisel3.internal.firrtl.{Component, DefBlackBox, DefModule, Port}
import firrtl.annotations.IsModule

/** User-facing Instance type.
Expand Down Expand Up @@ -107,9 +108,33 @@ object Instance extends SourceInfoDoc {
implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions
): Instance[T] = {
// Check to see if the module is already defined internally or externally
val existingMod = Builder.components.map {
case c: DefModule if c.id == definition.proto => Some(c)
case c: DefBlackBox if c.name == definition.proto.name => Some(c)
case _ => None
}.flatten

if (existingMod.isEmpty) {
// Add a Definition that will get emitted as an ExtModule so that FIRRTL
// does not complain about a missing element
class EmptyExtModule extends ExtModule {
override def desiredName: String = definition.proto.name
override def generateComponent(): Option[Component] = {
require(!_closed, s"Can't generate $desiredName module more than once")
_closed = true
val firrtlPorts = definition.proto.getModulePorts.map { port => Port(port, port.specifiedDirection) }
val component = DefBlackBox(this, definition.proto.name, firrtlPorts, SpecifiedDirection.Unspecified, params)
Some(component)
}
}
Definition(new EmptyExtModule() {})
}

val ports = experimental.CloneModuleAsRecord(definition.proto)
val clone = ports._parent.get.asInstanceOf[ModuleClone[T]]
clone._madeFromDefinition = true

new Instance(Clone(clone))
}

Expand Down
19 changes: 18 additions & 1 deletion core/src/main/scala/chisel3/internal/Builder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import scala.util.DynamicVariable
import scala.collection.mutable.ArrayBuffer
import chisel3._
import chisel3.experimental._
import chisel3.experimental.hierarchy.{Clone, Instance}
import chisel3.experimental.hierarchy.{Clone, ImportDefinitionAnnotation, Instance}
import chisel3.internal.firrtl._
import chisel3.internal.naming._
import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
Expand Down Expand Up @@ -364,7 +364,24 @@ private[chisel3] class ChiselContext() {
}

private[chisel3] class DynamicContext(val annotationSeq: AnnotationSeq, val throwOnFirstError: Boolean) {
val importDefinitionAnnos = annotationSeq.collect { case a: ImportDefinitionAnnotation[_] => a }

// Ensure there are no repeated names for imported Definitions
val importDefinitionNames = importDefinitionAnnos.map { a => a.definition.proto.name }
if (importDefinitionNames.distinct.length < importDefinitionNames.length) {
val duplicates = importDefinitionNames.diff(importDefinitionNames.distinct).mkString(", ")
throwException(s"Expected distinct imported Definition names but found duplicates for: $duplicates")
}

val globalNamespace = Namespace.empty

// Ensure imported Definitions emit as ExtModules with the correct name so
// that instantiations will also use the correct name and prevent any name
// conflicts with Modules/Definitions in this elaboration
importDefinitionNames.foreach { importDefName =>
globalNamespace.name(importDefName)
}

val components = ArrayBuffer[Component]()
val annotations = ArrayBuffer[ChiselAnnotation]()
var currentModule: Option[BaseModule] = None
Expand Down
Loading

0 comments on commit 1ee9adb

Please sign in to comment.