summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack2017-01-30 22:42:57 -0800
committerJack Koenig2017-01-31 11:30:28 -0800
commit3ef63639284b2b56f415e1540c58d85d88c360db (patch)
tree5ab5802bcd1ec2a86ef23a67b6d1249488425deb
parentf8408623e13149ccd4bfae443d916eeb9c5a2146 (diff)
Make Module and Bundle properly use empty namespaces
Fix default suggested name of Module instances (now based on desired name rather than actual assigned name). Remove parent/child relationship from Namespace. Previously, Module and Bundle namespaces were "children" of the Module definition namespace. This could lead to collisions that would give unexpected names for module instances or Bundle elements. In particular, otherwise identical modules that instantiate other identical modules in such a way that the instance cannot be named via reflection would not be deduplicated because the names of the instances would collide with the names of the modules in the Builder.globalNamespace.
-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)
+ }
+}
+