summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
authorAdam Izraelevitz2020-07-29 20:48:31 -0700
committerGitHub2020-07-29 20:48:31 -0700
commit164490c8fbf132ca65644d05d6ff8d0d7a3beb20 (patch)
tree862750b85dca5b8496c40c24b3a4e5e67c268bd4 /core/src/main
parent8aeb39b9b3755ccd0e3aa600b813ed4220ac72d8 (diff)
Improved Chisel Naming via Compiler Plugins + Prefixing (#1448)
Added prefixing and a compiler plugin to improve naming. Only works for Scala 2.12 and above. Co-authored-by: Jack Koenig <koenig@sifive.com>
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/scala/chisel3/Data.scala20
-rw-r--r--core/src/main/scala/chisel3/Module.scala4
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala23
-rw-r--r--core/src/main/scala/chisel3/SeqUtils.scala10
-rw-r--r--core/src/main/scala/chisel3/experimental/package.scala14
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala194
-rw-r--r--core/src/main/scala/chisel3/internal/Namer.scala6
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala4
-rw-r--r--core/src/main/scala/chisel3/internal/prefix.scala84
9 files changed, 324 insertions, 35 deletions
diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala
index 46c98bae..983307a6 100644
--- a/core/src/main/scala/chisel3/Data.scala
+++ b/core/src/main/scala/chisel3/Data.scala
@@ -283,6 +283,14 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
}
}
+ override def autoSeed(name: String): this.type = {
+ topBindingOpt match {
+ // Ports are special in that the autoSeed will keep the first name, not the last name
+ case Some(PortBinding(m)) if hasAutoSeed && Builder.currentModule.contains(m) => this
+ case _ => super.autoSeed(name)
+ }
+ }
+
// User-specified direction, local at this node only.
// Note that the actual direction of this node can differ from child and parent specifiedDirection.
private var _specifiedDirection: SpecifiedDirection = SpecifiedDirection.Unspecified
@@ -490,7 +498,11 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
* @param that the $coll to connect to
* @group Connect
*/
- final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions)
+ final def := (that: => Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = {
+ prefix(this) {
+ this.connect(that)(sourceInfo, connectionCompileOptions)
+ }
+ }
/** Connect this $coll to that $coll bi-directionally and element-wise.
*
@@ -499,7 +511,11 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
* @param that the $coll to connect to
* @group Connect
*/
- final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions)
+ final def <> (that: => Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = {
+ prefix(this) {
+ this.bulkConnect(that)(sourceInfo, connectionCompileOptions)
+ }
+ }
@chiselRuntimeDeprecated
@deprecated("litArg is deprecated, use litOption or litTo*Option", "3.2")
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index 140e3003..25037b00 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -41,6 +41,8 @@ object Module extends SourceInfoDoc {
// Save then clear clock and reset to prevent leaking scope, must be set again in the Module
val (saveClock, saveReset) = (Builder.currentClock, Builder.currentReset)
+ val savePrefix = Builder.getPrefix()
+ Builder.clearPrefix()
Builder.currentClock = None
Builder.currentReset = None
@@ -67,6 +69,8 @@ object Module extends SourceInfoDoc {
val component = module.generateComponent()
Builder.components += component
+ Builder.setPrefix(savePrefix)
+
// Handle connections at enclosing scope
if(!Builder.currentModule.isEmpty) {
pushCommand(DefInstance(sourceInfo, module, component.ports))
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
index 0fcec266..5b609384 100644
--- a/core/src/main/scala/chisel3/RawModule.scala
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -42,7 +42,7 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions)
private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = {
for (port <- getModulePorts) {
- port.suggestedName.orElse(names.get(port)) match {
+ port.computeName(None, 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,""" +
@@ -75,13 +75,21 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions)
// All suggestions are in, force names to every node.
for (id <- getIds) {
id match {
- case id: BaseModule => id.forceName(default=id.desiredName, _namespace)
- case id: MemBase[_] => id.forceName(default="_T", _namespace)
+ case id: BaseModule => id.forceName(None, default=id.desiredName, _namespace)
+ case id: MemBase[_] => id.forceName(None, default="MEM", _namespace)
case id: Data =>
if (id.isSynthesizable) {
id.topBinding match {
- case OpBinding(_) | MemoryPortBinding(_) | PortBinding(_) | RegBinding(_) | WireBinding(_) =>
- id.forceName(default="_T", _namespace)
+ case OpBinding(_) =>
+ id.forceName(Some(""), default="T", _namespace)
+ case MemoryPortBinding(_) =>
+ id.forceName(None, default="MPORT", _namespace)
+ case PortBinding(_) =>
+ id.forceName(None, default="PORT", _namespace)
+ case RegBinding(_) =>
+ id.forceName(None, default="REG", _namespace)
+ case WireBinding(_) =>
+ id.forceName(Some(""), default="WIRE", _namespace)
case _ => // don't name literals
}
} // else, don't name unbound types
@@ -152,8 +160,8 @@ trait RequireSyncReset extends MultiIOModule {
abstract class MultiIOModule(implicit moduleCompileOptions: CompileOptions)
extends RawModule {
// Implicit clock and reset pins
- final val clock: Clock = IO(Input(Clock()))
- final val reset: Reset = IO(Input(mkReset))
+ final val clock: Clock = IO(Input(Clock())).autoSeed("clock")
+ final val reset: Reset = IO(Input(mkReset)).autoSeed("reset")
private[chisel3] def mkReset: Reset = {
// Top module and compatibility mode use Bool for reset
@@ -164,6 +172,7 @@ abstract class MultiIOModule(implicit moduleCompileOptions: CompileOptions)
// Setup ClockAndReset
Builder.currentClock = Some(clock)
Builder.currentReset = Some(reset)
+ Builder.clearPrefix()
private[chisel3] override def initializeInParent(parentCompileOptions: CompileOptions): Unit = {
implicit val sourceInfo = UnlocatableSourceInfo
diff --git a/core/src/main/scala/chisel3/SeqUtils.scala b/core/src/main/scala/chisel3/SeqUtils.scala
index 9f09b2c2..9f068898 100644
--- a/core/src/main/scala/chisel3/SeqUtils.scala
+++ b/core/src/main/scala/chisel3/SeqUtils.scala
@@ -3,7 +3,7 @@
package chisel3
import chisel3.experimental.FixedPoint
-import chisel3.internal.throwException
+import chisel3.internal.{prefix, throwException}
import scala.language.experimental.macros
import chisel3.internal.sourceinfo._
@@ -23,8 +23,12 @@ private[chisel3] object SeqUtils {
if (in.tail.isEmpty) {
in.head.asUInt
} else {
- val left = asUInt(in.slice(0, in.length/2))
- val right = asUInt(in.slice(in.length/2, in.length))
+ val left = prefix("left") {
+ asUInt(in.slice(0, in.length/2))
+ }.autoSeed("left")
+ val right = prefix("right") {
+ asUInt(in.slice(in.length/2, in.length))
+ }.autoSeed("right")
right ## left
}
}
diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala
index da103318..71fd186c 100644
--- a/core/src/main/scala/chisel3/experimental/package.scala
+++ b/core/src/main/scala/chisel3/experimental/package.scala
@@ -136,4 +136,18 @@ package object experimental {
}
}
}
+
+ // Use to add a prefix to any component generated in input scope
+ val prefix = chisel3.internal.prefix
+ // Use to remove prefixes not in provided scope
+ val noPrefix = chisel3.internal.noPrefix
+ // Used by Chisel's compiler plugin to automatically name signals
+ def autoNameRecursively[T <: Any](name: String, nameMe: T): T = {
+ chisel3.internal.Builder.nameRecursively(
+ name.replace(" ", ""),
+ nameMe,
+ (id: chisel3.internal.HasId, n: String) => id.autoSeed(n)
+ )
+ nameMe
+ }
}
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index 510919bc..ceb14900 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -9,6 +9,7 @@ import chisel3.experimental._
import chisel3.internal.firrtl._
import chisel3.internal.naming._
import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
+import chisel3.internal.Builder.Prefix
import scala.collection.mutable
@@ -88,25 +89,133 @@ private[chisel3] trait HasId extends InstanceId {
override def hashCode: Int = super.hashCode()
override def equals(that: Any): Boolean = super.equals(that)
- // Facilities for 'suggesting' a name to this.
- // Post-name hooks called to carry the suggestion to other candidates as needed
- private var suggested_name: Option[String] = None
- private val postname_hooks = scala.collection.mutable.ListBuffer.empty[String=>Unit]
- // Only takes the first suggestion!
- def suggestName(name: =>String): this.type = {
- if(suggested_name.isEmpty) suggested_name = Some(name)
- for(hook <- postname_hooks) { hook(name) }
+ // Contains suggested seed (user-decided seed)
+ private var suggested_seed: Option[String] = None
+
+ // Contains the seed computed automatically by the compiler plugin
+ private var auto_seed: Option[String] = None
+
+ // Prefix at time when this class is constructed
+ private val construction_prefix: Prefix = Builder.getPrefix()
+
+ // Prefix when the latest [[suggestSeed]] or [[autoSeed]] is called
+ private var prefix_seed: Prefix = List.empty[Either[String, Data]]
+
+ // Post-seed hooks called to carry the suggested seeds to other candidates as needed
+ private val suggest_postseed_hooks = scala.collection.mutable.ListBuffer.empty[String=>Unit]
+
+ // Post-seed hooks called to carry the auto seeds to other candidates as needed
+ private val auto_postseed_hooks = scala.collection.mutable.ListBuffer.empty[String=>Unit]
+
+ /** Takes the last seed suggested. Multiple calls to this function will take the last given seed, unless
+ * this HasId is a module port (see overridden method in Data.scala).
+ *
+ * If the final computed name conflicts with the final name of another signal, the final name may get uniquified by
+ * appending a digit at the end of the name.
+ *
+ * Is a lower priority than [[suggestName]], in that regardless of whether [[autoSeed]]
+ * was called, [[suggestName]] will always take precedence if it was called.
+ *
+ * @param seed Seed for the name of this component
+ * @return this object
+ */
+ def autoSeed(seed: String): this.type = {
+ auto_seed = Some(seed)
+ for(hook <- auto_postseed_hooks) { hook(seed) }
+ prefix_seed = Builder.getPrefix()
this
}
- private[chisel3] def suggestedName: Option[String] = suggested_name
- private[chisel3] def addPostnameHook(hook: String=>Unit): Unit = postname_hooks += hook
+
+ /** Takes the first seed suggested. Multiple calls to this function will be ignored.
+ * If the final computed name conflicts with another name, it may get uniquified by appending
+ * a digit at the end.
+ *
+ * Is a higher priority than [[autoSeed]], in that regardless of whether [[autoSeed]]
+ * was called, [[suggestName]] will always take precedence.
+ *
+ * @param seed The seed for the name of this component
+ * @return this object
+ */
+ def suggestName(seed: =>String): this.type = {
+ if(suggested_seed.isEmpty) suggested_seed = Some(seed)
+ prefix_seed = Builder.getPrefix()
+ for(hook <- suggest_postseed_hooks) { hook(seed) }
+ this
+ }
+
+ /** Computes the name of this HasId, if one exists
+ * @param defaultPrefix Optionally provide a default prefix for computing the name
+ * @param defaultSeed Optionally provide default seed for computing the name
+ * @return the name, if it can be computed
+ */
+ def computeName(defaultPrefix: Option[String], defaultSeed: Option[String]): Option[String] = {
+ // Recursively builds a name if referenced fields of an aggregate type
+ def buildAggName(id: HasId): Option[String] = {
+ def recArg(node: Arg): Option[String] = node match {
+ case Slot(imm, name) => recArg(imm).map(_ + "_" + name)
+ case Index(imm, ILit(num)) => recArg(imm).map(_ + "_" + num)
+ case Index(imm, n: LitArg) => recArg(imm).map(_ + "_" + n.num)
+ case Index(imm, _: Node) => recArg(imm)
+ case Node(id) => recArg(id.getOptionRef.get)
+ case Ref(name) => Some(name)
+ case ModuleIO(mod, name) if _parent.contains(mod) => Some(name)
+ case ModuleIO(mod, name) => recArg(mod.getRef).map(_ + "_" + name)
+ }
+ id.getOptionRef.flatMap(recArg)
+ }
+
+ /** Computes a name of this signal, given the seed and prefix
+ * @param seed
+ * @param prefix
+ * @return
+ */
+ def buildName(seed: String, prefix: Prefix): String = {
+ val builder = new StringBuilder()
+ prefix.foreach {
+ case Left(s: String) => builder ++= s + "_"
+ case Right(d: HasId) =>
+ buildAggName(d) match {
+ case Some(n) => builder ++= n + "_"
+ case _ =>
+ }
+ case _ =>
+ }
+ builder ++= seed
+ builder.toString
+ }
+
+ if(hasSeed) {
+ Some(buildName(seedOpt.get, prefix_seed))
+ } else {
+ defaultSeed.map { default =>
+ defaultPrefix match {
+ case Some(p) => buildName(default, Left(p) +: construction_prefix)
+ case None => buildName(default, construction_prefix)
+ }
+ }
+ }
+ }
+
+ /** This resolves the precedence of [[autoSeed]] and [[suggestName]]
+ *
+ * @return the current calculation of a name, if it exists
+ */
+ private[chisel3] def seedOpt: Option[String] = suggested_seed.orElse(auto_seed)
+
+ /** @return Whether either autoName or suggestName has been called */
+ def hasSeed: Boolean = seedOpt.isDefined
+
+ private[chisel3] def hasAutoSeed: Boolean = auto_seed.isDefined
+
+ private[chisel3] def addSuggestPostnameHook(hook: String=>Unit): Unit = suggest_postseed_hooks += hook
+ private[chisel3] def addAutoPostnameHook(hook: String=>Unit): Unit = auto_postseed_hooks += hook
// Uses a namespace to convert suggestion into a true name
// Will not do any naming if the reference already assigned.
// (e.g. tried to suggest a name to part of a Record)
- private[chisel3] def forceName(default: =>String, namespace: Namespace): Unit =
+ private[chisel3] def forceName(prefix: Option[String], default: =>String, namespace: Namespace): Unit =
if(_ref.isEmpty) {
- val candidate_name = suggested_name.getOrElse(default)
+ val candidate_name = computeName(prefix, Some(default)).get
val available_name = namespace.name(candidate_name)
setRef(Ref(available_name))
}
@@ -124,7 +233,7 @@ private[chisel3] trait HasId extends InstanceId {
case Some(p) => p._component match {
case Some(c) => _ref match {
case Some(arg) => arg fullName c
- case None => suggested_name.getOrElse("??")
+ case None => computeName(None, None).get
}
case None => throwException("signalName/pathName should be called after circuit elaboration")
}
@@ -158,9 +267,14 @@ private[chisel3] trait HasId extends InstanceId {
}
}
val valNames = getValNames(this.getClass)
- def isPublicVal(m: java.lang.reflect.Method) =
- m.getParameterTypes.isEmpty && valNames.contains(m.getName) && !m.getDeclaringClass.isAssignableFrom(rootClass)
- this.getClass.getMethods.sortWith(_.getName < _.getName).filter(isPublicVal(_))
+ def isPublicVal(m: java.lang.reflect.Method) = {
+ val noParameters = m.getParameterTypes.isEmpty
+ val aVal = valNames.contains(m.getName)
+ val notAssignable = !m.getDeclaringClass.isAssignableFrom(rootClass)
+ val notWeirdVal = !m.getName.contains('$')
+ noParameters && aVal && notAssignable && notWeirdVal
+ }
+ this.getClass.getMethods.filter(isPublicVal).sortWith(_.getName < _.getName)
}
}
/** Holds the implementation of toNamed for Data and MemBase */
@@ -199,6 +313,9 @@ private[chisel3] class ChiselContext() {
// Record the Bundle instance, class name, method name, and reverse stack trace position of open Bundles
val bundleStack: ArrayBuffer[(Bundle, String, String, Int)] = ArrayBuffer()
+
+ // Records the different prefixes which have been scoped at this point in time
+ val prefixStack: ArrayBuffer[Either[String, HasId]] = ArrayBuffer()
}
private[chisel3] class DynamicContext() {
@@ -223,6 +340,10 @@ private[chisel3] class DynamicContext() {
}
private[chisel3] object Builder {
+
+ // Represents the current state of the prefixes given
+ type Prefix = List[Either[String, Data]]
+
// All global mutable state must be referenced via dynamicContextVar!!
private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None)
private def dynamicContext: DynamicContext = {
@@ -258,6 +379,43 @@ private[chisel3] object Builder {
def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations
def namingStack: NamingStack = dynamicContext.namingStack
+ // Puts either a prefix string or hasId onto the prefix stack
+ def pushPrefix(d: Either[String, HasId]): Unit = {
+ chiselContext.get().prefixStack += d
+ }
+
+ // Puts a prefix string onto the prefix stack
+ def pushPrefix(d: String): Unit = {
+ chiselContext.get().prefixStack += Left(d)
+ }
+
+ // Puts a prefix data onto the prefix stack
+ def pushPrefix(d: HasId): Unit = {
+ chiselContext.get().prefixStack += Right(d)
+ }
+
+ // Remove a prefix from top of the stack
+ def popPrefix(): Either[String, HasId] = {
+ val ps = chiselContext.get().prefixStack
+ ps.remove(ps.size - 1)
+ }
+
+ // Removes all prefixes from the prefix stack
+ def clearPrefix(): Unit = {
+ val ps = chiselContext.get().prefixStack
+ ps.clear()
+ }
+
+ // Clears existing prefixes and sets to new prefix stack
+ def setPrefix(prefix: Prefix): Unit = {
+ val ps = chiselContext.get().prefixStack
+ clearPrefix()
+ ps.insertAll(0, prefix)
+ }
+
+ // Returns the prefix stack at this moment
+ def getPrefix(): Prefix = chiselContext.get().prefixStack.toList.asInstanceOf[Prefix]
+
def currentModule: Option[BaseModule] = dynamicContextVar.value match {
case Some(dyanmicContext) => dynamicContext.currentModule
case _ => None
@@ -411,7 +569,7 @@ private[chisel3] object Builder {
dynamicContextVar.withValue(Some(new DynamicContext())) {
errors.info("Elaborating design...")
val mod = f
- mod.forceName(mod.name, globalNamespace)
+ mod.forceName(None, mod.name, globalNamespace)
errors.checkpoint()
errors.info("Done elaborating.")
@@ -446,7 +604,7 @@ object DynamicNamingStack {
}
prefixRef
}
-
+
def length() : Int = Builder.namingStackOption.get.length
}
diff --git a/core/src/main/scala/chisel3/internal/Namer.scala b/core/src/main/scala/chisel3/internal/Namer.scala
index 999971a4..0153c0df 100644
--- a/core/src/main/scala/chisel3/internal/Namer.scala
+++ b/core/src/main/scala/chisel3/internal/Namer.scala
@@ -72,7 +72,7 @@ class NamingContext extends NamingContextInterface {
val descendants = new IdentityHashMap[AnyRef, ListBuffer[NamingContext]]()
val anonymousDescendants = ListBuffer[NamingContext]()
val items = ListBuffer[(AnyRef, String)]()
- var closed = false // a sanity check to ensure no more name() calls are done after name_prefix
+ var closed = false // a sanity check to ensure no more name() calls are done after namePrefix
/** Adds a NamingContext object as a descendant - where its contained objects will have names
* prefixed with the name given to the reference object, if the reference object is named in the
@@ -87,7 +87,7 @@ class NamingContext extends NamingContextInterface {
}
def name[T](obj: T, name: String): T = {
- assert(!closed, "Can't name elements after name_prefix called")
+ assert(!closed, "Can't name elements after namePrefix called")
obj match {
case _: NoChiselNamePrefix => // Don't name things with NoChiselNamePrefix
case ref: AnyRef => items += ((ref, name))
@@ -149,6 +149,6 @@ class NamingStack {
namingStack.top.addDescendant(prefixRef, until)
}
}
-
+
def length() : Int = namingStack.length
}
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
index 44fdb833..1783f68f 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -72,11 +72,11 @@ abstract class Arg {
case class Node(id: HasId) extends Arg {
override def fullName(ctx: Component): String = id.getOptionRef match {
case Some(arg) => arg.fullName(ctx)
- case None => id.suggestedName.getOrElse("??")
+ case None => id.instanceName
}
def name: String = id.getOptionRef match {
case Some(arg) => arg.name
- case None => id.suggestedName.getOrElse("??")
+ case None => id.instanceName
}
}
diff --git a/core/src/main/scala/chisel3/internal/prefix.scala b/core/src/main/scala/chisel3/internal/prefix.scala
new file mode 100644
index 00000000..fbb1318c
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/prefix.scala
@@ -0,0 +1,84 @@
+// See LICENSE for license details.
+
+package chisel3.internal
+
+/** Use to add a prefix to any components generated in the provided scope.
+ *
+ * @example {{{
+ *
+ * val x1 = prefix("first") {
+ * // Anything generated here will be prefixed with "first"
+ * }
+ *
+ * val x2 = prefix(mysignal) {
+ * // Anything generated here will be prefixed with the name of mysignal
+ * }
+ *
+ * }}}
+ *
+ */
+private[chisel3] object prefix { // scalastyle:ignore
+
+ /** Use to add a prefix to any components generated in the provided scope
+ * The prefix is the name of the provided which, which may not be known yet.
+ *
+ * @param name The signal/instance whose name will be the prefix
+ * @param f a function for which any generated components are given the prefix
+ * @tparam T The return type of the provided function
+ * @return The return value of the provided function
+ */
+ def apply[T](name: HasId)(f: => T): T = {
+ Builder.pushPrefix(name)
+ val ret = f
+ Builder.popPrefix()
+ ret
+ }
+
+ /** Use to add a prefix to any components generated in the provided scope
+ * The prefix is a string, which must be known when this function is used.
+ *
+ * @param name The name which will be the prefix
+ * @param f a function for which any generated components are given the prefix
+ * @tparam T The return type of the provided function
+ * @return The return value of the provided function
+ */
+ def apply[T](name: String)(f: => T): T = {
+ Builder.pushPrefix(name)
+ val ret = f
+ // Sometimes val's can occur between the Module.apply and Module constructor
+ // This causes extra prefixes to be added, and subsequently cleared in the
+ // Module constructor. Thus, we need to just make sure if the previous push
+ // was an incorrect one, to not pop off an empty stack
+ if(Builder.getPrefix().nonEmpty) Builder.popPrefix()
+ ret
+ }
+}
+
+/** Use to eliminate any existing prefixes within the provided scope.
+ *
+ * @example {{{
+ *
+ * val x1 = noPrefix {
+ * // Anything generated here will not be prefixed by anything outside this scope
+ * }
+ *
+ * }}}
+ *
+ */
+private[chisel3] object noPrefix {
+
+ /** Use to clear existing prefixes so no signals within the scope are prefixed by signals/names
+ * outside the scope
+ *
+ * @param f a function for which any generated components are given the prefix
+ * @tparam T The return type of the provided function
+ * @return The return value of the provided function
+ */
+ def apply[T](f: => T): T = {
+ val prefix = Builder.getPrefix()
+ Builder.clearPrefix()
+ val ret = f
+ Builder.setPrefix(prefix)
+ ret
+ }
+}