Skip to content

Commit 9c2498a

Browse files
authored
Add module prefixing to BaseModule definitions (#4509)
* BaseModule.localModulePrefix can be used to set a prefix for the module and its children. * BaseModule.localPrefixAppliesToSelf (defaults to true) allows the module to exclude itself from the prefix. * localModulePrefix composes with prefixes added via withModulePrefix.
1 parent 4fa08f8 commit 9c2498a

File tree

4 files changed

+168
-13
lines changed

4 files changed

+168
-13
lines changed

core/src/main/scala/chisel3/ModuleImpl.scala

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ private[chisel3] trait ObjectModuleImpl {
123123
Builder.currentReset = saveReset
124124
Builder.setPrefix(savePrefix)
125125
Builder.enabledLayers = saveEnabledLayers
126+
if (module.localModulePrefix.isDefined) {
127+
Builder.popModulePrefix() // Pop localModulePrefix if it was defined
128+
}
126129

127130
module.moduleBuilt()
128131
module
@@ -696,7 +699,7 @@ package experimental {
696699
this match {
697700
case _: PseudoModule => Module.currentModulePrefix + desiredName
698701
case _: BaseBlackBox => Builder.globalNamespace.name(desiredName)
699-
case _ => Builder.globalNamespace.name(Module.currentModulePrefix + desiredName)
702+
case _ => Builder.globalNamespace.name(this.modulePrefix + desiredName)
700703
}
701704
} catch {
702705
case e: NullPointerException =>
@@ -933,8 +936,29 @@ package experimental {
933936
case Some(c) => getRef.fullName(c)
934937
}
935938

936-
/** Returns the current nested module prefix */
937-
val modulePrefix: String = Builder.getModulePrefix
939+
/** Additional module prefix, applies to this module if defined (unless localModulePrefix is false) and all children.
940+
*/
941+
def localModulePrefix: Option[String] = None
942+
943+
/** Should [[localModulePrefix]] apply to this module? Defaults to true.
944+
*
945+
* Users should override to false if [[localModulePrefix]] should apply only to children.
946+
*/
947+
def localPrefixAppliesToSelf: Boolean = true
948+
949+
/** The resolved module prefix used for this Module.
950+
*
951+
* Includes [[localModulePrefix]] if defined and if [[localPrefixAppliesToSelf]] is true.
952+
*/
953+
final val modulePrefix: String =
954+
withModulePrefix(localModulePrefix.filter(_ => localPrefixAppliesToSelf).getOrElse("")) {
955+
Builder.getModulePrefix
956+
}
957+
958+
// Apply localModulePrefix to children.
959+
localModulePrefix.foreach { prefix =>
960+
Builder.pushModulePrefix(prefix)
961+
}
938962
}
939963
}
940964

docs/src/explanations/moduleprefix.md

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Module prefixing allows you to create namespaces in the Verilog output of your d
55
They are especially useful for when you want to name a particular subsystem of your design,
66
and you want to make it easy to identify which subsystem a file belongs to by its name.
77

8+
## withModulePrefix
9+
810
We can open a module prefix block using `withModulePrefix`:
911

1012
```scala mdoc:silent
@@ -41,6 +43,46 @@ The result will be a design with two module definitions: `Top` and `Foo_Sub`.
4143
Note that the `val sub =` part must be pulled outside of the `withModulePrefix` block,
4244
or else the module will not be accessible to the rest of the `Top` module.
4345

46+
## localModulePrefix
47+
48+
We can also set a module prefix on a module by overriding the `localModulePrefix` method.
49+
This is useful if you want to set a prefix for all instances of a module.
50+
51+
```scala mdoc:silent:reset
52+
import chisel3._
53+
54+
class Top extends Module {
55+
override def localModulePrefix = Some("Foo")
56+
val sub = Module(new Sub)
57+
}
58+
59+
class Sub extends Module {
60+
// ..
61+
}
62+
```
63+
64+
This results in two module definitions: `Foo_Top` and `Foo_Sub`.
65+
66+
You can also override `localPrefixAppliesToSelf` to `false` to only apply the prefix to the children.
67+
68+
```scala mdoc:silent:reset
69+
import chisel3._
70+
71+
class Top extends Module {
72+
override def localModulePrefix = Some("Foo")
73+
override def localPrefixAppliesToSelf = false
74+
val sub = Module(new Sub)
75+
}
76+
77+
class Sub extends Module {
78+
// ..
79+
}
80+
```
81+
82+
This results in the two module definitions `Top` and `Foo_Sub`.
83+
84+
## Multiple Prefixes
85+
4486
If a generator is run in multiple prefix blocks, the result is multiple identical copies of the module definition,
4587
each with its own distinct prefix.
4688
For example, consider if we create two instances of `Sub` above like this:
@@ -66,6 +108,8 @@ class Sub extends Module {
66108
Then, the resulting Verilog will have three module definitions: `Top`, `Foo_Sub`, and `Bar_Sub`.
67109
Both `Foo_Sub` and `Bar_Sub` will be identical to each other.
68110

111+
## Nested Prefixes
112+
69113
Module prefixes can also be nested.
70114

71115
```scala mdoc:silent:reset
@@ -78,9 +122,10 @@ class Top extends Module {
78122
}
79123

80124
class Mid extends Module {
81-
val sub = withModulePrefix("Bar") {
82-
Module(new Sub)
83-
}
125+
// You can mix withModulePrefix and localModulePrefix.
126+
override def localModulePrefix = Some("Bar")
127+
override def localPrefixAppliesToSelf = false
128+
val sub = Module(new Sub)
84129
}
85130

86131
class Sub extends Module {
@@ -90,6 +135,8 @@ class Sub extends Module {
90135

91136
This results in three module definitions: `Top`, `Foo_Mid`, and `Foo_Bar_Sub`.
92137

138+
## Instantiate
139+
93140
The `withModulePrefix` blocks also work with the `Instantiate` API.
94141

95142
```scala mdoc:silent:reset
@@ -119,6 +166,8 @@ In this example, we end up with four modules: `Top`, `Foo_Sub`, `Bar_Sub`, and `
119166
When using `Definition` and `Instance`, all `Definition` calls will be affected by `withModulePrefix`.
120167
However, `Instance` will not be effected, since it always creates an instance of the captured definition.
121168

169+
## External Modules
170+
122171
`BlackBox` and `ExtModule` are unaffected by `withModulePrefix`.
123172
If you wish to have one that is sensitive to the module prefix,
124173
you can explicitly name the module like this:

src/test/scala/chiselTests/ChiselSpec.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ trait Utils {
365365
}
366366

367367
/** Contains helpful function to assert both statements to match, and statements to omit */
368-
trait MatchesAndOmits {
368+
trait MatchesAndOmits extends Assertions {
369369
private def matches(lines: List[String], matchh: String): Option[String] = lines.filter(_.contains(matchh)).lastOption
370370
private def omits(line: String, omit: String): Option[(String, String)] =
371371
if (line.contains(omit)) Some((omit, line)) else None
@@ -374,11 +374,11 @@ trait MatchesAndOmits {
374374
val lines = output.split("\n").toList
375375
val unmatched = matchList.flatMap { m =>
376376
if (matches(lines, m).nonEmpty) None else Some(m)
377-
}.map(x => s" > $x was unmatched")
377+
}.map(x => s" > '$x' was unmatched")
378378
val unomitted = omitList.flatMap { o => omits(lines, o) }.map {
379-
case (o, l) => s" > $o was not omitted in ($l)"
379+
case (o, l) => s" > '$o' was not omitted in ($l)"
380380
}
381381
val results = unmatched ++ unomitted
382-
assert(results.isEmpty, results.mkString("\n"))
382+
assert(results.isEmpty, results.mkString("\n") + s"\nFull Input:\n'$output'\n")
383383
}
384384
}

src/test/scala/chiselTests/PrefixSpec.scala renamed to src/test/scala/chiselTests/ModulePrefixSpec.scala

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import circt.stage.ChiselStage.emitCHIRRTL
99
import circt.stage.ChiselStage
1010
import chisel3.util.SRAM
1111

12-
object PrefixSpec {
12+
object ModulePrefixSpec {
1313
// This has to be defined at the top-level because @instantiable doesn't work when nested.
1414
@instantiable
1515
class AddOne(width: Int) extends Module {
@@ -19,8 +19,8 @@ object PrefixSpec {
1919
}
2020
}
2121

22-
class PrefixSpec extends ChiselFlatSpec with ChiselRunners with Utils with MatchesAndOmits {
23-
import PrefixSpec._
22+
class ModulePrefixSpec extends ChiselFlatSpec with ChiselRunners with Utils with MatchesAndOmits {
23+
import ModulePrefixSpec._
2424
behavior.of("withModulePrefix")
2525

2626
it should "prefix modules in a withModulePrefix block, but not outside" in {
@@ -275,4 +275,86 @@ class PrefixSpec extends ChiselFlatSpec with ChiselRunners with Utils with Match
275275

276276
matchesAndOmits(chirrtl)(lines: _*)()
277277
}
278+
279+
behavior.of("BaseModule.localModulePrefix")
280+
281+
it should "set the prefix for a Module and its children" in {
282+
283+
class Foo extends RawModule
284+
class Bar extends RawModule
285+
286+
class Top extends RawModule {
287+
override def localModulePrefix = Some("Prefix")
288+
val foo = Module(new Foo)
289+
val bar = Module(new Bar)
290+
}
291+
292+
val chirrtl = emitCHIRRTL(new Top)
293+
val lines =
294+
"""
295+
module Prefix_Foo :
296+
module Prefix_Bar :
297+
module Prefix_Top :
298+
inst foo of Prefix_Foo
299+
inst bar of Prefix_Bar
300+
""".linesIterator.map(_.trim).toSeq
301+
302+
matchesAndOmits(chirrtl)(lines: _*)()
303+
}
304+
305+
it should "set the prefix for a Module's children but not the Module itself if localPrefixAppliesToSelf is false" in {
306+
307+
class Foo extends RawModule
308+
class Bar extends RawModule
309+
310+
class Top extends RawModule {
311+
override def localModulePrefix = Some("Prefix")
312+
override def localPrefixAppliesToSelf = false
313+
val foo = Module(new Foo)
314+
val bar = Module(new Bar)
315+
}
316+
317+
val chirrtl = emitCHIRRTL(new Top)
318+
val lines =
319+
"""
320+
module Prefix_Foo :
321+
module Prefix_Bar :
322+
module Top :
323+
inst foo of Prefix_Foo
324+
inst bar of Prefix_Bar
325+
""".linesIterator.map(_.trim).toSeq
326+
327+
matchesAndOmits(chirrtl)(lines: _*)()
328+
}
329+
330+
it should "compose with withModulePrefix" in {
331+
332+
class Foo extends RawModule {
333+
override def localModulePrefix = Some("Inner")
334+
}
335+
class Bar extends RawModule
336+
337+
class Top extends RawModule {
338+
override def localModulePrefix = Some("Outer")
339+
val f1 = Module(new Foo)
340+
withModulePrefix("Prefix") {
341+
val f2 = Module(new Foo)
342+
val bar = Module(new Bar)
343+
}
344+
}
345+
346+
val chirrtl = emitCHIRRTL(new Top)
347+
val lines =
348+
"""
349+
module Outer_Inner_Foo :
350+
module Outer_Prefix_Inner_Foo :
351+
module Outer_Prefix_Bar :
352+
module Outer_Top :
353+
inst f1 of Outer_Inner_Foo
354+
inst f2 of Outer_Prefix_Inner_Foo
355+
inst bar of Outer_Prefix_Bar
356+
""".linesIterator.map(_.trim).toSeq
357+
358+
matchesAndOmits(chirrtl)(lines: _*)()
359+
}
278360
}

0 commit comments

Comments
 (0)