summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/Module.scala
diff options
context:
space:
mode:
authorJack Koenig2020-03-22 18:13:58 -0700
committerJack Koenig2020-03-25 19:17:15 -0700
commitfbf5e6f1a0e8bf535d465b748ad554575fe62156 (patch)
tree578858ab6d219ca6daf44cf87b73f75054989097 /chiselFrontend/src/main/scala/chisel3/Module.scala
parentb2e004fb615a3c931d910a338b9faa99c1c975d7 (diff)
Rename subprojects to more canonical names
* Rename coreMacros to macros * Rename chiselFrontend to core Also make each subproject publish with "chisel3-" as a prefix
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/Module.scala')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/Module.scala405
1 files changed, 0 insertions, 405 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/Module.scala b/chiselFrontend/src/main/scala/chisel3/Module.scala
deleted file mode 100644
index f1c4e30a..00000000
--- a/chiselFrontend/src/main/scala/chisel3/Module.scala
+++ /dev/null
@@ -1,405 +0,0 @@
-// See LICENSE for license details.
-
-package chisel3
-
-import scala.collection.immutable.ListMap
-import scala.collection.mutable.{ArrayBuffer, HashMap}
-import scala.collection.JavaConversions._
-import scala.language.experimental.macros
-
-import java.util.IdentityHashMap
-
-import chisel3.internal._
-import chisel3.internal.Builder._
-import chisel3.internal.firrtl._
-import chisel3.internal.sourceinfo.{InstTransform, SourceInfo}
-import chisel3.experimental.BaseModule
-import _root_.firrtl.annotations.{ModuleName, ModuleTarget, IsModule}
-
-object Module extends SourceInfoDoc {
- /** A wrapper method that all Module instantiations must be wrapped in
- * (necessary to help Chisel track internal state).
- *
- * @param bc the Module being created
- *
- * @return the input module `m` with Chisel metadata properly set
- */
- def apply[T <: BaseModule](bc: => T): T = macro InstTransform.apply[T]
-
- /** @group SourceInfoTransformMacro */
- def do_apply[T <: BaseModule](bc: => T)
- (implicit sourceInfo: SourceInfo,
- compileOptions: CompileOptions): T = {
- if (Builder.readyForModuleConstr) {
- throwException("Error: Called Module() twice without instantiating a Module." +
- sourceInfo.makeMessage(" See " + _))
- }
- Builder.readyForModuleConstr = true
-
- val parent = Builder.currentModule
- val whenDepth: Int = Builder.whenDepth
-
- // Save then clear clock and reset to prevent leaking scope, must be set again in the Module
- val (saveClock, saveReset) = (Builder.currentClock, Builder.currentReset)
- Builder.currentClock = None
- Builder.currentReset = None
-
- // Execute the module, this has the following side effects:
- // - set currentModule
- // - unset readyForModuleConstr
- // - reset whenDepth to 0
- // - set currentClockAndReset
- val module: T = bc // bc is actually evaluated here
-
- if (Builder.whenDepth != 0) {
- throwException("Internal Error! when() scope depth is != 0, this should have been caught!")
- }
- if (Builder.readyForModuleConstr) {
- throwException("Error: attempted to instantiate a Module, but nothing happened. " +
- "This is probably due to rewrapping a Module instance with Module()." +
- sourceInfo.makeMessage(" See " + _))
- }
- Builder.currentModule = parent // Back to parent!
- Builder.whenDepth = whenDepth
- Builder.currentClock = saveClock // Back to clock and reset scope
- Builder.currentReset = saveReset
-
- val component = module.generateComponent()
- Builder.components += component
-
- // Handle connections at enclosing scope
- if(!Builder.currentModule.isEmpty) {
- pushCommand(DefInstance(sourceInfo, module, component.ports))
- module.initializeInParent(compileOptions)
- }
- module
- }
-
- /** Returns the implicit Clock */
- def clock: Clock = Builder.forcedClock
- /** Returns the implicit Reset */
- def reset: Reset = Builder.forcedReset
- /** Returns the current Module */
- def currentModule: Option[BaseModule] = Builder.currentModule
-}
-
-package experimental {
-
- object IO {
- /** Constructs a port for the current Module
- *
- * This must wrap the datatype used to set the io field of any Module.
- * i.e. All concrete modules must have defined io in this form:
- * [lazy] val io[: io type] = IO(...[: io type])
- *
- * Items in [] are optional.
- *
- * The granted iodef must be a chisel type and not be bound to hardware.
- *
- * Also registers a Data as a port, also performing bindings. Cannot be called once ports are
- * requested (so that all calls to ports will return the same information).
- * Internal API.
- */
- def apply[T<:Data](iodef: T): T = {
- val module = Module.currentModule.get // Impossible to fail
- require(!module.isClosed, "Can't add more ports after module close")
- requireIsChiselType(iodef, "io type")
-
- // Clone the IO so we preserve immutability of data types
- val iodefClone = try {
- iodef.cloneTypeFull
- } catch {
- // For now this is going to be just a deprecation so we don't suddenly break everyone's code
- case e: AutoClonetypeException =>
- Builder.deprecated(e.getMessage, Some(s"${iodef.getClass}"))
- iodef
- }
- module.bindIoInPlace(iodefClone)
- iodefClone
- }
- }
-}
-
-package internal {
- import chisel3.experimental.BaseModule
-
- object BaseModule {
- 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]
- }
-
- private[chisel3] def cloneIORecord(proto: BaseModule)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): ClonePorts = {
- require(proto.isClosed, "Can't clone a module before module close")
- val clonePorts = new ClonePorts(proto.getModulePorts: _*)
- clonePorts.bind(WireBinding(Builder.forcedUserModule))
- val cloneInstance = new DefInstance(sourceInfo, proto, proto._component.get.ports) {
- override def name = clonePorts.getRef.name
- }
- pushCommand(cloneInstance)
- if (!compileOptions.explicitInvalidate) {
- pushCommand(DefInvalid(sourceInfo, clonePorts.ref))
- }
- if (proto.isInstanceOf[MultiIOModule]) {
- clonePorts("clock") := Module.clock
- clonePorts("reset") := Module.reset
- }
- clonePorts
- }
- }
-}
-
-package experimental {
-
- /** Abstract base class for Modules, an instantiable organizational unit for RTL.
- */
- // TODO: seal this?
- abstract class BaseModule extends HasId {
- //
- // Builder Internals - this tracks which Module RTL construction belongs to.
- //
- if (!Builder.readyForModuleConstr) {
- throwException("Error: attempted to instantiate a Module without wrapping it in Module().")
- }
- readyForModuleConstr = false
-
- Builder.currentModule = Some(this)
- Builder.whenDepth = 0
-
- //
- // Module Construction Internals
- //
- protected var _closed = false
-
- /** Internal check if a Module is closed */
- private[chisel3] def isClosed = _closed
-
- // Fresh Namespace because in Firrtl, Modules namespaces are disjoint with the global namespace
- 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
- }
- }
-
- protected def getIds = {
- require(_closed, "Can't get ids before module close")
- _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
-
- 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.
- */
- private[chisel3] def generateComponent(): Component
-
- /** Sets up this module in the parent context
- */
- private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit
-
- //
- // Chisel Internals
- //
-
- /** The desired name of this module (which will be used in generated FIRRTL IR or Verilog).
- *
- * The name of a module approximates the behavior of the Java Reflection [[`getSimpleName` method
- * https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getSimpleName--]] with some modifications:
- *
- * - Anonymous modules will get an `"_Anon"` tag
- * - Modules defined in functions will use their class name and not a numeric name
- *
- * @note If you want a custom or parametric name, override this method.
- */
- def desiredName: String = {
- /* The default module name is derived from the Java reflection derived class name. */
- val baseName = this.getClass.getName
-
- /* A sequence of string filters applied to the name */
- val filters: Seq[String => String] = Seq(
- ((a: String) => raw"\$$+anon".r.replaceAllIn(a, "_Anon")) // Merge the "$$anon" name with previous name
- )
-
- filters
- .foldLeft(baseName){ case (str, filter) => filter(str) } // 1. Apply filters to baseName
- .split("\\.|\\$") // 2. Split string at '.' or '$'
- .filterNot(_.forall(_.isDigit)) // 3. Drop purely numeric names
- .last // 4. Use the last name
- }
-
- /** Legalized name of this module. */
- final lazy val name = try {
- 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) // scalastyle:ignore line.size.limit
- case t: Throwable => throw t
- }
-
- /** Returns a FIRRTL ModuleName that references this object
- *
- * @note Should not be called until circuit elaboration is complete
- */
- final def toNamed: ModuleName = toTarget.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)
-
- /** Returns a FIRRTL ModuleTarget that references this object
- *
- * @note Should not be called until circuit elaboration is complete
- */
- final def toAbsoluteTarget: IsModule = {
- _parent match {
- case Some(parent) => parent.toAbsoluteTarget.instOf(this.instanceName, toTarget.module)
- case None => toTarget
- }
- }
-
- /**
- * 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)
- }
- }
-
- /** Called at the Module.apply(...) level after this Module has finished elaborating.
- * Returns a map of nodes -> names, for named nodes.
- *
- * Helper method.
- */
- protected def nameIds(rootClass: Class[_]): HashMap[HasId, String] = {
- val names = new HashMap[HasId, String]()
-
- def name(node: HasId, name: String) {
- // First name takes priority, like suggestName
- // TODO: DRYify with suggestName
- if (!names.contains(node)) {
- names.put(node, name)
- }
- }
-
- /** Scala generates names like chisel3$util$Queue$$ram for private vals
- * This extracts the part after $$ for names like this and leaves names
- * without $$ unchanged
- */
- def cleanName(name: String): String = name.split("""\$\$""").lastOption.getOrElse(name)
-
- for (m <- getPublicFields(rootClass)) {
- Builder.nameRecursively(cleanName(m.getName), m.invoke(this), name)
- }
-
- names
- }
-
- /** Compatibility function. Allows Chisel2 code which had ports without the IO wrapper to
- * compile under Bindings checks. Does nothing in non-compatibility mode.
- *
- * Should NOT be used elsewhere. This API will NOT last.
- *
- * TODO: remove this, perhaps by removing Bindings checks in compatibility mode.
- */
- def _compatAutoWrapPorts() {} // scalastyle:ignore method.name
-
- /** Chisel2 code didn't require the IO(...) wrapper and would assign a Chisel type directly to
- * io, then do operations on it. This binds a Chisel type in-place (mutably) as an IO.
- */
- protected def _bindIoInPlace(iodef: Data): Unit = { // scalastyle:ignore method.name
- // Compatibility code: Chisel2 did not require explicit direction on nodes
- // (unspecified treated as output, and flip on nothing was input).
- // This sets assigns the explicit directions required by newer semantics on
- // Bundles defined in compatibility mode.
- // This recursively walks the tree, and assigns directions if no explicit
- // direction given by upper-levels (override Input / Output) AND element is
- // directly inside a compatibility Bundle determined by compile options.
- def assignCompatDir(data: Data, insideCompat: Boolean): Unit = {
- data match {
- case data: Element if insideCompat => data._assignCompatibilityExplicitDirection
- case data: Element => // Not inside a compatibility Bundle, nothing to be done
- case data: Aggregate => data.specifiedDirection match {
- // Recurse into children to ensure explicit direction set somewhere
- case SpecifiedDirection.Unspecified | SpecifiedDirection.Flip => data match {
- case record: Record =>
- val compatRecord = !record.compileOptions.dontAssumeDirectionality
- record.getElements.foreach(assignCompatDir(_, compatRecord))
- case vec: Vec[_] =>
- vec.getElements.foreach(assignCompatDir(_, insideCompat))
- }
- case SpecifiedDirection.Input | SpecifiedDirection.Output => // forced assign, nothing to do
- }
- }
- }
-
- assignCompatDir(iodef, false)
-
- iodef.bind(PortBinding(this))
- _ports += iodef
- }
-
- /** Private accessor for _bindIoInPlace */
- private[chisel3] def bindIoInPlace(iodef: Data): Unit = _bindIoInPlace(iodef)
-
- /**
- * This must wrap the datatype used to set the io field of any Module.
- * i.e. All concrete modules must have defined io in this form:
- * [lazy] val io[: io type] = IO(...[: io type])
- *
- * Items in [] are optional.
- *
- * The granted iodef must be a chisel type and not be bound to hardware.
- *
- * Also registers a Data as a port, also performing bindings. Cannot be called once ports are
- * requested (so that all calls to ports will return the same information).
- * Internal API.
- *
- * TODO(twigg): Specifically walk the Data definition to call out which nodes
- * are problematic.
- */
- protected def IO[T <: Data](iodef: T): T = chisel3.experimental.IO.apply(iodef) // scalastyle:ignore method.name
-
- //
- // Internal Functions
- //
-
- /** Keep component for signal names */
- private[chisel3] var _component: Option[Component] = None
-
- /** Signal name (for simulation). */
- override def instanceName: String =
- if (_parent == None) name else _component match {
- case None => getRef.name
- case Some(c) => getRef fullName c
- }
-
- }
-}