From 700f18c767c21c9ccf5510e1bdad6c5564d71210 Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Thu, 7 Oct 2021 10:14:12 -0700 Subject: [PATCH 1/8] Implement module prefixing API --- core/src/main/scala/chisel3/Module.scala | 21 +++++++++- .../main/scala/chisel3/internal/Builder.scala | 20 ++++++++++ .../scala/chisel3/stage/ChiselStage.scala | 18 +++++++++ src/test/scala/chiselTests/Module.scala | 39 +++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index 56dce4d592d..e7be101143f 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -88,6 +88,8 @@ object Module extends SourceInfoDoc { def reset: Reset = Builder.forcedReset /** Returns the current Module */ def currentModule: Option[BaseModule] = Builder.currentModule + /** Returns the current nested module prefix */ + def currentPrefix: String = Builder.getModulePrefix } /** Abstract base class for Modules, which behave much like Verilog modules. @@ -140,6 +142,21 @@ abstract class Module(implicit moduleCompileOptions: CompileOptions) extends Raw } } +object withModulePrefix { + /** Creates a new Module prefix scope + * + * @param prefix the prefix to add to all modules in the scope + * @param block the block of code to run with the new prefix + * @return the result of the block + */ + def apply[T](prefix: String)(block: => T): T = { + Builder.pushModulePrefix(prefix) + val res = block // execute block + Builder.popModulePrefix() + res + } + +} package experimental { @@ -449,10 +466,12 @@ package experimental { final lazy val name = try { // PseudoModules are not "true modules" and thus should share // their original modules names without uniquification - this match { + val unprefixed = this match { case _: PseudoModule => desiredName case _ => Builder.globalNamespace.name(desiredName) } + // Prefix this module name with the combined prefixes of the current chisel context + Module.currentPrefix + unprefixed } catch { case e: NullPointerException => throwException( s"Error: desiredName of ${this.getClass.getName} is null. Did you evaluate 'name' before all values needed by desiredName were available?", e) diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 0a0a3f2ddc6..356ae6c7b26 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -349,6 +349,9 @@ private[chisel3] class ChiselContext() { // Records the different prefixes which have been scoped at this point in time var prefixStack: Prefix = Nil + // Records the current nested module prefix + var modulePrefixStack: Prefix = Nil + // Views belong to a separate namespace (for renaming) // The namespace outside of Builder context is useless, but it ensures that views can still be created // and the resulting .toTarget is very clearly useless (_$$View$$_...) @@ -498,6 +501,23 @@ private[chisel3] object Builder extends LazyLogging { // Returns the prefix stack at this moment def getPrefix: Prefix = chiselContext.get().prefixStack + // Puts a module prefix string onto the module prefix stack + def pushModulePrefix(prefix: String): Unit = { + val context = chiselContext.get() + context.modulePrefixStack = prefix :: context.modulePrefixStack + } + + // Remove the module prefix on top of the stack + def popModulePrefix(): List[String] = { + val context = chiselContext.get() + val tail = context.modulePrefixStack.tail + context.modulePrefixStack = tail + tail + } + + // Returns the nested module prefix at this moment + def getModulePrefix: String = chiselContext.get().modulePrefixStack.foldLeft("")((a, b) => b + a) + def currentModule: Option[BaseModule] = dynamicContextVar.value match { case Some(dyanmicContext) => dynamicContext.currentModule case _ => None diff --git a/src/main/scala/chisel3/stage/ChiselStage.scala b/src/main/scala/chisel3/stage/ChiselStage.scala index 0c76f411e9f..21be034d962 100644 --- a/src/main/scala/chisel3/stage/ChiselStage.scala +++ b/src/main/scala/chisel3/stage/ChiselStage.scala @@ -23,6 +23,7 @@ import chisel3.internal.{firrtl => cir, ErrorLog} import chisel3.stage.CircuitSerializationAnnotation.FirrtlFileFormat import java.io.{StringWriter, PrintWriter} +import chisel3.Module class ChiselStage extends Stage { @@ -149,6 +150,23 @@ object ChiselStage { } .get } + + /** Elaborates a Chisel module into a circuit, but return that circuit in module form + * @param gen a call-by-name Chisel module + */ + def construct[T <: RawModule](gen: => T): T = { + val phase = new ChiselPhase { + override val targets = Seq( Dependency[chisel3.stage.phases.Checks], + Dependency[chisel3.stage.phases.Elaborate] ) + } + + phase + .transform(Seq(ChiselGeneratorAnnotation(() => gen), NoRunFirrtlCompilerAnnotation)) + .collectFirst { + case DesignAnnotation(a) => a.asInstanceOf[T] + } + .get + } /** Return a CHIRRTL circuit for a Chisel module * @param gen a call-by-name Chisel module diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala index 7703e8765ed..cfabc317fc9 100644 --- a/src/test/scala/chiselTests/Module.scala +++ b/src/test/scala/chiselTests/Module.scala @@ -200,4 +200,43 @@ class ModuleSpec extends ChiselPropSpec with Utils { val s = Source.fromFile("generated/PlusOne.v").mkString("") assert(s.contains("assign io_out = io_in + 32'h1")) } + + property("withModulePrefix should prefix modules within it") { + val m = ChiselStage.construct(new Module { + val io = IO(new Bundle { }) + val child = withModulePrefix("Foo") { + Module(new chisel3.Module { + Module.currentPrefix should be ("Foo") + + val io = IO(new Bundle { }) + override val desiredName = "Module" + }) + } + }) + + m.child.name should be ("FooModule") + } + + property("withModulePrefix should support nested module prefixing") { + val m = ChiselStage.construct(new Module { + val io = IO(new Bundle { }) + val child = withModulePrefix("Foo") { + Module(new chisel3.Module { + Module.currentPrefix should be ("Foo") + + val io = IO(new Bundle { }) + val nestedChild = withModulePrefix("Bar") { + Module(new chisel3.Module { + Module.currentPrefix should be ("FooBar") + + val io = IO(new Bundle { }) + override val desiredName = "Module" + }) + } + }) + } + }) + + m.child.nestedChild.name should be ("FooBarModule") + } } From b5180f02b22db870323fa73f89de9c5d17295ae8 Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Mon, 11 Oct 2021 15:21:34 -0700 Subject: [PATCH 2/8] Scala doc for withModulePrefix object --- core/src/main/scala/chisel3/Module.scala | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index e7be101143f..fe83e892f6e 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -142,6 +142,37 @@ abstract class Module(implicit moduleCompileOptions: CompileOptions) extends Raw } } +/** Creates a new module prefix scope that prefixes all instantiated modules + * + * @example {{{ + * val m = Module(new Module { + * val child = withModulePrefix("Foo") { + * Module(new Module { + * override val desiredName = "Module" + * }) + * } + * }) + * + * // m.child.name will be equal to "FooModule" + * }}} + * + * Module prefixes can be nested within each other, like so: + * @example {{{ + * val m = ChiselStage.construct(new Module { + * val child = withModulePrefix("Foo") { + * Module(new chisel3.Module { + * val nestedChild = withModulePrefix("Bar") { + * Module(new chisel3.Module { + * override val desiredName = "Module" + * }) + * } + * }) + * } + * }) + * + * // m.child.nestedChild.name will be equal to "FooBarModule" + * }}} + */ object withModulePrefix { /** Creates a new Module prefix scope * From 374aafbe13c0738a109ef5bebcc902391d3560fa Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Mon, 11 Oct 2021 15:29:41 -0700 Subject: [PATCH 3/8] Remove ChiselStages.construct --- src/main/scala/chisel3/stage/ChiselStage.scala | 18 ------------------ src/test/scala/chiselTests/Module.scala | 8 ++------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/src/main/scala/chisel3/stage/ChiselStage.scala b/src/main/scala/chisel3/stage/ChiselStage.scala index 21be034d962..0c76f411e9f 100644 --- a/src/main/scala/chisel3/stage/ChiselStage.scala +++ b/src/main/scala/chisel3/stage/ChiselStage.scala @@ -23,7 +23,6 @@ import chisel3.internal.{firrtl => cir, ErrorLog} import chisel3.stage.CircuitSerializationAnnotation.FirrtlFileFormat import java.io.{StringWriter, PrintWriter} -import chisel3.Module class ChiselStage extends Stage { @@ -150,23 +149,6 @@ object ChiselStage { } .get } - - /** Elaborates a Chisel module into a circuit, but return that circuit in module form - * @param gen a call-by-name Chisel module - */ - def construct[T <: RawModule](gen: => T): T = { - val phase = new ChiselPhase { - override val targets = Seq( Dependency[chisel3.stage.phases.Checks], - Dependency[chisel3.stage.phases.Elaborate] ) - } - - phase - .transform(Seq(ChiselGeneratorAnnotation(() => gen), NoRunFirrtlCompilerAnnotation)) - .collectFirst { - case DesignAnnotation(a) => a.asInstanceOf[T] - } - .get - } /** Return a CHIRRTL circuit for a Chisel module * @param gen a call-by-name Chisel module diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala index cfabc317fc9..b077ccc62a3 100644 --- a/src/test/scala/chiselTests/Module.scala +++ b/src/test/scala/chiselTests/Module.scala @@ -202,13 +202,11 @@ class ModuleSpec extends ChiselPropSpec with Utils { } property("withModulePrefix should prefix modules within it") { - val m = ChiselStage.construct(new Module { - val io = IO(new Bundle { }) + val m = elaborateAndGetModule(new Module { val child = withModulePrefix("Foo") { Module(new chisel3.Module { Module.currentPrefix should be ("Foo") - val io = IO(new Bundle { }) override val desiredName = "Module" }) } @@ -218,18 +216,16 @@ class ModuleSpec extends ChiselPropSpec with Utils { } property("withModulePrefix should support nested module prefixing") { - val m = ChiselStage.construct(new Module { + val m = elaborateAndGetModule(new Module { val io = IO(new Bundle { }) val child = withModulePrefix("Foo") { Module(new chisel3.Module { Module.currentPrefix should be ("Foo") - val io = IO(new Bundle { }) val nestedChild = withModulePrefix("Bar") { Module(new chisel3.Module { Module.currentPrefix should be ("FooBar") - val io = IO(new Bundle { }) override val desiredName = "Module" }) } From bad9f004478cb56cad9c42ac70f1c738cebdca7a Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Mon, 11 Oct 2021 15:33:04 -0700 Subject: [PATCH 4/8] Rename 'currentModulePrefix' to 'Module.currentModulePrefix' --- core/src/main/scala/chisel3/Module.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index fe83e892f6e..b6429c91b6e 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -89,7 +89,7 @@ object Module extends SourceInfoDoc { /** Returns the current Module */ def currentModule: Option[BaseModule] = Builder.currentModule /** Returns the current nested module prefix */ - def currentPrefix: String = Builder.getModulePrefix + def currentModulePrefix: String = Builder.getModulePrefix } /** Abstract base class for Modules, which behave much like Verilog modules. @@ -502,7 +502,7 @@ package experimental { case _ => Builder.globalNamespace.name(desiredName) } // Prefix this module name with the combined prefixes of the current chisel context - Module.currentPrefix + unprefixed + Module.currentModulePrefix + unprefixed } catch { case e: NullPointerException => throwException( s"Error: desiredName of ${this.getClass.getName} is null. Did you evaluate 'name' before all values needed by desiredName were available?", e) From 6a22f97616aff2e2c467be0d5169f54a87ba95eb Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Mon, 11 Oct 2021 15:38:50 -0700 Subject: [PATCH 5/8] Add empty prefix test --- src/test/scala/chiselTests/Module.scala | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala index b077ccc62a3..67569984261 100644 --- a/src/test/scala/chiselTests/Module.scala +++ b/src/test/scala/chiselTests/Module.scala @@ -217,7 +217,6 @@ class ModuleSpec extends ChiselPropSpec with Utils { property("withModulePrefix should support nested module prefixing") { val m = elaborateAndGetModule(new Module { - val io = IO(new Bundle { }) val child = withModulePrefix("Foo") { Module(new chisel3.Module { Module.currentPrefix should be ("Foo") @@ -235,4 +234,17 @@ class ModuleSpec extends ChiselPropSpec with Utils { m.child.nestedChild.name should be ("FooBarModule") } + + property("withModulePrefix should not prefix if given an empty argument") { + val m = elaborateAndGetModule(new Module { + val child = withModulePrefix("") { + Module(new chisel3.Module { + Module.currentPrefix should be ("") + override val desiredName = "NoPrefixModule" + }) + } + }) + + m.child.name should be ("NoPrefixModule") + } } From 86eb496571427fc413dc7260cda3a80bedffb3e9 Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Mon, 11 Oct 2021 16:08:37 -0700 Subject: [PATCH 6/8] Fix compilation errors --- src/test/scala/chiselTests/Module.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala index 67569984261..ce2aeab1f04 100644 --- a/src/test/scala/chiselTests/Module.scala +++ b/src/test/scala/chiselTests/Module.scala @@ -205,7 +205,7 @@ class ModuleSpec extends ChiselPropSpec with Utils { val m = elaborateAndGetModule(new Module { val child = withModulePrefix("Foo") { Module(new chisel3.Module { - Module.currentPrefix should be ("Foo") + Module.currentModulePrefix should be ("Foo") override val desiredName = "Module" }) @@ -219,11 +219,11 @@ class ModuleSpec extends ChiselPropSpec with Utils { val m = elaborateAndGetModule(new Module { val child = withModulePrefix("Foo") { Module(new chisel3.Module { - Module.currentPrefix should be ("Foo") + Module.currentModulePrefix should be ("Foo") val nestedChild = withModulePrefix("Bar") { Module(new chisel3.Module { - Module.currentPrefix should be ("FooBar") + Module.currentModulePrefix should be ("FooBar") override val desiredName = "Module" }) @@ -239,7 +239,7 @@ class ModuleSpec extends ChiselPropSpec with Utils { val m = elaborateAndGetModule(new Module { val child = withModulePrefix("") { Module(new chisel3.Module { - Module.currentPrefix should be ("") + Module.currentModulePrefix should be ("") override val desiredName = "NoPrefixModule" }) } From 4a0fb281b0fcb70474ebfb7984eeba1030c2a7d0 Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Wed, 13 Oct 2021 18:07:52 -0700 Subject: [PATCH 7/8] Add negative blackbox prefixing tests --- core/src/main/scala/chisel3/Module.scala | 9 +++---- src/test/scala/chiselTests/Module.scala | 34 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index b6429c91b6e..d7aa352ac28 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -497,12 +497,11 @@ package experimental { final lazy val name = try { // PseudoModules are not "true modules" and thus should share // their original modules names without uniquification - val unprefixed = this match { - case _: PseudoModule => desiredName - case _ => Builder.globalNamespace.name(desiredName) + this match { + case _: BlackBox => desiredName + case _: PseudoModule => Module.currentModulePrefix + desiredName + case _ => Module.currentModulePrefix + Builder.globalNamespace.name(desiredName) } - // Prefix this module name with the combined prefixes of the current chisel context - Module.currentModulePrefix + unprefixed } catch { case e: NullPointerException => throwException( s"Error: desiredName of ${this.getClass.getName} is null. Did you evaluate 'name' before all values needed by desiredName were available?", e) diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala index ce2aeab1f04..358ccae78a1 100644 --- a/src/test/scala/chiselTests/Module.scala +++ b/src/test/scala/chiselTests/Module.scala @@ -5,6 +5,7 @@ package chiselTests import chisel3._ import chisel3.experimental.DataMirror import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage, NoRunFirrtlCompilerAnnotation} +import chisel3.util.HasBlackBoxInline import firrtl.annotations.NoTargetAnnotation import firrtl.options.Unserializable @@ -247,4 +248,37 @@ class ModuleSpec extends ChiselPropSpec with Utils { m.child.name should be ("NoPrefixModule") } + + property("withModulePrefix should not prefix blackboxes") { + val m = elaborateAndGetModule(new Module { + val bb = withModulePrefix("Foo") { + Module(new BlackBox { + val io = IO(new Bundle { }) + override val desiredName = "BlackBox" + }) + } + }) + + m.bb.name should be ("BlackBox") + } + + property("withModulePrefix should not prefix inlined blackboxes") { + val m = elaborateAndGetModule(new Module { + val bb = withModulePrefix("Foo") { + Module(new BlackBox with HasBlackBoxInline { + val io = IO(new Bundle { }) + override val desiredName = "InlineBlackBox" + + setInline("InlineBlackBox.v", + s""" + |module InlineBlackBox (); + | + |endmodule + """.stripMargin) + }) + } + }) + + m.bb.name should be ("InlineBlackBox") + } } From f8f335f16de76e75022eb51dc21417373156d436 Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Thu, 14 Oct 2021 10:18:12 -0700 Subject: [PATCH 8/8] Fix blackbox name resolution in namespace --- core/src/main/scala/chisel3/Module.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index d7aa352ac28..bdcbc7f0d86 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -498,8 +498,8 @@ package experimental { // PseudoModules are not "true modules" and thus should share // their original modules names without uniquification this match { - case _: BlackBox => desiredName case _: PseudoModule => Module.currentModulePrefix + desiredName + case _: BlackBox => Builder.globalNamespace.name(desiredName) case _ => Module.currentModulePrefix + Builder.globalNamespace.name(desiredName) } } catch {