summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt1
-rw-r--r--core/src/main/scala/chisel3/experimental/package.scala9
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala2
-rw-r--r--core/src/main/scala/chisel3/internal/plugin/package.scala22
-rw-r--r--docs/src/cookbooks/naming.md62
-rw-r--r--docs/src/explanations/naming.md229
-rw-r--r--plugin/src/main/resources/scalac-plugin.xml2
-rw-r--r--plugin/src/main/scala-2.12/chisel3/internal/plugin/ChiselPlugin.scala (renamed from plugin/src/main/scala-2.12/chisel3/plugin/ChiselPlugin.scala)18
-rw-r--r--src/test/scala/chiselTests/naming/NamePluginSpec.scala18
9 files changed, 343 insertions, 20 deletions
diff --git a/build.sbt b/build.sbt
index 8512eb0e..b3eb93d2 100644
--- a/build.sbt
+++ b/build.sbt
@@ -233,6 +233,7 @@ lazy val docs = project // new documentation project
.in(file("docs-target")) // important: it must not be docs/
.dependsOn(chisel)
.enablePlugins(MdocPlugin)
+ .settings(usePluginSettings: _*)
.settings(commonSettings)
.settings(
scalacOptions += "-language:reflectiveCalls",
diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala
index 71fd186c..12631512 100644
--- a/core/src/main/scala/chisel3/experimental/package.scala
+++ b/core/src/main/scala/chisel3/experimental/package.scala
@@ -141,13 +141,4 @@ package object experimental {
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 e55f1af7..741a2498 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -119,7 +119,7 @@ private[chisel3] trait HasId extends InstanceId {
* @param seed Seed for the name of this component
* @return this object
*/
- def autoSeed(seed: String): this.type = {
+ private [chisel3] def autoSeed(seed: String): this.type = {
auto_seed = Some(seed)
for(hook <- auto_postseed_hooks) { hook(seed) }
prefix_seed = Builder.getPrefix()
diff --git a/core/src/main/scala/chisel3/internal/plugin/package.scala b/core/src/main/scala/chisel3/internal/plugin/package.scala
new file mode 100644
index 00000000..6d78b1c3
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/plugin/package.scala
@@ -0,0 +1,22 @@
+// See LICENSE for license details.
+
+package chisel3.internal
+
+package object plugin {
+ /** Used by Chisel's compiler plugin to automatically name signals
+ * DO NOT USE in your normal Chisel code!!!
+ *
+ * @param name The name to use
+ * @param nameMe The thing to be named
+ * @tparam T The type of the thing to be named
+ * @return The thing, but now named
+ */
+ 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/docs/src/cookbooks/naming.md b/docs/src/cookbooks/naming.md
new file mode 100644
index 00000000..5f57826f
--- /dev/null
+++ b/docs/src/cookbooks/naming.md
@@ -0,0 +1,62 @@
+---
+layout: docs
+title: "Naming Cookbook"
+section: "chisel3"
+---
+
+```scala mdoc:invisible
+import chisel3.internal.plugin._
+import chisel3._
+import chisel3.experimental.prefix
+import chisel3.experimental.noPrefix
+import chisel3.stage.ChiselStage
+```
+
+### I still have _T signals, can this be fixed?
+
+First check - is the compiler plugin properly enabled? Scalac plugins are enabled via the scalac option
+`-Xplugin:<path/to/jar>`. You can check which compiler plugins are enabled by running `show Compile / scalacOptions` in
+the sbt prompt.
+
+If the plugin is enabled, these signals could be intermediate values which are consumed by either assertions or when
+predicates. In these cases, the compiler plugin often can't find a good prefix for the generated intermediate signals.
+We recommend you manually insert calls to `prefix` to fix these cases. We did this to Rocket Chip and saw huge benefits!
+
+### I still see _GEN signals, can this be fixed?
+
+`_GEN` signals are usually generated from the FIRRTL compiler, rather than the Chisel library. We are working on
+renaming these signals with more context-dependent names, but it is a work in progress. Thanks for caring!
+
+### My module names are super unstable - I change one thing and Queue_1 becomes Queue_42. Help!
+
+This is the infamous `Queue` instability problem. In general, these cases are best solved at the source - the module
+itself! If you overwrite `desiredName` to include parameter information (see the
+[explanation](../explanations/naming.md#set-a-module-name) for more info), then this can avoid this problem permanantly.
+We've done this with some Chisel utilities with great results!
+
+### I want to add some hardware or assertions, but each time I do all the signal names get bumped!
+
+This is the classic "ECO" problem, and we provide descriptions in [explanation](../explanations/naming.md). In short,
+we recommend wrapping all additional logic in a prefix scope, which enables a unique namespace. This should prevent
+name collisions, which are what triggers all those annoying signal name bumps!
+
+### I want to force a signal (or instance) name to something, how do I do that?
+
+Use the `.suggestName` method, which is on all classes which subtype 'Data'.
+
+### All this prefixing is annoying, how do I fix it?
+
+You can use the `noPrefix { ... }` to strip the prefix from all signals generated in that scope.
+
+```scala mdoc
+class ExampleNoPrefix extends MultiIOModule {
+ val in = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt()))
+
+ val add = noPrefix { in + in + in }
+
+ out := add
+}
+
+println(ChiselStage.emitVerilog(new Example7))
+```
diff --git a/docs/src/explanations/naming.md b/docs/src/explanations/naming.md
new file mode 100644
index 00000000..69870813
--- /dev/null
+++ b/docs/src/explanations/naming.md
@@ -0,0 +1,229 @@
+---
+layout: docs
+title: "Naming"
+section: "chisel3"
+---
+
+Historically, Chisel has had trouble reliably capturing the names of signals. The reasons for this are due to (1)
+primarily relying on reflection to find names, (2) using `@chiselName` macro which had unreliable behavior.
+
+Chisel 3.4 introduced a custom Scala compiler plugin which enables reliabe and automatic capturing of signal names, when
+they are declared. In addition, this release includes prolific use of a new prefixing API which enables more stable
+naming of signals programmatically generated from function calls.
+
+This document explains how naming now works in Chisel for signal and module names. For cookbook examples on how to fix
+systemic name-stability issues, please refer to the naming [cookbook](../cookbooks/naming.md).
+
+### Compiler Plugin
+
+```scala mdoc
+import chisel3.internal.plugin._
+import chisel3._
+import chisel3.experimental.prefix
+import chisel3.experimental.noPrefix
+import chisel3.stage.ChiselStage
+```
+
+With the release of Chisel 3.4, users should add the following line to their build.sbt settings to get the improved
+naming:
+
+```scala
+addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full)
+```
+
+This plugin will run after the 'typer' phase of the Scala compiler. It looks for any user code which is of the form
+`val x = y`, where `x` is of type `chisel3.Data`, `chisel3.MemBase`, or `chisel3.experimental.BaseModule`. For each
+line which fits this criteria, it rewrites that line. In the following examples, the commented line is the what the
+line above is rewritten to.
+
+If the line is within a bundle declaration or is a module instantiation, it is rewritten to replace the right hand
+side with a call to `autoNameRecursively`, which names the signal/module.
+
+```scala mdoc
+class MyBundle extends Bundle {
+ val foo = Input(UInt(3.W))
+ // val foo = autoNameRecursively("foo", Input(UInt(3.W)))
+}
+class Example1 extends MultiIOModule {
+ val io = IO(new MyBundle())
+ // val io = autoNameRecursively("io", IO(new MyBundle()))
+}
+println(ChiselStage.emitVerilog(new Example1))
+```
+
+Otherwise, it is rewritten to also include the name as a prefix to any signals generated while executing the right-hand-
+side of the val declaration:
+
+```scala mdoc
+class Example2 extends MultiIOModule {
+ val in = IO(Input(UInt(2.W)))
+ // val in = autoNameRecursively("in", prefix("in")(IO(Input(UInt(2.W)))))
+
+ val out = IO(Output(UInt(2.W)))
+ // val out = autoNameRecursively("out", prefix("out")(IO(Output(UInt(2.W)))))
+
+ def inXin() = in * in
+
+ val add = 3.U + inXin()
+ // val add = autoNameRecursively("add", prefix("add")(3.U + inXin()))
+ // Note that the intermediate result of the multiplication is prefixed with `add`
+
+ out := add + 1.U
+}
+
+println(ChiselStage.emitVerilog(new Example2))
+```
+
+Note that the naming also works if the hardware type is nested in an `Option` or a subtype of `Iterable`:
+
+```scala mdoc
+class Example3 extends MultiIOModule {
+ val in = IO(Input(UInt(2.W)))
+ // val in = autoNameRecursively("in", prefix("in")(IO(Input(UInt(2.W)))))
+
+ val out = IO(Output(UInt()))
+ // val out = autoNameRecursively("out", prefix("out")(IO(Output(UInt(2.W)))))
+
+ def inXin() = in * in
+
+ val opt = Some(3.U + inXin())
+ // Note that the intermediate result of the inXin() is prefixed with `opt`:
+ // val opt = autoNameRecursively("opt", prefix("opt")(Some(3.U + inXin())))
+
+ out := opt.get + 1.U
+}
+
+println(ChiselStage.emitVerilog(new Example3))
+```
+
+### Prefixing
+
+As shown above, the compiler plugin automatically attempts to prefix some of your signals for you. However, you as a
+user can also add your own prefixes. This is especially for ECO-type fixes where you need to add some logic to a module
+but don't want to influence other names in the module.
+
+In the following example, we prefix additional logic with "ECO", where `Example4` is pre-ECO and `Example5` is post-ECO:
+
+```scala mdoc
+class Example4 extends MultiIOModule {
+ val in = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt()))
+
+ val add = in + in + in
+
+ out := add + 1.U
+}
+
+class Example5 extends MultiIOModule {
+ val in = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt()))
+
+ val add = in + in + in
+
+ out := prefix("ECO") { add + 1.U + in }
+}
+
+println(ChiselStage.emitVerilog(new Example4))
+println(ChiselStage.emitVerilog(new Example5))
+
+```
+
+Also note that the prefixes append to each other (including the prefix generated by the compiler plugin):
+
+```scala mdoc
+class Example6 extends MultiIOModule {
+ val in = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt()))
+
+ val add = prefix("foo") { in + in + in }
+
+ out := add
+}
+
+println(ChiselStage.emitVerilog(new Example6))
+```
+
+Sometimes you may want to disable the prefixing. This might occur if you are writing a library function and
+don't want the prefixing behavior. In this case, you can use the `noPrefix` object:
+
+```scala mdoc
+class Example7 extends MultiIOModule {
+ val in = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt()))
+
+ val add = noPrefix { in + in + in }
+
+ out := add
+}
+
+println(ChiselStage.emitVerilog(new Example7))
+```
+
+### Suggest a Signal's Name (or the instance name of a Module)
+
+If you want to specify the name of a signal, you can always use the `.suggestName` API. Please note that the suggested
+name will still be prefixed (including by the plugin). You can always use the `noPrefix` object to strip this.
+
+```scala mdoc
+class Example8 extends MultiIOModule {
+ val in = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt()))
+
+ val add = (in + (in + in).suggestName("foo"))
+
+ out := add
+}
+
+println(ChiselStage.emitVerilog(new Example8))
+```
+
+### Set a Module Name
+
+If you want to specify the module's name (not the instance name of a module), you can always override the `desiredName`
+value. Note that you can parameterize the name by the module's parameters. This is an excellent way to make your module
+names more stable and is highly recommended to do.
+
+```scala mdoc
+class Example9(width: Int) extends MultiIOModule {
+ override val desiredName = s"EXAMPLE9WITHWIDTH$width"
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt()))
+
+ val add = (in + (in + in).suggestName("foo"))
+
+ out := add
+}
+
+println(ChiselStage.emitVerilog(new Example9(8)))
+println(ChiselStage.emitVerilog(new Example9(1)))
+```
+
+### Reflection Naming
+
+Regardless of whether the compiler plugin is enabled or not, after Chisel constructs a module, it attempts to name all
+members of the Module. This will name all vals which are fields of the module class, but it will not name any
+vals in nested functions or scopes.
+
+If the plugin successfully names a signal, the reflection naming will do nothing. We plan to deprecate all reflection
+naming in a future Chisel release, but are leaving it to allow the plugin naming to be optional (but recommended).
+
+For example, the signals in the following module are in a nested scope; the plugin successfully names them, but
+reflection naming cannot:
+
+```scala mdoc
+class Example10 extends MultiIOModule {
+ {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt()))
+
+ val add = in + in
+
+ out := add
+ }
+}
+```
+
+### @chiselName
+
+This macro is no longer recommended as its functionality is entirely replaced by the compiler plugin. Feel free to
+delete from your Chisel designs! \ No newline at end of file
diff --git a/plugin/src/main/resources/scalac-plugin.xml b/plugin/src/main/resources/scalac-plugin.xml
index b2b44fc6..abe51d12 100644
--- a/plugin/src/main/resources/scalac-plugin.xml
+++ b/plugin/src/main/resources/scalac-plugin.xml
@@ -1,4 +1,4 @@
<plugin>
<name>chiselplugin</name>
- <classname>chisel3.plugin.ChiselPlugin</classname>
+ <classname>chisel3.internal.plugin.ChiselPlugin</classname>
</plugin>
diff --git a/plugin/src/main/scala-2.12/chisel3/plugin/ChiselPlugin.scala b/plugin/src/main/scala-2.12/chisel3/internal/plugin/ChiselPlugin.scala
index 3b3b52e9..2197430c 100644
--- a/plugin/src/main/scala-2.12/chisel3/plugin/ChiselPlugin.scala
+++ b/plugin/src/main/scala-2.12/chisel3/internal/plugin/ChiselPlugin.scala
@@ -1,6 +1,6 @@
// See LICENSE for license details.
-package chisel3.plugin
+package chisel3.internal.plugin
import scala.tools.nsc
import nsc.{Global, Phase}
@@ -13,14 +13,14 @@ import scala.tools.nsc.transform.TypingTransformers
class ChiselPlugin(val global: Global) extends Plugin {
val name = "chiselplugin"
val description = "Plugin for Chisel 3 Hardware Description Language"
- val components = List[PluginComponent](new ChiselComponent(global))
+ val components: List[PluginComponent] = List[PluginComponent](new ChiselComponent(global))
}
// The component of the chisel plugin. Not sure exactly what the difference is between
// a Plugin and a PluginComponent.
class ChiselComponent(val global: Global) extends PluginComponent with TypingTransformers {
import global._
- val runsAfter = List[String]("typer")
+ val runsAfter: List[String] = List[String]("typer")
val phaseName: String = "chiselcomponent"
def newPhase(_prev: Phase): ChiselComponentPhase = new ChiselComponentPhase(_prev)
class ChiselComponentPhase(prev: Phase) extends StdPhase(prev) {
@@ -115,21 +115,21 @@ class ChiselComponent(val global: Global) extends PluginComponent with TypingTra
// If a Data and in a Bundle, just get the name but not a prefix
case dd @ ValDef(mods, name, tpt, rhs) if okVal(dd, tq"chisel3.Data") && inBundle(dd) =>
val TermName(str: String) = name
- val newRHS = super.transform(rhs)
- val named = q"chisel3.experimental.autoNameRecursively($str, $newRHS)"
+ val newRHS = transform(rhs)
+ val named = q"chisel3.internal.plugin.autoNameRecursively($str, $newRHS)"
treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
// If a Data or a Memory, get the name and a prefix
case dd @ ValDef(mods, name, tpt, rhs) if okVal(dd, tq"chisel3.Data", tq"chisel3.MemBase[_]") =>
val TermName(str: String) = name
- val newRHS = super.transform(rhs)
+ val newRHS = transform(rhs)
val prefixed = q"chisel3.experimental.prefix.apply[$tpt](name=$str)(f=$newRHS)"
- val named = q"chisel3.experimental.autoNameRecursively($str, $prefixed)"
+ val named = q"chisel3.internal.plugin.autoNameRecursively($str, $prefixed)"
treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
// If an instance, just get a name but no prefix
case dd @ ValDef(mods, name, tpt, rhs) if okVal(dd, tq"chisel3.experimental.BaseModule") =>
val TermName(str: String) = name
- val newRHS = super.transform(rhs)
- val named = q"chisel3.experimental.autoNameRecursively($str, $newRHS)"
+ val newRHS = transform(rhs)
+ val named = q"chisel3.internal.plugin.autoNameRecursively($str, $newRHS)"
treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
// Otherwise, continue
case _ => super.transform(tree)
diff --git a/src/test/scala/chiselTests/naming/NamePluginSpec.scala b/src/test/scala/chiselTests/naming/NamePluginSpec.scala
index fc90264d..946b557a 100644
--- a/src/test/scala/chiselTests/naming/NamePluginSpec.scala
+++ b/src/test/scala/chiselTests/naming/NamePluginSpec.scala
@@ -203,5 +203,23 @@ class NamePluginSpec extends ChiselFlatSpec with Utils {
y
}
}
+
+ "Nested val declarations" should "all be named" in {
+ class Test extends MultiIOModule {
+ {
+ val a = {
+ val b = {
+ val c = Wire(UInt(3.W))
+ Wire(UInt(3.W))
+ }
+ Wire(UInt(3.W))
+ }
+ }
+ }
+
+ aspectTest(() => new Test) {
+ top: Test => Select.wires(top).map(_.instanceName) should be (List("a_b_c", "a_b", "a"))
+ }
+ }
}