summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala5
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Module.scala5
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Builder.scala14
-rw-r--r--src/test/scala/chiselTests/DedupSpec.scala57
4 files changed, 71 insertions, 10 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index 732bf8fc..efb30326 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -374,7 +374,10 @@ abstract class Record extends Aggregate {
// NOTE: This sets up dependent references, it can be done before closing the Module
private[chisel3] override def _onModuleClose: Unit = { // scalastyle:ignore method.name
- val _namespace = Builder.globalNamespace.child
+ // Since Bundle names this via reflection, it is impossible for two elements to have the same
+ // identifier; however, Namespace sanitizes identifiers to make them legal for Firrtl/Verilog
+ // which can cause collisions
+ val _namespace = Namespace.empty
for ((name, elt) <- elements) { elt.setRef(this, _namespace.name(name)) }
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
index ca7c8abd..de13c078 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
@@ -113,7 +113,8 @@ extends HasId {
Port(iodef)
}
- private[core] val _namespace = Builder.globalNamespace.child
+ // Fresh Namespace because in Firrtl, Modules namespaces are disjoint with the global namespace
+ private[core] val _namespace = Namespace.empty
private[chisel3] val _commands = ArrayBuffer[Command]()
private[core] val _ids = ArrayBuffer[HasId]()
Builder.currentModule = Some(this)
@@ -210,7 +211,7 @@ extends HasId {
// For Module instances we haven't named, suggest the name of the Module
_ids foreach {
- case m: Module => m.suggestName(m.name)
+ case m: Module => m.suggestName(m.desiredName)
case _ =>
}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
index 5d841941..d8202da6 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
@@ -9,7 +9,7 @@ import chisel3._
import core._
import firrtl._
-private[chisel3] class Namespace(parent: Option[Namespace], keywords: Set[String]) {
+private[chisel3] class Namespace(keywords: Set[String]) {
private val names = collection.mutable.HashMap[String, Long]()
for (keyword <- keywords)
names(keyword) = 1
@@ -29,9 +29,7 @@ private[chisel3] class Namespace(parent: Option[Namespace], keywords: Set[String
if (res.isEmpty || !legalStart(res.head)) s"_$res" else res
}
- def contains(elem: String): Boolean = {
- names.contains(elem) || parent.map(_ contains elem).getOrElse(false)
- }
+ def contains(elem: String): Boolean = names.contains(elem)
def name(elem: String): String = {
val sanitized = sanitize(elem)
@@ -42,9 +40,11 @@ private[chisel3] class Namespace(parent: Option[Namespace], keywords: Set[String
sanitized
}
}
+}
- def child(kws: Set[String]): Namespace = new Namespace(Some(this), kws)
- def child: Namespace = child(Set())
+private[chisel3] object Namespace {
+ /** Constructs an empty Namespace */
+ def empty: Namespace = new Namespace(Set.empty[String])
}
private[chisel3] class IdGen {
@@ -143,7 +143,7 @@ private[chisel3] trait HasId extends InstanceId {
private[chisel3] class DynamicContext() {
val idGen = new IdGen
- val globalNamespace = new Namespace(None, Set())
+ val globalNamespace = Namespace.empty
val components = ArrayBuffer[Component]()
val annotations = ArrayBuffer[ChiselAnnotation]()
var currentModule: Option[Module] = None
diff --git a/src/test/scala/chiselTests/DedupSpec.scala b/src/test/scala/chiselTests/DedupSpec.scala
new file mode 100644
index 00000000..b8fe075e
--- /dev/null
+++ b/src/test/scala/chiselTests/DedupSpec.scala
@@ -0,0 +1,57 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import chisel3._
+import chisel3.util._
+
+class DedupIO extends Bundle {
+ val in = Flipped(Decoupled(UInt(32.W)))
+ val out = Decoupled(UInt(32.W))
+}
+
+class DedupQueues(n: Int) extends Module {
+ require(n > 0)
+ val io = IO(new DedupIO)
+ val queues = Seq.fill(n)(Module(new Queue(UInt(32.W), 4)))
+ var port = io.in
+ for (q <- queues) {
+ q.io.enq <> port
+ port = q.io.deq
+ }
+ io.out <> port
+}
+
+/* This module creates a Queue in a nested function (such that it is not named via reflection). The
+ * default naming for instances prior to #470 caused otherwise identical instantiations of this
+ * module to have different instance names for the queues which prevented deduplication.
+ * NestedDedup instantiates this module twice to ensure it is deduplicated properly.
+ */
+class DedupSubModule extends Module {
+ val io = IO(new DedupIO)
+ io.out <> Queue(io.in, 4)
+}
+
+class NestedDedup extends Module {
+ val io = IO(new DedupIO)
+ val inst0 = Module(new DedupSubModule)
+ val inst1 = Module(new DedupSubModule)
+ inst0.io.in <> io.in
+ inst1.io.in <> inst0.io.out
+ io.out <> inst1.io.out
+}
+
+class DedupSpec extends ChiselFlatSpec {
+ private val ModuleRegex = """\s*module\s+(\w+)\b.*""".r
+ def countModules(verilog: String): Int =
+ (verilog split "\n" collect { case ModuleRegex(name) => name }).size
+
+ "Deduplication" should "occur" in {
+ assert(countModules(compile { new DedupQueues(4) }) === 2)
+ }
+
+ it should "properly dedup modules with deduped submodules" in {
+ assert(countModules(compile { new NestedDedup }) === 3)
+ }
+}
+