Skip to content

Commit 68d0b6d

Browse files
Add command line options to control elaboration of inline tests (#4826)
1 parent 4cc4ab8 commit 68d0b6d

File tree

10 files changed

+262
-29
lines changed

10 files changed

+262
-29
lines changed

core/src/main/scala/chisel3/experimental/hierarchy/core/Definition.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ object Definition extends SourceInfoDoc {
120120
context.loggerOptions,
121121
context.definitions,
122122
context.contextCache,
123-
context.layerMap
123+
context.layerMap,
124+
context.inlineTestIncluder
124125
)
125126
}
126127
dynamicContext.inDefinition = true

core/src/main/scala/chisel3/internal/Builder.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -472,10 +472,11 @@ private[chisel3] class DynamicContext(
472472
val sourceRoots: Seq[File],
473473
val defaultNamespace: Option[Namespace],
474474
// Definitions from other scopes in the same elaboration, use allDefinitions below
475-
val loggerOptions: LoggerOptions,
476-
val definitions: ArrayBuffer[Definition[_]],
477-
val contextCache: BuilderContextCache,
478-
val layerMap: Map[layer.Layer, layer.Layer]
475+
val loggerOptions: LoggerOptions,
476+
val definitions: ArrayBuffer[Definition[_]],
477+
val contextCache: BuilderContextCache,
478+
val layerMap: Map[layer.Layer, layer.Layer],
479+
val inlineTestIncluder: InlineTestIncluder
479480
) {
480481
val importedDefinitionAnnos = annotationSeq.collect { case a: ImportDefinitionAnnotation[_] => a }
481482

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chisel3.internal
4+
5+
import java.nio.file.{FileSystems, PathMatcher, Paths}
6+
7+
class InlineTestIncluder private (includeModuleGlobs: Seq[String], includeTestNameGlobs: Seq[String]) {
8+
private def copy(
9+
includeModuleGlobs: Seq[String] = this.includeModuleGlobs,
10+
includeTestNameGlobs: Seq[String] = this.includeTestNameGlobs
11+
) = new InlineTestIncluder(includeModuleGlobs, includeTestNameGlobs)
12+
13+
def includeModule(glob: String) = copy(includeModuleGlobs = includeModuleGlobs ++ Seq(glob))
14+
def includeTest(glob: String) = copy(includeTestNameGlobs = includeTestNameGlobs ++ Seq(glob))
15+
16+
private val filesystem = FileSystems.getDefault()
17+
18+
private def matchesGlob(glob: String, path: String): Boolean = {
19+
val matcher = filesystem.getPathMatcher(s"glob:$glob")
20+
matcher.matches(Paths.get(path))
21+
}
22+
23+
def shouldElaborateTest(moduleDesiredName: String, testName: String): Boolean = {
24+
val (resolvedModuleGlobs, resolvedTestNameGlobs) = (includeModuleGlobs, includeTestNameGlobs) match {
25+
case x @ (Seq(), Seq()) => x
26+
// If only one type of glob is provided, default to "*" for the other.
27+
case (Seq(), ts) => (Seq("*"), ts)
28+
case (ms, Seq()) => (ms, Seq("*"))
29+
case x => x
30+
}
31+
32+
resolvedModuleGlobs.exists { glob => matchesGlob(glob, moduleDesiredName) } &&
33+
resolvedTestNameGlobs.exists { glob => matchesGlob(glob, testName) }
34+
}
35+
}
36+
37+
object InlineTestIncluder {
38+
39+
/** Create an InlineTestIncluder that does not include any tests */
40+
def none: InlineTestIncluder = new InlineTestIncluder(Nil, Nil)
41+
42+
/** Create an InlineTestIncluder that includes all tests */
43+
def all: InlineTestIncluder = new InlineTestIncluder(Seq("*"), Seq("*"))
44+
45+
/** Create an InlineTestIncluder with module and test name globs */
46+
def apply(
47+
includeModuleGlobs: Seq[String],
48+
includeTestNameGlobs: Seq[String]
49+
): InlineTestIncluder = new InlineTestIncluder(includeModuleGlobs, includeModuleGlobs)
50+
}

src/main/scala/chisel3/experimental/inlinetest/InlineTest.scala

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ object TestHarnessGenerator {
9696
trait HasTests { module: RawModule =>
9797
type M = module.type
9898

99+
/** Whether inline tests will be elaborated as a top-level definition to the circuit. */
100+
protected def elaborateTests: Boolean = true
101+
102+
private val inlineTestIncluder = internal.Builder.captureContext().inlineTestIncluder
103+
104+
private def shouldElaborateTest(testName: String) =
105+
inlineTestIncluder.shouldElaborateTest(module.desiredName, testName)
106+
99107
/** A Definition of the DUT to be used for each of the tests. */
100108
private lazy val moduleDefinition =
101109
module.toDefinition.asInstanceOf[Definition[module.type]]
@@ -116,12 +124,14 @@ trait HasTests { module: RawModule =>
116124
protected final def test[R](
117125
testName: String
118126
)(testBody: Instance[M] => R)(implicit th: TestHarnessGenerator[M, R]): Unit =
119-
elaborateParentModule { moduleDefinition =>
120-
val resetType = module match {
121-
case module: Module => Some(module.resetType)
122-
case _ => None
127+
if (elaborateTests && shouldElaborateTest(testName)) {
128+
elaborateParentModule { moduleDefinition =>
129+
val resetType = module match {
130+
case module: Module => Some(module.resetType)
131+
case _ => None
132+
}
133+
val test = new TestParameters[M, R](desiredName, testName, moduleDefinition, testBody, resetType)
134+
th.generate(test)
123135
}
124-
val test = new TestParameters[M, R](desiredName, testName, moduleDefinition, testBody, resetType)
125-
th.generate(test)
126136
}
127137
}

src/main/scala/chisel3/stage/ChiselAnnotations.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,3 +582,33 @@ case object UseSRAMBlackbox extends NoTargetAnnotation with ChiselOption with Ha
582582
)
583583
)
584584
}
585+
586+
case class IncludeInlineTestsForModuleAnnotation(glob: String)
587+
extends NoTargetAnnotation
588+
with Unserializable
589+
with ChiselOption
590+
591+
case object IncludeInlineTestsForModule extends HasShellOptions {
592+
val options = Seq(
593+
new ShellOption[String](
594+
longOption = "include-tests-module",
595+
toAnnotationSeq = glob => Seq(IncludeInlineTestsForModuleAnnotation(glob)),
596+
helpText = "Elaborate inline tests when the module-under-test name matches this glob"
597+
)
598+
)
599+
}
600+
601+
case class IncludeInlineTestsWithNameAnnotation(glob: String)
602+
extends NoTargetAnnotation
603+
with Unserializable
604+
with ChiselOption
605+
606+
case object IncludeInlineTestsWithName extends HasShellOptions {
607+
val options = Seq(
608+
new ShellOption[String](
609+
longOption = "include-tests-name",
610+
toAnnotationSeq = glob => Seq(IncludeInlineTestsWithNameAnnotation(glob)),
611+
helpText = "Elaborate inline tests whose name matches this glob"
612+
)
613+
)
614+
}

src/main/scala/chisel3/stage/ChiselOptions.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
package chisel3.stage
44

55
import chisel3.internal.firrtl.ir.Circuit
6-
import chisel3.internal.WarningFilter
6+
import chisel3.internal.{InlineTestIncluder, WarningFilter}
77
import chisel3.layer.Layer
88
import chisel3.ElaboratedCircuit
99
import java.io.File
@@ -18,7 +18,8 @@ class ChiselOptions private[stage] (
1818
val layerMap: Map[Layer, Layer] = Map.empty,
1919
val includeUtilMetadata: Boolean = false,
2020
val useSRAMBlackbox: Boolean = false,
21-
val elaboratedCircuit: Option[ElaboratedCircuit] = None
21+
val elaboratedCircuit: Option[ElaboratedCircuit] = None,
22+
val inlineTestIncluder: InlineTestIncluder = InlineTestIncluder.none
2223
) {
2324

2425
private[stage] def copy(
@@ -31,7 +32,8 @@ class ChiselOptions private[stage] (
3132
layerMap: Map[Layer, Layer] = layerMap,
3233
includeUtilMetadata: Boolean = includeUtilMetadata,
3334
useSRAMBlackbox: Boolean = useSRAMBlackbox,
34-
elaboratedCircuit: Option[ElaboratedCircuit] = elaboratedCircuit
35+
elaboratedCircuit: Option[ElaboratedCircuit] = elaboratedCircuit,
36+
inlineTestIncluder: InlineTestIncluder = inlineTestIncluder
3537
): ChiselOptions = {
3638

3739
new ChiselOptions(
@@ -44,7 +46,8 @@ class ChiselOptions private[stage] (
4446
layerMap = layerMap,
4547
includeUtilMetadata = includeUtilMetadata,
4648
useSRAMBlackbox = useSRAMBlackbox,
47-
elaboratedCircuit = elaboratedCircuit
49+
elaboratedCircuit = elaboratedCircuit,
50+
inlineTestIncluder = inlineTestIncluder
4851
)
4952

5053
}

src/main/scala/chisel3/stage/package.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ package object stage {
3434
case RemapLayer(oldLayer, newLayer) => c.copy(layerMap = c.layerMap + ((oldLayer, newLayer)))
3535
case IncludeUtilMetadata => c.copy(includeUtilMetadata = true)
3636
case UseSRAMBlackbox => c.copy(useSRAMBlackbox = true)
37+
case IncludeInlineTestsForModuleAnnotation(glob) =>
38+
c.copy(inlineTestIncluder = c.inlineTestIncluder.includeModule(glob))
39+
case IncludeInlineTestsWithNameAnnotation(glob) =>
40+
c.copy(inlineTestIncluder = c.inlineTestIncluder.includeTest(glob))
3741
}
3842
}
3943

src/main/scala/chisel3/stage/phases/Elaborate.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ class Elaborate extends Phase {
5353
loggerOptions,
5454
ArrayBuffer[Definition[_]](),
5555
BuilderContextCache.empty,
56-
chiselOptions.layerMap
56+
chiselOptions.layerMap,
57+
chiselOptions.inlineTestIncluder
5758
)
5859
val (elaboratedCircuit, dut) = {
5960
Builder.build(Module(gen()), context)

src/main/scala/circt/stage/Shell.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import chisel3.stage.{
66
ChiselCircuitAnnotation,
77
ChiselGeneratorAnnotation,
88
CircuitSerializationAnnotation,
9+
IncludeInlineTestsForModule,
10+
IncludeInlineTestsWithName,
911
IncludeUtilMetadata,
1012
PrintFullStackTraceAnnotation,
1113
RemapLayer,
@@ -48,7 +50,9 @@ trait CLI extends BareShell { this: BareShell =>
4850
DumpFir,
4951
RemapLayer,
5052
IncludeUtilMetadata,
51-
UseSRAMBlackbox
53+
UseSRAMBlackbox,
54+
IncludeInlineTestsForModule,
55+
IncludeInlineTestsWithName
5256
).foreach(_.addOptions(parser))
5357

5458
parser.note("CIRCT (MLIR FIRRTL Compiler) options")

0 commit comments

Comments
 (0)