summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt15
-rw-r--r--core/src/main/scala/chisel3/Module.scala4
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala57
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/package.scala2
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala2
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala30
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala2
-rw-r--r--docs/src/explanations/naming.md121
-rw-r--r--plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala5
-rw-r--r--src/test/scala/chiselTests/naming/NamePluginSpec.scala19
-rw-r--r--src/test/scala/chiselTests/naming/PrefixSpec.scala93
11 files changed, 299 insertions, 51 deletions
diff --git a/build.sbt b/build.sbt
index 7242bb6e..c3d25a09 100644
--- a/build.sbt
+++ b/build.sbt
@@ -170,7 +170,20 @@ lazy val core = (project in file("core")).
buildInfoKeys := Seq[BuildInfoKey](buildInfoPackage, version, scalaVersion, sbtVersion)
).
settings(publishSettings: _*).
- settings(mimaPreviousArtifacts := Set("edu.berkeley.cs" %% "chisel3-core" % "3.5.3")).
+ settings(
+ mimaPreviousArtifacts := Set("edu.berkeley.cs" %% "chisel3-core" % "3.5.3"),
+ mimaBinaryIssueFilters ++= Seq(
+ // Modified package private methods (https://github.com/lightbend/mima/issues/53)
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.Data._computeName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.Data.forceName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.MemBase._computeName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.MemBase.forceName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.VerificationStatement._computeName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.VerificationStatement.forceName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.experimental.BaseModule._computeName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.experimental.BaseModule.forceName"),
+ )
+ ).
settings(
name := "chisel3-core",
scalacOptions := scalacOptions.value ++ Seq(
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index d03122f9..ba2d2e32 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -275,7 +275,7 @@ package internal {
private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = {
val record = _portsRecord
// Use .forceName to re-use default name resolving behavior
- record.forceName(None, default = this.desiredName, namespace)
+ record.forceName(default = this.desiredName, namespace)
// Now take the Ref that forceName set and convert it to the correct Arg
val instName = record.getRef match {
case Ref(name) => name
@@ -497,7 +497,7 @@ package experimental {
private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = {
for (port <- getModulePorts) {
- port._computeName(None, None).orElse(names.get(port)) match {
+ port._computeName(None).orElse(names.get(port)) match {
case Some(name) =>
if (_namespace.contains(name)) {
Builder.error(
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
index bd04fdc4..f2ce4c70 100644
--- a/core/src/main/scala/chisel3/RawModule.scala
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -94,26 +94,26 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
id match {
case id: ModuleClone[_] => id.setRefAndPortsRef(_namespace) // special handling
case id: InstanceClone[_] => id.setAsInstanceRef()
- case id: BaseModule => id.forceName(None, default = id.desiredName, _namespace)
- case id: MemBase[_] => id.forceName(None, default = "MEM", _namespace)
- case id: stop.Stop => id.forceName(None, default = "stop", _namespace)
- case id: assert.Assert => id.forceName(None, default = "assert", _namespace)
- case id: assume.Assume => id.forceName(None, default = "assume", _namespace)
- case id: cover.Cover => id.forceName(None, default = "cover", _namespace)
- case id: printf.Printf => id.forceName(None, default = "printf", _namespace)
+ case id: BaseModule => id.forceName(default = id.desiredName, _namespace)
+ case id: MemBase[_] => id.forceName(default = "MEM", _namespace)
+ case id: stop.Stop => id.forceName(default = "stop", _namespace)
+ case id: assert.Assert => id.forceName(default = "assert", _namespace)
+ case id: assume.Assume => id.forceName(default = "assume", _namespace)
+ case id: cover.Cover => id.forceName(default = "cover", _namespace)
+ case id: printf.Printf => id.forceName(default = "printf", _namespace)
case id: Data =>
if (id.isSynthesizable) {
id.topBinding match {
case OpBinding(_, _) =>
- id.forceName(Some(""), default = "T", _namespace)
+ id.forceName(default = "_T", _namespace)
case MemoryPortBinding(_, _) =>
- id.forceName(None, default = "MPORT", _namespace)
+ id.forceName(default = "MPORT", _namespace)
case PortBinding(_) =>
- id.forceName(None, default = "PORT", _namespace)
+ id.forceName(default = "PORT", _namespace)
case RegBinding(_, _) =>
- id.forceName(None, default = "REG", _namespace)
+ id.forceName(default = "REG", _namespace)
case WireBinding(_, _) =>
- id.forceName(Some(""), default = "WIRE", _namespace)
+ id.forceName(default = "_WIRE", _namespace)
case _ => // don't name literals
}
} // else, don't name unbound types
@@ -189,18 +189,39 @@ package object internal {
/** Marker trait for modules that are not true modules */
private[chisel3] trait PseudoModule extends BaseModule
+ /* Check if a String name is a temporary name */
+ def isTemp(name: String): Boolean = name.nonEmpty && name.head == '_'
+
/** Creates a name String from a prefix and a seed
* @param prefix The prefix associated with the seed (must be in correct order, *not* reversed)
* @param seed The seed for computing the name (if available)
*/
def buildName(seed: String, prefix: Prefix): String = {
- val builder = new StringBuilder()
- prefix.foreach { p =>
- builder ++= p
- builder += '_'
+ // Don't bother copying the String if there's no prefix
+ if (prefix.isEmpty) {
+ seed
+ } else {
+ // Using Java's String builder to micro-optimize appending a String excluding 1st character
+ // for temporaries
+ val builder = new java.lang.StringBuilder()
+ // Starting with _ is the indicator of a temporary
+ val temp = isTemp(seed)
+ // Make sure the final result is also a temporary if this is a temporary
+ if (temp) {
+ builder.append('_')
+ }
+ prefix.foreach { p =>
+ builder.append(p)
+ builder.append('_')
+ }
+ if (temp) {
+ // We've moved the leading _ to the front, drop it here
+ builder.append(seed, 1, seed.length)
+ } else {
+ builder.append(seed)
+ }
+ builder.toString
}
- builder ++= seed
- builder.toString
}
// Private reflective version of "val io" to maintain Chisel.Module semantics without having
diff --git a/core/src/main/scala/chisel3/experimental/dataview/package.scala b/core/src/main/scala/chisel3/experimental/dataview/package.scala
index c583c516..71ae2d8f 100644
--- a/core/src/main/scala/chisel3/experimental/dataview/package.scala
+++ b/core/src/main/scala/chisel3/experimental/dataview/package.scala
@@ -33,7 +33,7 @@ package object dataview {
// The names of views do not matter except for when a view is annotated. For Views that correspond
// To a single Data, we just forward the name of the Target. For Views that correspond to more
// than one Data, we return this assigned name but rename it in the Convert stage
- result.forceName(None, "view", Builder.viewNamespace)
+ result.forceName("view", Builder.viewNamespace)
result
}
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
index 46a38e7c..c83479b0 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
@@ -218,7 +218,7 @@ object Lookupable {
result.bind(newBinding)
result.setAllParents(Some(ViewParent))
- result.forceName(None, "view", Builder.viewNamespace)
+ result.forceName("view", Builder.viewNamespace)
result
}
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index 6f02b57c..6fd9bdd5 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -177,21 +177,13 @@ private[chisel3] trait HasId extends InstanceId {
}
/** 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
*/
- private[chisel3] def _computeName(defaultPrefix: Option[String], defaultSeed: Option[String]): Option[String] = {
- if (hasSeed) {
- Some(buildName(seedOpt.get, naming_prefix.reverse))
- } else {
- defaultSeed.map { default =>
- defaultPrefix match {
- case Some(p) => buildName(default, p :: naming_prefix.reverse)
- case None => buildName(default, naming_prefix.reverse)
- }
- }
- }
+ private[chisel3] def _computeName(defaultSeed: Option[String]): Option[String] = {
+ seedOpt
+ .orElse(defaultSeed)
+ .map(name => buildName(name, naming_prefix.reverse))
}
/** This resolves the precedence of [[autoSeed]] and [[suggestName]]
@@ -211,9 +203,9 @@ private[chisel3] trait HasId extends InstanceId {
// 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(prefix: Option[String], default: => String, namespace: Namespace): Unit =
+ private[chisel3] def forceName(default: => String, namespace: Namespace): Unit =
if (_ref.isEmpty) {
- val candidate_name = _computeName(prefix, Some(default)).get
+ val candidate_name = _computeName(Some(default)).get
val available_name = namespace.name(candidate_name)
setRef(Ref(available_name))
// Clear naming prefix to free memory
@@ -246,7 +238,7 @@ private[chisel3] trait HasId extends InstanceId {
"This will become an error in Chisel 3.6."
errors.deprecated(msg, None)
errors.checkpoint(logger)
- _computeName(None, None).get
+ _computeName(None).get
}
// Helper for reifying views if they map to a single Target
@@ -506,7 +498,11 @@ private[chisel3] object Builder extends LazyLogging {
}
}
buildAggName(d).map { name =>
- pushPrefix(name)
+ if (isTemp(name)) {
+ pushPrefix(name.tail)
+ } else {
+ pushPrefix(name)
+ }
}.isDefined
}
@@ -749,7 +745,7 @@ private[chisel3] object Builder extends LazyLogging {
logger.info("Elaborating design...")
val mod = f
if (forceModName) { // This avoids definition name index skipping with D/I
- mod.forceName(None, mod.name, globalNamespace)
+ mod.forceName(mod.name, globalNamespace)
}
errors.checkpoint(logger)
logger.info("Done elaborating.")
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
index 1ee8842f..9327c29e 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -94,7 +94,7 @@ object Arg {
case Some(arg) => arg.name
case None =>
id match {
- case data: Data => data._computeName(None, Some("?")).get
+ case data: Data => data._computeName(Some("?")).get
case _ => "?"
}
}
diff --git a/docs/src/explanations/naming.md b/docs/src/explanations/naming.md
index a9f21936..99797cb2 100644
--- a/docs/src/explanations/naming.md
+++ b/docs/src/explanations/naming.md
@@ -24,11 +24,11 @@ import chisel3.experimental.{prefix, 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:
+With the release of Chisel 3.5, users are required to add the following line to
+their build.sbt settings:
```scala
-// chiselVersion is the String version (eg. "3.4.0")
+// chiselVersion is the String version (eg. "3.5.3")
addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full)
```
@@ -78,6 +78,29 @@ class Example2 extends Module {
ChiselStage.emitVerilog(new Example2)
```
+Prefixing can also be derived from the name of signals on the left-hand side of a connection.
+While this is not implemented via the compiler plugin, the behavior should feel similar:
+
+```scala mdoc
+class ConnectPrefixing extends Module {
+ 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)))))
+
+ out := { // technically this is not wrapped in autoNameRecursively nor prefix
+ // But the Chisel runtime will still use the name of `out` as a prefix
+ val double = in * in
+ // val double = autoNameRecursively("double")(prefix("double")(in * in))
+ double + 1.U
+ }
+}
+```
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new ConnectPrefixing)
+```
+
Note that the naming also works if the hardware type is nested in an `Option` or a subtype of `Iterable`:
```scala mdoc
@@ -121,7 +144,7 @@ Users who desire a prefix are encouraged to provide one as [described below](#pr
### 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
+user can also add your own prefixes. This is especially useful 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:
@@ -202,6 +225,96 @@ class Example8 extends Module {
ChiselStage.emitVerilog(new Example8)
```
+Note that using `.suggestName` does **not** affect prefixes derived from val names;
+however, it _can_ affect prefixes derived from connections (eg. `:=`):
+
+```scala mdoc
+class ConnectionPrefixExample extends Module {
+ val in0 = IO(Input(UInt(2.W)))
+ val in1 = IO(Input(UInt(2.W)))
+
+ val out0 = {
+ val port = IO(Output(UInt()))
+ // Even though this suggestName is before mul, the prefix used in this scope
+ // is derived from `val out0`, so this does not affect the name of mul
+ port.suggestName("foo")
+ // out0_mul
+ val mul = in0 * in1
+ port := mul + 1.U
+ port
+ }
+
+ val out1 = IO(Output(UInt()))
+ val out2 = IO(Output(UInt()))
+
+ out1 := {
+ // out1_sum
+ val sum = in0 + in1
+ sum + 1.U
+ }
+ // Comes after so does *not* affect prefix above
+ out1.suggestName("bar")
+
+ // Comes before so *does* affect prefix below
+ out2.suggestName("fizz")
+ out2 := {
+ // fizz_diff
+ val diff = in0 - in1
+ diff + 1.U
+ }
+}
+```
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new ConnectionPrefixExample)
+```
+
+As this example illustrates, this behavior is slightly inconsistent so is subject to change in a future version of Chisel.
+
+
+### Behavior for "Unnamed signals" (aka "Temporaries")
+
+If you want to signify that the name of a signal does not matter, you can prefix the name of your val with `_`.
+Chisel will preserve the convention of leading `_` signifying an unnamed signal across prefixes.
+For example:
+
+```scala mdoc
+class TemporaryExample extends Module {
+ val in0 = IO(Input(UInt(2.W)))
+ val in1 = IO(Input(UInt(2.W)))
+
+ val out = {
+ val port = IO(Output(UInt()))
+ val _sum = in0 + in1
+ port := _sum + 1.U
+ port
+ }
+}
+```
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new TemporaryExample)
+```
+
+If an unnamed signal is itself used to generate a prefix, the leading `_` will be ignored to avoid double `__` in the names of further nested signals.
+
+
+```scala mdoc
+class TemporaryPrefixExample extends Module {
+ val in0 = IO(Input(UInt(2.W)))
+ val in1 = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt()))
+
+ val _sum = {
+ val x = in0 + in1
+ x + 1.U
+ }
+ out := _sum & 0x2.U
+}
+```
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new TemporaryPrefixExample)
+```
+
+
### 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`
diff --git a/plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala b/plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala
index f98049e2..b3bbdbe4 100644
--- a/plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala
+++ b/plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala
@@ -181,8 +181,11 @@ class ChiselComponent(val global: Global, arguments: ChiselPluginArguments)
// If a Data or a Memory, get the name and a prefix
else if (shouldMatchNamedComp(tpe)) {
val str = stringFromTermName(name)
+ // Starting with '_' signifies a temporary, we ignore it for prefixing because we don't
+ // want double "__" in names when the user is just specifying a temporary
+ val prefix = if (str.head == '_') str.tail else str
val newRHS = transform(rhs)
- val prefixed = q"chisel3.experimental.prefix.apply[$tpt](name=$str)(f=$newRHS)"
+ val prefixed = q"chisel3.experimental.prefix.apply[$tpt](name=$prefix)(f=$newRHS)"
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
diff --git a/src/test/scala/chiselTests/naming/NamePluginSpec.scala b/src/test/scala/chiselTests/naming/NamePluginSpec.scala
index 482ef62b..a787bb80 100644
--- a/src/test/scala/chiselTests/naming/NamePluginSpec.scala
+++ b/src/test/scala/chiselTests/naming/NamePluginSpec.scala
@@ -340,4 +340,23 @@ class NamePluginSpec extends ChiselFlatSpec with Utils {
Select.wires(top).map(_.instanceName) should be(List("a_b_c", "a_b", "a"))
}
}
+
+ behavior.of("Unnamed values (aka \"Temporaries\")")
+
+ they should "be declared by starting the name with '_'" in {
+ class Test extends Module {
+ {
+ val a = {
+ val b = {
+ val _c = Wire(UInt(3.W))
+ 4.U // literal so there is no name
+ }
+ b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("_a_b_c"))
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/naming/PrefixSpec.scala b/src/test/scala/chiselTests/naming/PrefixSpec.scala
index 1e628391..6d52407e 100644
--- a/src/test/scala/chiselTests/naming/PrefixSpec.scala
+++ b/src/test/scala/chiselTests/naming/PrefixSpec.scala
@@ -233,18 +233,46 @@ class PrefixSpec extends ChiselPropSpec with Utils {
}
}
- property("Prefixing should be the prefix during the last call to autoName/suggestName") {
+ property("Prefixing should NOT be influenced by suggestName") {
class Test extends Module {
{
val wire = {
- val x = Wire(UInt(3.W)).suggestName("mywire")
- x
+ val x = Wire(UInt(3.W)) // wire_x
+ Wire(UInt(3.W)).suggestName("foo")
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("wire_x", "foo"))
+ }
+ }
+
+ property("Prefixing should be influenced by the \"current name\" of the signal") {
+ class Test extends Module {
+ {
+ val wire = {
+ val y = Wire(UInt(3.W)).suggestName("foo")
+ val x = Wire(UInt(3.W)) // wire_x
+ y
+ }
+
+ val wire2 = Wire(UInt(3.W))
+ wire2 := {
+ val x = Wire(UInt(3.W)) // wire2_x
+ x + 1.U
+ }
+ wire2.suggestName("bar")
+
+ val wire3 = Wire(UInt(3.W))
+ wire3.suggestName("fizz")
+ wire3 := {
+ val x = Wire(UInt(3.W)) // fizz_x
+ x + 1.U
}
}
}
aspectTest(() => new Test) { top: Test =>
- Select.wires(top).map(_.instanceName) should be(List("mywire"))
- Select.wires(top).map(_.instanceName) shouldNot be(List("wire_mywire"))
+ Select.wires(top).map(_.instanceName) should be(List("foo", "wire_x", "bar", "wire2_x", "fizz", "fizz_x"))
}
}
@@ -414,4 +442,59 @@ class PrefixSpec extends ChiselPropSpec with Utils {
(chirrtl should include).regex("assume.*: x5_x3")
(chirrtl should include).regex("printf.*: x5_x4")
}
+
+ property("Leading '_' in val names should be ignored in prefixes") {
+ class Test extends Module {
+ {
+ val a = {
+ val _b = {
+ val c = Wire(UInt(3.W))
+ 4.U // literal because there is no name
+ }
+ _b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a_b_c"))
+ }
+ }
+
+ // This checks that we don't just blanket ignore leading _ in prefixes
+ property("User-specified prefixes with '_' should be respected") {
+ class Test extends Module {
+ {
+ val a = {
+ val _b = prefix("_b") {
+ val c = Wire(UInt(3.W))
+ }
+ 4.U
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a__b_c"))
+ }
+ }
+
+ property("Leading '_' in signal names should be ignored in prefixes from connections") {
+ class Test extends Module {
+ {
+ val a = {
+ val b = {
+ val _c = IO(Output(UInt(3.W))) // port so not selected as wire
+ _c := {
+ val d = Wire(UInt(3.W))
+ d
+ }
+ 4.U // literal so there is no name
+ }
+ b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a_b_c_d"))
+ }
+ }
}