summaryrefslogtreecommitdiff
path: root/src/test/scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/scala')
-rw-r--r--src/test/scala/chiselTests/AutoClonetypeSpec.scala19
-rw-r--r--src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala39
-rw-r--r--src/test/scala/chiselTests/CompileOptionsTest.scala28
-rw-r--r--src/test/scala/chiselTests/DecoupledSpec.scala91
-rw-r--r--src/test/scala/chiselTests/ExtModule.scala44
-rw-r--r--src/test/scala/chiselTests/InstanceNameSpec.scala20
-rw-r--r--src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala133
-rw-r--r--src/test/scala/chiselTests/NamingAnnotationTest.scala31
-rw-r--r--src/test/scala/chiselTests/NewAnnotationsSpec.scala72
-rw-r--r--src/test/scala/chiselTests/PrintableSpec.scala207
-rw-r--r--src/test/scala/chiselTests/SIntOps.scala6
-rw-r--r--src/test/scala/chiselTests/StrongEnum.scala5
-rw-r--r--src/test/scala/chiselTests/ToTargetSpec.scala52
-rw-r--r--src/test/scala/chiselTests/UIntOps.scala6
-rw-r--r--src/test/scala/chiselTests/Vec.scala22
-rw-r--r--src/test/scala/chiselTests/VerificationSpec.scala10
-rw-r--r--src/test/scala/chiselTests/experimental/DataMirrorSpec.scala58
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala19
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala495
-rw-r--r--src/test/scala/chiselTests/naming/NamePluginSpec.scala38
-rw-r--r--src/test/scala/chiselTests/naming/PrefixSpec.scala114
-rw-r--r--src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala161
-rw-r--r--src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala17
23 files changed, 1603 insertions, 84 deletions
diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
index 2ab4c800..5d2cd496 100644
--- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala
+++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
@@ -381,4 +381,23 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
}
elaborate(new MyModule)
}
+
+ it should "support Bundles with vararg arguments" in {
+ // Without the fix, this doesn't even compile
+ // Extra parameter lists to make this a complex test case
+ class VarArgsBundle(x: Int)(y: Int, widths: Int*) extends Bundle {
+ def mkField(idx: Int): Option[UInt] =
+ (x +: y +: widths).lift(idx).map(w => UInt(w.W))
+ val foo = mkField(0)
+ val bar = mkField(1)
+ val fizz = mkField(2)
+ val buzz = mkField(3)
+ }
+ class MyModule extends Module {
+ val in = IO(Input(new VarArgsBundle(1)(2, 3, 4)))
+ val out = IO(Output(new VarArgsBundle(1)(2, 3, 4)))
+ out := in
+ }
+ elaborate(new MyModule)
+ }
}
diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
index 70dcda48..1e199297 100644
--- a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
@@ -351,4 +351,43 @@ class CompatibilityInteroperabilitySpec extends ChiselFlatSpec {
compile(new Top(true))
compile(new Top(false))
}
+
+ "A unidirectional but flipped Bundle with something close to NotStrict compileOptions, but not exactly" should "bulk connect in import chisel3._ code correctly" in {
+ object Compat {
+ import Chisel.{defaultCompileOptions => _, _}
+ // arbitrary thing to make this *not* exactly NotStrict
+ implicit val defaultCompileOptions = new chisel3.ExplicitCompileOptions.CompileOptionsClass(
+ connectFieldsMustMatch = false,
+ declaredTypeMustBeUnbound = false,
+ dontTryConnectionsSwapped = false,
+ dontAssumeDirectionality = false,
+ checkSynthesizable = false,
+ explicitInvalidate = false,
+ inferModuleReset = true // different from NotStrict, to ensure case class equivalence to NotStrict is false
+ ) {
+ override def emitStrictConnects = false
+ }
+
+ class MyBundle(extraFlip: Boolean) extends Bundle {
+ private def maybeFlip[T <: Data](t: T): T = if (extraFlip) t.flip else t
+ val foo = maybeFlip(new Bundle {
+ val bar = UInt(INPUT, width = 8)
+ })
+ }
+ }
+ import chisel3._
+ import Compat.{defaultCompileOptions => _, _}
+ class Top(extraFlip: Boolean) extends RawModule {
+ val port = IO(new MyBundle(extraFlip))
+ val wire = Wire(new MyBundle(extraFlip))
+ port <> DontCare
+ wire <> DontCare
+ port <> wire
+ wire <> port
+ port.foo <> wire.foo
+ wire.foo <> port.foo
+ }
+ compile(new Top(true))
+ compile(new Top(false))
+ }
}
diff --git a/src/test/scala/chiselTests/CompileOptionsTest.scala b/src/test/scala/chiselTests/CompileOptionsTest.scala
index 3ec59954..b39d8ee3 100644
--- a/src/test/scala/chiselTests/CompileOptionsTest.scala
+++ b/src/test/scala/chiselTests/CompileOptionsTest.scala
@@ -163,4 +163,32 @@ class CompileOptionsSpec extends ChiselFlatSpec with Utils {
}
}
+ "Strict.copy()" should "be equivalent in all CompileOptions traits" in {
+ import chisel3.ExplicitCompileOptions.Strict
+ val copiedCompileOptions = Strict.copy()
+ assert(copiedCompileOptions.connectFieldsMustMatch == Strict.connectFieldsMustMatch)
+ assert(copiedCompileOptions.declaredTypeMustBeUnbound == Strict.declaredTypeMustBeUnbound)
+ assert(copiedCompileOptions.dontTryConnectionsSwapped == Strict.dontTryConnectionsSwapped)
+ assert(copiedCompileOptions.dontAssumeDirectionality == Strict.dontAssumeDirectionality)
+ assert(copiedCompileOptions.checkSynthesizable == Strict.checkSynthesizable)
+ assert(copiedCompileOptions.explicitInvalidate == Strict.explicitInvalidate)
+ assert(copiedCompileOptions.inferModuleReset == Strict.inferModuleReset)
+ assert(copiedCompileOptions.migrateInferModuleReset == Strict.migrateInferModuleReset)
+ assert(copiedCompileOptions.emitStrictConnects == Strict.emitStrictConnects)
+ }
+
+ "NotStrict.copy()" should "be equivalent in all CompileOptions traits" in {
+ import chisel3.ExplicitCompileOptions.NotStrict
+ val copiedCompileOptions = NotStrict.copy()
+ assert(copiedCompileOptions.connectFieldsMustMatch == NotStrict.connectFieldsMustMatch)
+ assert(copiedCompileOptions.declaredTypeMustBeUnbound == NotStrict.declaredTypeMustBeUnbound)
+ assert(copiedCompileOptions.dontTryConnectionsSwapped == NotStrict.dontTryConnectionsSwapped)
+ assert(copiedCompileOptions.dontAssumeDirectionality == NotStrict.dontAssumeDirectionality)
+ assert(copiedCompileOptions.checkSynthesizable == NotStrict.checkSynthesizable)
+ assert(copiedCompileOptions.explicitInvalidate == NotStrict.explicitInvalidate)
+ assert(copiedCompileOptions.inferModuleReset == NotStrict.inferModuleReset)
+ assert(copiedCompileOptions.migrateInferModuleReset == NotStrict.migrateInferModuleReset)
+ assert(copiedCompileOptions.emitStrictConnects == NotStrict.emitStrictConnects)
+ }
+
}
diff --git a/src/test/scala/chiselTests/DecoupledSpec.scala b/src/test/scala/chiselTests/DecoupledSpec.scala
index 2d305f4a..69d74aab 100644
--- a/src/test/scala/chiselTests/DecoupledSpec.scala
+++ b/src/test/scala/chiselTests/DecoupledSpec.scala
@@ -17,4 +17,95 @@ class DecoupledSpec extends ChiselFlatSpec {
assert(io.asUInt.widthOption.get === 4)
})
}
+
+ "Decoupled.map" should "apply a function to a wrapped Data" in {
+ val chirrtl = ChiselStage
+ .emitChirrtl(new Module {
+ val enq = IO(Flipped(Decoupled(UInt(8.W))))
+ val deq = IO(Decoupled(UInt(8.W)))
+ deq <> enq.map(_ + 1.U)
+ })
+
+ // Check for data assignment
+ chirrtl should include("""node _deq_map_bits_T = add(enq.bits, UInt<1>("h1")""")
+ chirrtl should include("""node _deq_map_bits = tail(_deq_map_bits_T, 1)""")
+ chirrtl should include("""_deq_map.bits <= _deq_map_bits""")
+ chirrtl should include("""deq <= _deq_map""")
+
+ // Check for back-pressure (ready signal is driven in the opposite direction of bits + valid)
+ chirrtl should include("""enq.ready <= _deq_map.ready""")
+ }
+
+ "Decoupled.map" should "apply a function to a wrapped Bundle" in {
+ class TestBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = UInt(8.W)
+ val fizz = Bool()
+ val buzz = Bool()
+ }
+
+ // Add one to foo, subtract one from bar, set fizz to false and buzz to true
+ def func(t: TestBundle): TestBundle = {
+ val res = Wire(new TestBundle)
+
+ res.foo := t.foo + 1.U
+ res.bar := t.bar - 1.U
+ res.fizz := false.B
+ res.buzz := true.B
+
+ res
+ }
+
+ val chirrtl = ChiselStage
+ .emitChirrtl(new Module {
+ val enq = IO(Flipped(Decoupled(new TestBundle)))
+ val deq = IO(Decoupled(new TestBundle))
+ deq <> enq.map(func)
+ })
+
+ // Check for data assignment
+ chirrtl should include("""wire _deq_map_bits : { foo : UInt<8>, bar : UInt<8>, fizz : UInt<1>, buzz : UInt<1>}""")
+
+ chirrtl should include("""node _deq_map_bits_res_foo_T = add(enq.bits.foo, UInt<1>("h1")""")
+ chirrtl should include("""node _deq_map_bits_res_foo_T_1 = tail(_deq_map_bits_res_foo_T, 1)""")
+ chirrtl should include("""_deq_map_bits.foo <= _deq_map_bits_res_foo_T_1""")
+
+ chirrtl should include("""node _deq_map_bits_res_bar_T = sub(enq.bits.bar, UInt<1>("h1")""")
+ chirrtl should include("""node _deq_map_bits_res_bar_T_1 = tail(_deq_map_bits_res_bar_T, 1)""")
+ chirrtl should include("""_deq_map_bits.bar <= _deq_map_bits_res_bar_T_1""")
+
+ chirrtl should include("""_deq_map_bits.fizz <= UInt<1>("h0")""")
+ chirrtl should include("""_deq_map_bits.buzz <= UInt<1>("h1")""")
+
+ chirrtl should include("""_deq_map.bits <= _deq_map_bits""")
+ chirrtl should include("""deq <= _deq_map""")
+
+ // Check for back-pressure (ready signal is driven in the opposite direction of bits + valid)
+ chirrtl should include("""enq.ready <= _deq_map.ready""")
+ }
+
+ "Decoupled.map" should "apply a function to a wrapped Bundle and return a different typed DecoupledIO" in {
+ class TestBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = UInt(8.W)
+ }
+
+ val chirrtl = ChiselStage
+ .emitChirrtl(new Module {
+ val enq = IO(Flipped(Decoupled(new TestBundle)))
+ val deq = IO(Decoupled(UInt(8.W)))
+ deq <> enq.map(bundle => bundle.foo & bundle.bar)
+ })
+
+ // Check that the _map wire wraps a UInt and not a TestBundle
+ chirrtl should include("""wire _deq_map : { flip ready : UInt<1>, valid : UInt<1>, bits : UInt<8>}""")
+
+ // Check for data assignment
+ chirrtl should include("""node _deq_map_bits = and(enq.bits.foo, enq.bits.bar)""")
+ chirrtl should include("""_deq_map.bits <= _deq_map_bits""")
+ chirrtl should include("""deq <= _deq_map""")
+
+ // Check for back-pressure (ready signal is driven in the opposite direction of bits + valid)
+ chirrtl should include("""enq.ready <= _deq_map.ready""")
+ }
}
diff --git a/src/test/scala/chiselTests/ExtModule.scala b/src/test/scala/chiselTests/ExtModule.scala
index 1dbd7447..b5a8ff7c 100644
--- a/src/test/scala/chiselTests/ExtModule.scala
+++ b/src/test/scala/chiselTests/ExtModule.scala
@@ -59,6 +59,35 @@ class MultiExtModuleTester extends BasicTester {
stop()
}
+class ExtModuleWithSuggestName extends ExtModule {
+ val in = IO(Input(UInt(8.W)))
+ in.suggestName("foo")
+ val out = IO(Output(UInt(8.W)))
+}
+
+class ExtModuleWithSuggestNameTester extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ val inst = Module(new ExtModuleWithSuggestName)
+ inst.in := in
+ out := inst.out
+}
+
+class SimpleIOBundle extends Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+}
+
+class ExtModuleWithFlatIO extends ExtModule {
+ val badIO = FlatIO(new SimpleIOBundle)
+}
+
+class ExtModuleWithFlatIOTester extends Module {
+ val io = IO(new SimpleIOBundle)
+ val inst = Module(new ExtModuleWithFlatIO)
+ io <> inst.badIO
+}
+
class ExtModuleSpec extends ChiselFlatSpec {
"A ExtModule inverter" should "work" in {
assertTesterPasses({ new ExtModuleTester }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
@@ -73,4 +102,19 @@ class ExtModuleSpec extends ChiselFlatSpec {
assert(DataMirror.modulePorts(m) == Seq("in" -> m.in, "out" -> m.out))
})
}
+
+ behavior.of("ExtModule")
+
+ it should "work with .suggestName (aka it should not require reflection for naming)" in {
+ val chirrtl = ChiselStage.emitChirrtl(new ExtModuleWithSuggestNameTester)
+ chirrtl should include("input foo : UInt<8>")
+ chirrtl should include("inst.foo <= in")
+ }
+
+ it should "work with FlatIO" in {
+ val chirrtl = ChiselStage.emitChirrtl(new ExtModuleWithFlatIOTester)
+ chirrtl should include("io.out <= inst.out")
+ chirrtl should include("inst.in <= io.in")
+ chirrtl shouldNot include("badIO")
+ }
}
diff --git a/src/test/scala/chiselTests/InstanceNameSpec.scala b/src/test/scala/chiselTests/InstanceNameSpec.scala
index 7eaf3106..cc5980f4 100644
--- a/src/test/scala/chiselTests/InstanceNameSpec.scala
+++ b/src/test/scala/chiselTests/InstanceNameSpec.scala
@@ -22,28 +22,36 @@ class InstanceNameModule extends Module {
io.bar := io.foo + x
}
-class InstanceNameSpec extends ChiselFlatSpec {
+class InstanceNameSpec extends ChiselFlatSpec with Utils {
behavior.of("instanceName")
val moduleName = "InstanceNameModule"
var m: InstanceNameModule = _
ChiselStage.elaborate { m = new InstanceNameModule; m }
+ val deprecationMsg = "Accessing the .instanceName or .toTarget of non-hardware Data is deprecated"
+
it should "work with module IO" in {
val io = m.io.pathName
assert(io == moduleName + ".io")
}
- it should "work with internal vals" in {
+ it should "work for literals" in {
val x = m.x.pathName
- val y = m.y.pathName
- val z = m.z.pathName
assert(x == moduleName + ".UInt<2>(\"h03\")")
+ }
+
+ it should "work with non-hardware values (but be deprecated)" in {
+ val (ylog, y) = grabLog(m.y.pathName)
+ val (zlog, z) = grabLog(m.z.pathName)
+ ylog should include(deprecationMsg)
assert(y == moduleName + ".y")
+ zlog should include(deprecationMsg)
assert(z == moduleName + ".z")
}
- it should "work with bundle elements" in {
- val foo = m.z.foo.pathName
+ it should "work with non-hardware bundle elements (but be deprecated)" in {
+ val (log, foo) = grabLog(m.z.foo.pathName)
+ log should include(deprecationMsg)
assert(foo == moduleName + ".z.foo")
}
diff --git a/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala b/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala
new file mode 100644
index 00000000..091f7f28
--- /dev/null
+++ b/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3.stage.ChiselStage
+import chisel3.ImplicitInvalidate
+import chisel3.ExplicitCompileOptions
+
+import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks
+
+object MigrationExamples {
+ object InferResets {
+ import Chisel.{defaultCompileOptions => _, _}
+ import chisel3.RequireSyncReset
+ implicit val migrateIR = new chisel3.CompileOptions {
+ val connectFieldsMustMatch = false
+ val declaredTypeMustBeUnbound = false
+ val dontTryConnectionsSwapped = false
+ val dontAssumeDirectionality = false
+ val checkSynthesizable = false
+ val explicitInvalidate = false
+ val inferModuleReset = false
+
+ override val migrateInferModuleReset = true
+ }
+
+ class Foo extends Module {
+ val io = new Bundle {}
+ }
+ class FooWithRequireSyncReset extends Module with RequireSyncReset {
+ val io = new Bundle {}
+ }
+ }
+ object ExplicitInvalidate {
+ import chisel3.ImplicitInvalidate
+ val migrateEI = new chisel3.CompileOptions {
+ val connectFieldsMustMatch = false
+ val declaredTypeMustBeUnbound = false
+ val dontTryConnectionsSwapped = false
+ val dontAssumeDirectionality = false
+ val checkSynthesizable = false
+ val explicitInvalidate = true
+ val inferModuleReset = false
+ }
+ object ChiselChildren {
+ import Chisel.{defaultCompileOptions => _, _}
+ implicit val options = migrateEI
+ class Foo extends Module {
+ val io = new Bundle {
+ val out = Output(UInt(width = 3))
+ }
+ }
+ class FooWithImplicitInvalidate extends Module with ImplicitInvalidate {
+ val io = new Bundle {
+ val out = Output(UInt(width = 3))
+ }
+ }
+ class FooWire extends Module {
+ val io = new Bundle {}
+ val wire = Wire(Bool())
+ }
+ class FooWireWithImplicitInvalidate extends Module with ImplicitInvalidate {
+ val io = new Bundle {}
+ val wire = Wire(Bool())
+ }
+ }
+ object chisel3Children {
+ import chisel3._
+ class Foo extends Module {
+ val in = IO(chisel3.Input(UInt(3.W)))
+ }
+ }
+ object ChiselParents {
+ import Chisel.{defaultCompileOptions => _, _}
+ implicit val options = migrateEI
+
+ class FooParent extends Module {
+ val io = new Bundle {}
+ val i = Module(new chisel3Children.Foo)
+ }
+ class FooParentWithImplicitInvalidate extends Module with ImplicitInvalidate {
+ val io = new Bundle {}
+ val i = Module(new chisel3Children.Foo)
+ }
+ }
+ }
+}
+
+class MigrateCompileOptionsSpec extends ChiselFunSpec with Utils {
+ import Chisel.{defaultCompileOptions => _, _}
+ import chisel3.RequireSyncReset
+
+ describe("(0): Migrating infer resets") {
+ import MigrationExamples.InferResets._
+ it("(0.a): Error if migrating, but not extended RequireSyncReset") {
+ intercept[Exception] { ChiselStage.elaborate(new Foo) }
+ }
+ it("(0.b): Not error if migrating, and you mix with RequireSyncReset") {
+ ChiselStage.elaborate(new FooWithRequireSyncReset)
+ }
+ }
+
+ describe("(1): Migrating explicit invalidate") {
+ import MigrationExamples.ExplicitInvalidate._
+
+ it("(1.a): error if migrating module input, but not extending ImplicitInvalidate") {
+ intercept[_root_.firrtl.passes.CheckInitialization.RefNotInitializedException] {
+ ChiselStage.emitVerilog(new ChiselChildren.Foo)
+ }
+ }
+ it("(1.b): succeed if migrating module input with extending ImplicitInvalidate") {
+ ChiselStage.emitVerilog(new ChiselChildren.FooWithImplicitInvalidate)
+ }
+
+ it("(1.c): error if migrating instance output, but not extending ImplicitInvalidate") {
+ intercept[_root_.firrtl.passes.CheckInitialization.RefNotInitializedException] {
+ ChiselStage.emitVerilog(new ChiselParents.FooParent)
+ }
+ }
+ it("(1.d): succeed if migrating instance output with extending ImplicitInvalidate") {
+ ChiselStage.emitVerilog(new ChiselParents.FooParentWithImplicitInvalidate)
+ }
+
+ it("(1.e): error if migrating wire declaration, but not extending ImplicitInvalidate") {
+ intercept[_root_.firrtl.passes.CheckInitialization.RefNotInitializedException] {
+ ChiselStage.emitVerilog(new ChiselChildren.FooWire)
+ }
+ }
+ it("(1.f): succeed if migrating wire declaration with extending ImplicitInvalidate") {
+ ChiselStage.emitVerilog(new ChiselChildren.FooWireWithImplicitInvalidate)
+ }
+ }
+}
diff --git a/src/test/scala/chiselTests/NamingAnnotationTest.scala b/src/test/scala/chiselTests/NamingAnnotationTest.scala
index ded321cd..a3f39c51 100644
--- a/src/test/scala/chiselTests/NamingAnnotationTest.scala
+++ b/src/test/scala/chiselTests/NamingAnnotationTest.scala
@@ -4,12 +4,13 @@ package chiselTests
import chisel3._
import chisel3.experimental.chiselName
+import chisel3.experimental.AffectsChiselPrefix
import chisel3.internal.InstanceId
import chisel3.stage.ChiselStage
import scala.collection.mutable.ListBuffer
-trait NamedModuleTester extends Module {
+trait NamedModuleTester extends Module with AffectsChiselPrefix {
val expectedNameMap = ListBuffer[(InstanceId, String)]()
val expectedModuleNameMap = ListBuffer[(Module, String)]()
@@ -48,25 +49,20 @@ trait NamedModuleTester extends Module {
failures.toList
}
}
-@chiselName
-class OuterNamedNonModule {
+class OuterNamedNonModule extends AffectsChiselPrefix {
val value = Wire(Bool())
}
-@chiselName
-class NonModule {
+class NonModule extends AffectsChiselPrefix {
val value = Wire(Bool())
- @chiselName
- class InnerNamedNonModule {
+ class InnerNamedNonModule extends AffectsChiselPrefix {
val value = Wire(Bool())
}
val inner = new InnerNamedNonModule
val outer = new OuterNamedNonModule
}
-@chiselName
class NamedModule extends NamedModuleTester {
- @chiselName
def FunctionMockupInner(): UInt = {
val my2A = 1.U
val my2B = expectName(my2A +& 2.U, "test_myNested_my2B")
@@ -74,7 +70,6 @@ class NamedModule extends NamedModuleTester {
my2C
}
- @chiselName
def FunctionMockup(): UInt = {
val myNested = expectName(FunctionMockupInner(), "test_myNested")
val myA = expectName(1.U + myNested, "test_myA")
@@ -123,11 +118,9 @@ class NamedModule extends NamedModuleTester {
NoReturnFunction()
}
-@chiselName
class NameCollisionModule extends NamedModuleTester {
- @chiselName
- def repeatedCalls(id: Int): UInt = {
- val test = expectName(1.U + 3.U, s"test_$id") // should disambiguate by invocation order
+ def repeatedCalls(name: String): UInt = {
+ val test = expectName(1.U + 3.U, s"${name}_test") // should disambiguate by invocation order
test + 2.U
}
@@ -135,8 +128,8 @@ class NameCollisionModule extends NamedModuleTester {
def innerNamedFunction() {
// ... but not this inner function
def innerUnnamedFunction() {
- val a = repeatedCalls(1)
- val b = repeatedCalls(2)
+ val a = repeatedCalls("a")
+ val b = repeatedCalls("b")
}
innerUnnamedFunction()
@@ -212,19 +205,17 @@ class NoChiselNamePrefixTester extends NamedModuleTester {
val a = expectName(1.U +& 2.U, "a")
}
val inst = new NoChiselNamePrefixClass
- @chiselName
class NormalClass {
val b = 1.U +& 2.U
}
- val foo = new NormalClass
+ val foo = new NormalClass with AffectsChiselPrefix
expectName(foo.b, "foo_b")
val bar = new NormalClass with chisel3.experimental.NoChiselNamePrefix
expectName(bar.b, "b")
// Check that we're not matching by name but actual type
trait NoChiselNamePrefix
- @chiselName
- class FakeNoChiselNamePrefix extends NoChiselNamePrefix {
+ class FakeNoChiselNamePrefix extends NoChiselNamePrefix with AffectsChiselPrefix {
val c = 1.U +& 2.U
}
val fizz = new FakeNoChiselNamePrefix
diff --git a/src/test/scala/chiselTests/NewAnnotationsSpec.scala b/src/test/scala/chiselTests/NewAnnotationsSpec.scala
new file mode 100644
index 00000000..38e1c1d9
--- /dev/null
+++ b/src/test/scala/chiselTests/NewAnnotationsSpec.scala
@@ -0,0 +1,72 @@
+package chiselTests
+import chisel3._
+import chisel3.experimental.{annotate, ChiselMultiAnnotation}
+import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
+import firrtl.stage.FirrtlCircuitAnnotation
+import org.scalatest.freespec.AnyFreeSpec
+import org.scalatest.matchers.should.Matchers
+import firrtl.transforms.NoDedupAnnotation
+import firrtl.transforms.DontTouchAnnotation
+
+class NewAnnotationsSpec extends AnyFreeSpec with Matchers {
+
+ class MuchUsedModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+ io.out := io.in +% 1.U
+ }
+
+ class UsesMuchUsedModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+
+ val mod0 = Module(new MuchUsedModule)
+ val mod1 = Module(new MuchUsedModule)
+ val mod2 = Module(new MuchUsedModule)
+ val mod3 = Module(new MuchUsedModule)
+
+ mod0.io.in := io.in
+ mod1.io.in := mod0.io.out
+ mod2.io.in := mod1.io.out
+ mod3.io.in := mod2.io.out
+ io.out := mod3.io.out
+
+ // Give two annotations as single element of the seq - ensures previous API works by wrapping into a seq.
+ annotate(new ChiselMultiAnnotation { def toFirrtl = Seq(new NoDedupAnnotation(mod2.toNamed)) })
+ annotate(new ChiselMultiAnnotation { def toFirrtl = Seq(new NoDedupAnnotation(mod3.toNamed)) })
+
+ // Pass multiple annotations in the same seq - should get emitted out correctly.
+ annotate(new ChiselMultiAnnotation {
+ def toFirrtl =
+ Seq(new DontTouchAnnotation(mod1.io.in.toNamed), new DontTouchAnnotation(mod1.io.out.toNamed))
+ })
+ }
+
+ val stage = new ChiselStage
+ "Ensure all annotations continue to be passed / digested correctly with the new API" - {
+ "NoDedup and DontTouch work as expected" in {
+ val dutAnnos = stage
+ .execute(
+ Array("-X", "low", "--target-dir", "test_run_dir"),
+ Seq(ChiselGeneratorAnnotation(() => new UsesMuchUsedModule))
+ )
+
+ val dontTouchAnnos = dutAnnos.collect { case DontTouchAnnotation(target) => target.serialize }
+ val noDedupAnnos = dutAnnos.collect { case NoDedupAnnotation(target) => target.serialize }
+ require(dontTouchAnnos.size == 2, s"Exactly two DontTouch Annotations expected but got $dontTouchAnnos ")
+ require(noDedupAnnos.size == 2, s"Exactly two NoDedup Annotations expected but got $noDedupAnnos ")
+ val dontTouchAnnosCombined = dontTouchAnnos.mkString(",")
+ val noDedupAnnosCombined = noDedupAnnos.mkString(",")
+
+ noDedupAnnosCombined should include("~UsesMuchUsedModule|MuchUsedModule_2")
+ noDedupAnnosCombined should include("~UsesMuchUsedModule|MuchUsedModule_3")
+ dontTouchAnnosCombined should include("~UsesMuchUsedModule|UsesMuchUsedModule/mod1:MuchUsedModule>io_out")
+ dontTouchAnnosCombined should include("~UsesMuchUsedModule|UsesMuchUsedModule/mod1:MuchUsedModule>io_in")
+
+ }
+ }
+}
diff --git a/src/test/scala/chiselTests/PrintableSpec.scala b/src/test/scala/chiselTests/PrintableSpec.scala
index 7d584cea..8039918d 100644
--- a/src/test/scala/chiselTests/PrintableSpec.scala
+++ b/src/test/scala/chiselTests/PrintableSpec.scala
@@ -9,7 +9,8 @@ import chisel3.testers.BasicTester
import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
-
+import chisel3.util._
+import org.scalactic.source.Position
import java.io.File
/** Dummy [[printf]] annotation.
@@ -32,7 +33,7 @@ object PrintfAnnotation {
}
/* Printable Tests */
-class PrintableSpec extends AnyFlatSpec with Matchers {
+class PrintableSpec extends AnyFlatSpec with Matchers with Utils {
// This regex is brittle, it specifically finds the clock and enable signals followed by commas
private val PrintfRegex = """\s*printf\(\w+, [^,]+,(.*)\).*""".r
private val StringRegex = """([^"]*)"(.*?)"(.*)""".r
@@ -47,7 +48,6 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
case _ => fail(s"Regex to process Printf should work on $str!")
}
}
-
firrtl.split("\n").collect {
case PrintfRegex(matched) =>
val (str, args) = processBody(matched)
@@ -55,26 +55,34 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
}
}
+ // Generates firrtl, gets Printfs
+ // Calls fail() if failed match; else calls the partial function which could have its own check
+ private def generateAndCheck(gen: => RawModule)(check: PartialFunction[Seq[Printf], Unit])(implicit pos: Position) = {
+ val firrtl = ChiselStage.emitChirrtl(gen)
+ val printfs = getPrintfs(firrtl)
+ if (!check.isDefinedAt(printfs)) {
+ fail()
+ } else {
+ check(printfs)
+ }
+ }
+
behavior.of("Printable & Custom Interpolator")
it should "pass exact strings through" in {
class MyModule extends BasicTester {
printf(p"An exact string")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("An exact string", Seq())) =>
- case e => fail()
}
}
it should "handle Printable and String concatination" in {
class MyModule extends BasicTester {
printf(p"First " + PString("Second ") + "Third")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("First Second Third", Seq())) =>
- case e => fail()
}
}
it should "call toString on non-Printable objects" in {
@@ -82,10 +90,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myInt = 1234
printf(p"myInt = $myInt")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("myInt = 1234", Seq())) =>
- case e => fail()
}
}
it should "generate proper printf for simple Decimal printing" in {
@@ -93,41 +99,33 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myWire = WireDefault(1234.U)
printf(p"myWire = ${Decimal(myWire)}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("myWire = %d", Seq("myWire"))) =>
- case e => fail()
}
}
it should "handle printing literals" in {
class MyModule extends BasicTester {
printf(Decimal(10.U(32.W)))
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d", Seq(lit))) =>
assert(lit contains "UInt<32>")
- case e => fail()
}
}
it should "correctly escape percent" in {
class MyModule extends BasicTester {
printf(p"%")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%%", Seq())) =>
- case e => fail()
}
}
it should "correctly emit tab" in {
class MyModule extends BasicTester {
printf(p"\t")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("\\t", Seq())) =>
- case e => fail()
}
}
it should "support names of circuit elements including submodule IO" in {
@@ -149,10 +147,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
printf(p"${FullName(myWire.foo)}")
printf(p"${FullName(myInst.io.fizz)}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("foo", Seq()), Printf("myWire.foo", Seq()), Printf("myInst.io.fizz", Seq())) =>
- case e => fail()
}
}
it should "handle printing ports of submodules" in {
@@ -165,10 +161,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myInst = Module(new MySubModule)
printf(p"${myInst.io.fizz}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d", Seq("myInst.io.fizz"))) =>
- case e => fail()
}
}
it should "print UInts and SInts as Decimal by default" in {
@@ -177,10 +171,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val mySInt = WireDefault(-1.S)
printf(p"$myUInt & $mySInt")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d & %d", Seq("myUInt", "mySInt"))) =>
- case e => fail()
}
}
it should "print Vecs like Scala Seqs by default" in {
@@ -189,10 +181,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
myVec.foreach(_ := 0.U)
printf(p"$myVec")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("Vec(%d, %d, %d, %d)", Seq("myVec[0]", "myVec[1]", "myVec[2]", "myVec[3]"))) =>
- case e => fail()
}
}
it should "print Bundles like Scala Maps by default" in {
@@ -205,10 +195,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
myBun.bar := 0.U
printf(p"$myBun")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("AnonymousBundle(foo -> %d, bar -> %d)", Seq("myBun.foo", "myBun.bar"))) =>
- case e => fail()
}
}
it should "get emitted with a name and annotated" in {
@@ -261,4 +249,145 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
"""printf(clock, UInt<1>("h1"), "adieu AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : farewell"""
)
}
+
+ // Unit tests for cf
+ it should "print regular scala variables with cf format specifier" in {
+
+ class MyModule extends BasicTester {
+ val f1 = 20.4517
+ val i1 = 10
+ val str1 = "String!"
+ printf(
+ cf"F1 = $f1 D1 = $i1 F1 formatted = $f1%2.2f str1 = $str1%s i1_str = $i1%s i1_hex=$i1%x"
+ )
+
+ }
+
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("F1 = 20.4517 D1 = 10 F1 formatted = 20.45 str1 = String! i1_str = 10 i1_hex=a", Seq())) =>
+ }
+ }
+
+ it should "print chisel bits with cf format specifier" in {
+
+ class MyBundle extends Bundle {
+ val foo = UInt(32.W)
+ val bar = UInt(32.W)
+ override def toPrintable: Printable = {
+ cf"Bundle : " +
+ cf"Foo : $foo%x Bar : $bar%x"
+ }
+ }
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ val w1 = Wire(new MyBundle)
+ w1.foo := 5.U
+ w1.bar := 10.U
+ printf(cf"w1 = $w1")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("w1 = Bundle : Foo : %x Bar : %x", Seq("w1.foo", "w1.bar"))) =>
+ }
+ }
+
+ it should "support names of circuit elements using format specifier including submodule IO with cf format specifier" in {
+ // Submodule IO is a subtle issue because the Chisel element has a different
+ // parent module
+ class MySubModule extends Module {
+ val io = IO(new Bundle {
+ val fizz = UInt(32.W)
+ })
+ }
+ class MyBundle extends Bundle {
+ val foo = UInt(32.W)
+ }
+ class MyModule extends BasicTester {
+ override def desiredName: String = "MyModule"
+ val myWire = Wire(new MyBundle)
+ val myInst = Module(new MySubModule)
+ printf(cf"${myWire.foo}%n")
+ printf(cf"${myWire.foo}%N")
+ printf(cf"${myInst.io.fizz}%N")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("foo", Seq()), Printf("myWire.foo", Seq()), Printf("myInst.io.fizz", Seq())) =>
+ }
+ }
+
+ it should "correctly print strings after modifier" in {
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ printf(cf"This is here $b1%x!!!! And should print everything else")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("This is here %x!!!! And should print everything else", Seq("UInt<4>(\"ha\")"))) =>
+ }
+ }
+
+ it should "correctly print strings with a lot of literal %% and different format specifiers for Wires" in {
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ val b2 = 20.U
+ printf(cf"%% $b1%x%%$b2%b = ${b1 % b2}%d %%%% Tail String")
+ }
+
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("%% %x%%%b = %d %%%% Tail String", Seq(lita, litb, _))) =>
+ assert(lita.contains("UInt<4>") && litb.contains("UInt<5>"))
+ }
+ }
+
+ it should "not allow unescaped % in the message" in {
+ class MyModule extends BasicTester {
+ printf(cf"This should error out for sure because of % - it should be %%")
+ }
+ a[java.util.UnknownFormatConversionException] should be thrownBy {
+ extractCause[java.util.UnknownFormatConversionException] {
+ ChiselStage.elaborate { new MyModule }
+ }
+ }
+ }
+
+ it should "allow Printables to be expanded and used" in {
+ class MyModule extends BasicTester {
+ val w1 = 20.U
+ val f1 = 30.2
+ val i1 = 14
+ val pable = cf"w1 = $w1%b f1 = $f1%2.2f"
+ printf(cf"Trying to expand printable $pable and mix with i1 = $i1%d")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("Trying to expand printable w1 = %b f1 = 30.20 and mix with i1 = 14", Seq(lit))) =>
+ assert(lit.contains("UInt<5>"))
+ }
+ }
+
+ it should "fail with a single % in the message" in {
+ class MyModule extends BasicTester {
+ printf(cf"%")
+ }
+ a[java.util.UnknownFormatConversionException] should be thrownBy {
+ extractCause[java.util.UnknownFormatConversionException] {
+ ChiselStage.elaborate { new MyModule }
+ }
+ }
+ }
+
+ it should "fail when passing directly to StirngContext.cf a string with literal \\ correctly escaped " in {
+ a[StringContext.InvalidEscapeException] should be thrownBy {
+ extractCause[StringContext.InvalidEscapeException] {
+ val s_seq = Seq("Test with literal \\ correctly escaped")
+ StringContext(s_seq: _*).cf(Seq(): _*)
+ }
+ }
+ }
+
+ it should "pass correctly escaped \\ when using Printable.pack" in {
+ class MyModule extends BasicTester {
+ printf(Printable.pack("\\ \\]"))
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("\\\\ \\\\]", Seq())) =>
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/SIntOps.scala b/src/test/scala/chiselTests/SIntOps.scala
index 55b4c915..ebbd2012 100644
--- a/src/test/scala/chiselTests/SIntOps.scala
+++ b/src/test/scala/chiselTests/SIntOps.scala
@@ -85,9 +85,9 @@ class SIntOpsTester(c: SIntOps) extends Tester(c) {
*/
class SIntLitExtractTester extends BasicTester {
- assert(-5.S(1) === true.B)
- assert(-5.S(2) === false.B)
- assert(-5.S(100) === true.B)
+ assert(-5.S.extract(1) === true.B)
+ assert(-5.S.extract(2) === false.B)
+ assert(-5.S.extract(100) === true.B)
assert(-5.S(3, 0) === "b1011".U)
assert(-5.S(9, 0) === "b1111111011".U)
assert(-5.S(4.W)(1) === true.B)
diff --git a/src/test/scala/chiselTests/StrongEnum.scala b/src/test/scala/chiselTests/StrongEnum.scala
index c43d832a..44ed77f9 100644
--- a/src/test/scala/chiselTests/StrongEnum.scala
+++ b/src/test/scala/chiselTests/StrongEnum.scala
@@ -4,8 +4,8 @@ package chiselTests
import chisel3._
import chisel3.experimental.ChiselEnum
+import chisel3.experimental.AffectsChiselPrefix
import chisel3.internal.firrtl.UnknownWidth
-import chisel3.internal.naming.chiselName
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util._
import chisel3.testers.BasicTester
@@ -575,11 +575,10 @@ class StrongEnumAnnotator extends Module {
val indexed2 = vec_of_bundles(cycle)
}
-@chiselName
class StrongEnumAnnotatorWithChiselName extends Module {
import EnumExample._
- object LocalEnum extends ChiselEnum {
+ object LocalEnum extends ChiselEnum with AffectsChiselPrefix {
val le0, le1 = Value
val le2 = Value
val le100 = Value(100.U)
diff --git a/src/test/scala/chiselTests/ToTargetSpec.scala b/src/test/scala/chiselTests/ToTargetSpec.scala
new file mode 100644
index 00000000..dc4ec448
--- /dev/null
+++ b/src/test/scala/chiselTests/ToTargetSpec.scala
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3._
+import chisel3.stage.ChiselStage
+import chisel3.util.Queue
+import chisel3.internal.ChiselException
+
+class ToTargetSpec extends ChiselFlatSpec with Utils {
+
+ var m: InstanceNameModule = _
+ ChiselStage.elaborate { m = new InstanceNameModule; m }
+
+ val mn = "InstanceNameModule"
+ val top = s"~$mn|$mn"
+
+ behavior.of(".toTarget")
+
+ val deprecationMsg = "Accessing the .instanceName or .toTarget of non-hardware Data is deprecated"
+
+ it should "work with module IO" in {
+ val io = m.io.toTarget.toString
+ assert(io == s"$top>io")
+ }
+
+ it should "not work for literals" in {
+ a[ChiselException] shouldBe thrownBy {
+ m.x.toTarget.toString
+ }
+ }
+
+ it should "work with non-hardware values (but be deprecated)" in {
+ val (ylog, y) = grabLog(m.y.toTarget.toString)
+ val (zlog, z) = grabLog(m.z.toTarget.toString)
+ assert(y == s"$top>y")
+ ylog should include(deprecationMsg)
+ assert(z == s"$top>z")
+ zlog should include(deprecationMsg)
+ }
+
+ it should "work with non-hardware bundle elements (but be deprecated)" in {
+ val (log, foo) = grabLog(m.z.foo.toTarget.toString)
+ log should include(deprecationMsg)
+ assert(foo == s"$top>z.foo")
+ }
+
+ it should "work with modules" in {
+ val q = m.q.toTarget.toString
+ assert(q == s"~$mn|Queue")
+ }
+}
diff --git a/src/test/scala/chiselTests/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala
index 0010e9ac..2f55da9a 100644
--- a/src/test/scala/chiselTests/UIntOps.scala
+++ b/src/test/scala/chiselTests/UIntOps.scala
@@ -172,9 +172,9 @@ class MatchedRotateLeftAndRight(w: Int = 13) extends BasicTester {
}
class UIntLitExtractTester extends BasicTester {
- assert("b101010".U(2) === false.B)
- assert("b101010".U(3) === true.B)
- assert("b101010".U(100) === false.B)
+ assert("b101010".U.extract(2) === false.B)
+ assert("b101010".U.extract(3) === true.B)
+ assert("b101010".U.extract(100) === false.B)
assert("b101010".U(3, 0) === "b1010".U)
assert("b101010".U(9, 0) === "b0000101010".U)
diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala
index 2eb6ae5f..02743187 100644
--- a/src/test/scala/chiselTests/Vec.scala
+++ b/src/test/scala/chiselTests/Vec.scala
@@ -517,4 +517,26 @@ class VecSpec extends ChiselPropSpec with Utils {
property("reduceTree should preserve input/output type") {
assertTesterPasses { new ReduceTreeTester() }
}
+
+ property("Vecs of empty Bundles and empty Records should work") {
+ class MyModule(gen: Record) extends Module {
+ val idx = IO(Input(UInt(2.W)))
+ val in = IO(Input(gen))
+ val out = IO(Output(gen))
+
+ val reg = RegInit(0.U.asTypeOf(Vec(4, gen)))
+ reg(idx) := in
+ out := reg(idx)
+ }
+ class EmptyBundle extends Bundle
+ class EmptyRecord extends Record {
+ val elements = collection.immutable.ListMap.empty
+ override def cloneType = (new EmptyRecord).asInstanceOf[this.type]
+ }
+ for (gen <- List(new EmptyBundle, new EmptyRecord)) {
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule(gen))
+ chirrtl should include("input in : { }")
+ chirrtl should include("reg reg : { }[4]")
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/VerificationSpec.scala b/src/test/scala/chiselTests/VerificationSpec.scala
index 95b0ffe6..32cee9e3 100644
--- a/src/test/scala/chiselTests/VerificationSpec.scala
+++ b/src/test/scala/chiselTests/VerificationSpec.scala
@@ -105,9 +105,9 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val firLines = scala.io.Source.fromFile(firFile).getLines.toList
// check that verification components have expected names
- exactly(1, firLines) should include("cover(clock, _T, UInt<1>(\"h1\"), \"\") : cov")
- exactly(1, firLines) should include("assume(clock, _T_3, UInt<1>(\"h1\"), \"\") : assm")
- exactly(1, firLines) should include("assert(clock, _T_7, UInt<1>(\"h1\"), \"\") : asst")
+ (exactly(1, firLines) should include).regex("^\\s*cover\\(.*\\) : cov")
+ (exactly(1, firLines) should include).regex("^\\s*assume\\(.*\\) : assm")
+ (exactly(1, firLines) should include).regex("^\\s*assert\\(.*\\) : asst")
}
property("annotation of verification constructs with suggested name should work") {
@@ -150,7 +150,7 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val firLines = scala.io.Source.fromFile(firFile).getLines.toList
// check that verification components have expected names
- exactly(1, firLines) should include("assert(clock, _T, UInt<1>(\"h1\"), \"\") : hello")
- exactly(1, firLines) should include("assume(clock, _T_4, UInt<1>(\"h1\"), \"\") : howdy")
+ (exactly(1, firLines) should include).regex("^\\s*assert\\(.*\\) : hello")
+ (exactly(1, firLines) should include).regex("^\\s*assume\\(.*\\) : howdy")
}
}
diff --git a/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala b/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala
new file mode 100644
index 00000000..731596ec
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests.experimental
+
+import chisel3._
+import chisel3.util.Valid
+import chisel3.stage.ChiselStage
+import chisel3.experimental.DataMirror
+import chiselTests.ChiselFlatSpec
+
+class DataMirrorSpec extends ChiselFlatSpec {
+ behavior.of("DataMirror")
+
+ def assertBinding(x: Data, io: Boolean, wire: Boolean, reg: Boolean) = {
+ DataMirror.isIO(x) should be(io)
+ DataMirror.isWire(x) should be(wire)
+ DataMirror.isReg(x) should be(reg)
+ }
+
+ def assertIO(x: Data) = assertBinding(x, true, false, false)
+
+ def assertWire(x: Data) = assertBinding(x, false, true, false)
+
+ def assertReg(x: Data) = assertBinding(x, false, false, true)
+
+ def assertNone(x: Data) = assertBinding(x, false, false, false)
+
+ it should "validate bindings" in {
+ class MyModule extends Module {
+ val typ = UInt(4.W)
+ val vectyp = Vec(8, UInt(4.W))
+ val io = IO(new Bundle {
+ val in = Input(UInt(4.W))
+ val vec = Input(vectyp)
+ val out = Output(UInt(4.W))
+ })
+ val vec = Wire(vectyp)
+ val regvec = Reg(vectyp)
+ val wire = Wire(UInt(4.W))
+ val reg = RegNext(wire)
+
+ assertIO(io)
+ assertIO(io.in)
+ assertIO(io.out)
+ assertIO(io.vec(1))
+ assertIO(io.vec)
+ assertWire(vec)
+ assertWire(vec(0))
+ assertWire(wire)
+ assertReg(reg)
+ assertReg(regvec)
+ assertReg(regvec(2))
+ assertNone(typ)
+ assertNone(vectyp)
+ }
+ ChiselStage.elaborate(new MyModule)
+ }
+}
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
index e7caacfd..ac8357f0 100644
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ b/src/test/scala/chiselTests/experimental/DataView.scala
@@ -479,6 +479,25 @@ class DataViewSpec extends ChiselFlatSpec {
(err.getMessage should fullyMatch).regex(expected)
}
+ it should "support invalidation" in {
+ class MyModule extends Module {
+ val a, b, c, d, e, f = IO(Output(UInt(8.W)))
+ val foo = (a, b).viewAs
+ val bar = (c, d).viewAs
+ val fizz = (e, f).viewAs
+ foo := DontCare
+ bar <> DontCare
+ fizz._1 := DontCare
+ fizz._2 <> DontCare
+ }
+
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ val expected = ('a' to 'f').map(c => s"$c is invalid")
+ for (line <- expected) {
+ chirrtl should include(line)
+ }
+ }
+
behavior.of("PartialDataView")
it should "still error if the mapping is non-total in the view" in {
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
new file mode 100644
index 00000000..25bbc474
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests.experimental.hierarchy
+
+import chiselTests.ChiselFunSpec
+import chisel3._
+import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselStage, DesignAnnotation}
+import chisel3.experimental.hierarchy.{Definition, Instance}
+import chisel3.experimental.hierarchy.ImportDefinitionAnnotation
+import firrtl.AnnotationSeq
+import firrtl.options.TargetDirAnnotation
+
+import scala.io.Source
+
+class SeparateElaborationSpec extends ChiselFunSpec with Utils {
+ import Examples._
+
+ /** Return a [[DesignAnnotation]] from a list of annotations. */
+ private def getDesignAnnotation[T <: RawModule](annos: AnnotationSeq): DesignAnnotation[T] = {
+ val designAnnos = annos.flatMap { a =>
+ a match {
+ case a: DesignAnnotation[T] => Some(a)
+ case _ => None
+ }
+ }
+ require(designAnnos.length == 1, s"Exactly one DesignAnnotation should exist, but found: $designAnnos.")
+ designAnnos.head
+ }
+
+ /** Elaborates [[AddOne]] and returns its [[Definition]]. */
+ private def getAddOneDefinition(testDir: String): Definition[AddOne] = {
+ val dutAnnos = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOne),
+ TargetDirAnnotation(testDir)
+ )
+ )
+
+ // Grab DUT definition to pass into testbench
+ getDesignAnnotation(dutAnnos).design.asInstanceOf[AddOne].toDefinition
+ }
+
+ /** Return [[Definition]]s of all modules in a circuit. */
+ private def allModulesToImportedDefs(annos: AnnotationSeq): Seq[ImportDefinitionAnnotation[_]] = {
+ annos.flatMap { a =>
+ a match {
+ case a: ChiselCircuitAnnotation =>
+ a.circuit.components.map { c => ImportDefinitionAnnotation(c.id.toDefinition) }
+ case _ => Seq.empty
+ }
+ }
+ }
+
+ describe("(0): Name conflicts") {
+ it("(0.a): should not occur between a Module and an Instance of a previously elaborated Definition.") {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutDef = getAddOneDefinition(testDir)
+
+ class Testbench(defn: Definition[AddOne]) extends Module {
+ val mod = Module(new AddOne)
+ val inst = Instance(defn)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ mod.in := 0.U
+ inst.in := 0.U
+ dontTouch(mod.out)
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef)
+ )
+ )
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("module AddOne_1(")
+ tb_rtl should include("AddOne_1 mod (")
+ (tb_rtl should not).include("module AddOne(")
+ tb_rtl should include("AddOne inst (")
+ }
+
+ it(
+ "(0.b): should not occur between an Instance of a Definition and an Instance of a previously elaborated Definition."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutDef = getAddOneDefinition(testDir)
+
+ class Testbench(defn: Definition[AddOne]) extends Module {
+ val inst0 = Instance(Definition(new AddOne))
+ val inst1 = Instance(defn)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ dontTouch(inst0.out)
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef)
+ )
+ )
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("module AddOne_1(")
+ tb_rtl should include("AddOne_1 inst0 (")
+ (tb_rtl should not).include("module AddOne(")
+ tb_rtl should include("AddOne inst1 (")
+ }
+ }
+
+ describe("(1): Repeat Module definitions") {
+ it("(1.a): should not occur when elaborating multiple Instances separately from its Definition.") {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutDef = getAddOneDefinition(testDir)
+
+ class Testbench(defn: Definition[AddOne]) extends Module {
+ val inst0 = Instance(defn)
+ val inst1 = Instance(defn)
+
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ // If there is a repeat module definition, FIRRTL emission will fail
+ (new ChiselStage).emitFirrtl(
+ gen = new Testbench(dutDef),
+ args = Array("-td", testDir, "--full-stacktrace"),
+ annotations = Seq(ImportDefinitionAnnotation(dutDef))
+ )
+ }
+ }
+
+ describe("(2): Multiple imported Definitions of modules without submodules") {
+ it(
+ "(2.a): should work if a list of imported Definitions is passed between Stages."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(4)),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(8)),
+ TargetDirAnnotation(s"$testDir/dutDef1"),
+ // pass in previously elaborated Definitions
+ ImportDefinitionAnnotation(dutDef0)
+ )
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ class Testbench(defn0: Definition[AddOneParameterized], defn1: Definition[AddOneParameterized]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef0),
+ ImportDefinitionAnnotation(dutDef1)
+ )
+ )
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddOneParameterized.v").getLines.mkString
+ dutDef0_rtl should include("module AddOneParameterized(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddOneParameterized_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOneParameterized_1(")
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("AddOneParameterized inst0 (")
+ tb_rtl should include("AddOneParameterized_1 inst1 (")
+ (tb_rtl should not).include("module AddOneParameterized(")
+ (tb_rtl should not).include("module AddOneParameterized_1(")
+ }
+
+ it(
+ "(2.b): should throw an exception if information is not passed between Stages."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(4)),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(8)),
+ TargetDirAnnotation(s"$testDir/dutDef1")
+ )
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ class Testbench(defn0: Definition[AddOneParameterized], defn1: Definition[AddOneParameterized]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ // Because these elaborations have no knowledge of each other, they create
+ // modules of the same name
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddOneParameterized.v").getLines.mkString
+ dutDef0_rtl should include("module AddOneParameterized(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddOneParameterized.v").getLines.mkString
+ dutDef1_rtl should include("module AddOneParameterized(")
+
+ val errMsg = intercept[ChiselException] {
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef0),
+ ImportDefinitionAnnotation(dutDef1)
+ )
+ )
+ }
+ errMsg.getMessage should include(
+ "Expected distinct imported Definition names but found duplicates for: AddOneParameterized"
+ )
+ }
+ }
+
+ describe("(3): Multiple imported Definitions of modules with submodules") {
+ it(
+ "(3.a): should work if a list of imported Definitions for all modules is passed between Stages."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddTwoMixedModules),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddTwoMixedModules].toDefinition
+ val importDefinitionAnnos0 = allModulesToImportedDefs(dutAnnos0)
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddTwoMixedModules),
+ TargetDirAnnotation(s"$testDir/dutDef1")
+ ) ++ importDefinitionAnnos0
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddTwoMixedModules].toDefinition
+ val importDefinitionAnnos1 = allModulesToImportedDefs(dutAnnos1)
+
+ class Testbench(defn0: Definition[AddTwoMixedModules], defn1: Definition[AddTwoMixedModules]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddTwoMixedModules.v").getLines.mkString
+ dutDef0_rtl should include("module AddOne(")
+ dutDef0_rtl should include("module AddTwoMixedModules(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddTwoMixedModules_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOne_2(")
+ dutDef1_rtl should include("module AddTwoMixedModules_1(")
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir)
+ ) ++ importDefinitionAnnos0 ++ importDefinitionAnnos1
+ )
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("AddTwoMixedModules inst0 (")
+ tb_rtl should include("AddTwoMixedModules_1 inst1 (")
+ (tb_rtl should not).include("module AddTwoMixedModules(")
+ (tb_rtl should not).include("module AddTwoMixedModules_1(")
+ }
+ }
+
+ it(
+ "(3.b): should throw an exception if submodules are not passed between Definition elaborations."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddTwoMixedModules),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddTwoMixedModules].toDefinition
+ val importDefinitionAnnos0 = allModulesToImportedDefs(dutAnnos0)
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddTwoMixedModules),
+ ImportDefinitionAnnotation(dutDef0),
+ TargetDirAnnotation(s"$testDir/dutDef1")
+ )
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddTwoMixedModules].toDefinition
+ val importDefinitionAnnos1 = allModulesToImportedDefs(dutAnnos1)
+
+ class Testbench(defn0: Definition[AddTwoMixedModules], defn1: Definition[AddTwoMixedModules]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddTwoMixedModules.v").getLines.mkString
+ dutDef0_rtl should include("module AddOne(")
+ dutDef0_rtl should include("module AddTwoMixedModules(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddTwoMixedModules_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOne(")
+ dutDef1_rtl should include("module AddTwoMixedModules_1(")
+
+ val errMsg = intercept[ChiselException] {
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir)
+ ) ++ importDefinitionAnnos0 ++ importDefinitionAnnos1
+ )
+ }
+ errMsg.getMessage should include(
+ "Expected distinct imported Definition names but found duplicates for: AddOne"
+ )
+ }
+
+ describe("(4): With ExtMod Names") {
+ it("(4.a): should pick correct ExtMod names when passed") {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutDef = getAddOneDefinition(testDir)
+
+ class Testbench(defn: Definition[AddOne]) extends Module {
+ val mod = Module(new AddOne)
+ val inst = Instance(defn)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ mod.in := 0.U
+ inst.in := 0.U
+ dontTouch(mod.out)
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef, Some("CustomPrefix_AddOne_CustomSuffix"))
+ )
+ )
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+
+ tb_rtl should include("module AddOne_1(")
+ tb_rtl should include("AddOne_1 mod (")
+ (tb_rtl should not).include("module AddOne(")
+ tb_rtl should include("CustomPrefix_AddOne_CustomSuffix inst (")
+ }
+ }
+
+ it(
+ "(4.b): should work if a list of imported Definitions is passed between Stages with ExtModName."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(4)),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(8)),
+ TargetDirAnnotation(s"$testDir/dutDef1"),
+ // pass in previously elaborated Definitions
+ ImportDefinitionAnnotation(dutDef0)
+ )
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ class Testbench(defn0: Definition[AddOneParameterized], defn1: Definition[AddOneParameterized]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef0, Some("Inst1_Prefix_AddOnePramaterized_Inst1_Suffix")),
+ ImportDefinitionAnnotation(dutDef1, Some("Inst2_Prefix_AddOnePrameterized_1_Inst2_Suffix"))
+ )
+ )
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddOneParameterized.v").getLines.mkString
+ dutDef0_rtl should include("module AddOneParameterized(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddOneParameterized_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOneParameterized_1(")
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("Inst1_Prefix_AddOnePramaterized_Inst1_Suffix inst0 (")
+ tb_rtl should include("Inst2_Prefix_AddOnePrameterized_1_Inst2_Suffix inst1 (")
+ (tb_rtl should not).include("module AddOneParameterized(")
+ (tb_rtl should not).include("module AddOneParameterized_1(")
+ }
+
+ it(
+ "(4.c): should throw an exception if a list of imported Definitions is passed between Stages with same ExtModName."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(4)),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val importDefinitionAnnos0 = allModulesToImportedDefs(dutAnnos0)
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(8)),
+ TargetDirAnnotation(s"$testDir/dutDef1"),
+ // pass in previously elaborated Definitions
+ ImportDefinitionAnnotation(dutDef0)
+ )
+ )
+ val importDefinitionAnnos1 = allModulesToImportedDefs(dutAnnos1)
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ class Testbench(defn0: Definition[AddOneParameterized], defn1: Definition[AddOneParameterized]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddOneParameterized.v").getLines.mkString
+ dutDef0_rtl should include("module AddOneParameterized(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddOneParameterized_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOneParameterized_1(")
+
+ val errMsg = intercept[ChiselException] {
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef0, Some("Inst1_Prefix_AddOnePrameterized_Inst1_Suffix")),
+ ImportDefinitionAnnotation(dutDef1, Some("Inst1_Prefix_AddOnePrameterized_Inst1_Suffix"))
+ )
+ )
+ }
+ errMsg.getMessage should include(
+ "Expected distinct overrideDef names but found duplicates for: Inst1_Prefix_AddOnePrameterized_Inst1_Suffix"
+ )
+ }
+}
diff --git a/src/test/scala/chiselTests/naming/NamePluginSpec.scala b/src/test/scala/chiselTests/naming/NamePluginSpec.scala
index 18359fd2..a787bb80 100644
--- a/src/test/scala/chiselTests/naming/NamePluginSpec.scala
+++ b/src/test/scala/chiselTests/naming/NamePluginSpec.scala
@@ -3,6 +3,7 @@
package chiselTests.naming
import chisel3._
+import chisel3.stage.ChiselStage
import chisel3.aop.Select
import chisel3.experimental.{prefix, treedump}
import chiselTests.{ChiselFlatSpec, Utils}
@@ -69,6 +70,24 @@ class NamePluginSpec extends ChiselFlatSpec with Utils {
}
}
+ "Scala plugin" should "name verification ops" in {
+ class Test extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+
+ {
+ val x1 = chisel3.assert(1.U === 1.U)
+ val x2 = cover(foo =/= bar)
+ val x3 = chisel3.assume(foo =/= 123.U)
+ val x4 = printf("foo = %d\n", foo)
+ }
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new Test)
+ (chirrtl should include).regex("assert.*: x1")
+ (chirrtl should include).regex("cover.*: x2")
+ (chirrtl should include).regex("assume.*: x3")
+ (chirrtl should include).regex("printf.*: x4")
+ }
+
"Naming on option" should "work" in {
class Test extends Module {
@@ -321,4 +340,23 @@ class NamePluginSpec extends ChiselFlatSpec with Utils {
Select.wires(top).map(_.instanceName) should be(List("a_b_c", "a_b", "a"))
}
}
+
+ behavior.of("Unnamed values (aka \"Temporaries\")")
+
+ they should "be declared by starting the name with '_'" in {
+ class Test extends Module {
+ {
+ val a = {
+ val b = {
+ val _c = Wire(UInt(3.W))
+ 4.U // literal so there is no name
+ }
+ b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("_a_b_c"))
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/naming/PrefixSpec.scala b/src/test/scala/chiselTests/naming/PrefixSpec.scala
index f9a78f0e..6d52407e 100644
--- a/src/test/scala/chiselTests/naming/PrefixSpec.scala
+++ b/src/test/scala/chiselTests/naming/PrefixSpec.scala
@@ -3,6 +3,7 @@
package chiselTests.naming
import chisel3._
+import chisel3.stage.ChiselStage
import chisel3.aop.Select
import chisel3.experimental.{dump, noPrefix, prefix, treedump}
import chiselTests.{ChiselPropSpec, Utils}
@@ -232,18 +233,46 @@ class PrefixSpec extends ChiselPropSpec with Utils {
}
}
- property("Prefixing should be the prefix during the last call to autoName/suggestName") {
+ property("Prefixing should NOT be influenced by suggestName") {
class Test extends Module {
{
val wire = {
- val x = Wire(UInt(3.W)).suggestName("mywire")
- x
+ val x = Wire(UInt(3.W)) // wire_x
+ Wire(UInt(3.W)).suggestName("foo")
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("wire_x", "foo"))
+ }
+ }
+
+ property("Prefixing should be influenced by the \"current name\" of the signal") {
+ class Test extends Module {
+ {
+ val wire = {
+ val y = Wire(UInt(3.W)).suggestName("foo")
+ val x = Wire(UInt(3.W)) // wire_x
+ y
+ }
+
+ val wire2 = Wire(UInt(3.W))
+ wire2 := {
+ val x = Wire(UInt(3.W)) // wire2_x
+ x + 1.U
+ }
+ wire2.suggestName("bar")
+
+ val wire3 = Wire(UInt(3.W))
+ wire3.suggestName("fizz")
+ wire3 := {
+ val x = Wire(UInt(3.W)) // fizz_x
+ x + 1.U
}
}
}
aspectTest(() => new Test) { top: Test =>
- Select.wires(top).map(_.instanceName) should be(List("mywire"))
- Select.wires(top).map(_.instanceName) shouldNot be(List("wire_mywire"))
+ Select.wires(top).map(_.instanceName) should be(List("foo", "wire_x", "bar", "wire2_x", "fizz", "fizz_x"))
}
}
@@ -391,6 +420,81 @@ class PrefixSpec extends ChiselPropSpec with Utils {
aspectTest(() => new Test) { top: Test =>
Select.wires(top).map(_.instanceName) should be(List("x", "x_w_w", "x_w_w_w", "x_w_w_w_w"))
}
+ }
+
+ property("Prefixing should work for verification ops") {
+ class Test extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+
+ {
+ val x5 = {
+ val x1 = chisel3.assert(1.U === 1.U)
+ val x2 = cover(foo =/= bar)
+ val x3 = chisel3.assume(foo =/= 123.U)
+ val x4 = printf("foo = %d\n", foo)
+ x1
+ }
+ }
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new Test)
+ (chirrtl should include).regex("assert.*: x5")
+ (chirrtl should include).regex("cover.*: x5_x2")
+ (chirrtl should include).regex("assume.*: x5_x3")
+ (chirrtl should include).regex("printf.*: x5_x4")
+ }
+ property("Leading '_' in val names should be ignored in prefixes") {
+ class Test extends Module {
+ {
+ val a = {
+ val _b = {
+ val c = Wire(UInt(3.W))
+ 4.U // literal because there is no name
+ }
+ _b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a_b_c"))
+ }
+ }
+
+ // This checks that we don't just blanket ignore leading _ in prefixes
+ property("User-specified prefixes with '_' should be respected") {
+ class Test extends Module {
+ {
+ val a = {
+ val _b = prefix("_b") {
+ val c = Wire(UInt(3.W))
+ }
+ 4.U
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a__b_c"))
+ }
+ }
+
+ property("Leading '_' in signal names should be ignored in prefixes from connections") {
+ class Test extends Module {
+ {
+ val a = {
+ val b = {
+ val _c = IO(Output(UInt(3.W))) // port so not selected as wire
+ _c := {
+ val d = Wire(UInt(3.W))
+ d
+ }
+ 4.U // literal so there is no name
+ }
+ b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a_b_c_d"))
+ }
}
}
diff --git a/src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala b/src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala
new file mode 100644
index 00000000..baa991dd
--- /dev/null
+++ b/src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests.naming
+
+import chisel3._
+import chiselTests.{ChiselFlatSpec, Utils}
+
+class ReflectiveNamingSpec extends ChiselFlatSpec with Utils {
+
+ behavior.of("Reflective naming")
+
+ private def emitChirrtl(gen: => RawModule): String = {
+ // Annoyingly need to emit files to use CLI
+ val targetDir = createTestDirectory(this.getClass.getSimpleName).toString
+ val args = Array("--warn:reflective-naming", "-td", targetDir)
+ (new chisel3.stage.ChiselStage).emitChirrtl(gen, args)
+ }
+
+ it should "NOT warn when no names are changed" in {
+ class Example extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ val sum = foo +& bar
+ out := sum
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ chirrtl should include("node sum = add(foo, bar)")
+ }
+
+ it should "warn when changing the name of a node" in {
+ class Example extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ val sum = foo +& bar
+ val fuzz = sum
+ out := sum
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'sum' is renamed by reflection to 'fuzz'")
+ chirrtl should include("node fuzz = add(foo, bar)")
+ }
+
+ // This also checks correct prefix reversing
+ it should "warn when changing the name of a node with a prefix in the name" in {
+ class Example extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ // This is sketch, don't do this
+ var fuzz = 0.U
+ out := {
+ val sum = {
+ val node = foo +& bar
+ fuzz = node
+ node +% 0.U
+ }
+ sum
+ }
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'out_sum_node' is renamed by reflection to 'fuzz'")
+ chirrtl should include("node fuzz = add(foo, bar)")
+ }
+
+ it should "warn when changing the name of a Module instance" in {
+ import chisel3.util._
+ class Example extends Module {
+ val enq = IO(Flipped(Decoupled(UInt(8.W))))
+ val deq = IO(Decoupled(UInt(8.W)))
+
+ val q = Module(new Queue(UInt(8.W), 4))
+ q.io.enq <> enq
+ deq <> q.io.deq
+
+ val fuzz = q
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'q' is renamed by reflection to 'fuzz'")
+ chirrtl should include("inst fuzz of Queue")
+ }
+
+ it should "warn when changing the name of an Instance" in {
+ import chisel3.experimental.hierarchy.{Definition, Instance}
+ import chiselTests.experimental.hierarchy.Examples.AddOne
+ class Example extends Module {
+ val defn = Definition(new AddOne)
+ val inst = Instance(defn)
+ val fuzz = inst
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'inst' is renamed by reflection to 'fuzz'")
+ chirrtl should include("inst fuzz of AddOne")
+ }
+
+ it should "warn when changing the name of a Mem" in {
+ class Example extends Module {
+ val mem = SyncReadMem(8, UInt(8.W))
+
+ val fuzz = mem
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'mem' is renamed by reflection to 'fuzz'")
+ chirrtl should include("smem fuzz")
+ }
+
+ it should "NOT warn when changing the name of a verification statement" in {
+ class Example extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val z = chisel3.assert(in =/= 123.U)
+ val fuzz = z
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ // But the name is actually changed
+ (chirrtl should include).regex("assert.*: fuzz")
+ }
+
+ it should "NOT warn when \"naming\" a literal" in {
+ class Example extends Module {
+ val out = IO(Output(UInt(8.W)))
+
+ val sum = 0.U
+ val fuzz = sum
+ out := sum
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ chirrtl should include("out <= UInt")
+ }
+
+ it should "NOT warn when \"naming\" a field of an Aggregate" in {
+ class Example extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ val in = io.in
+ val out = io.out
+ out := in
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ chirrtl should include("io.out <= io.in")
+ }
+
+ it should "NOT warn when \"naming\" unbound Data" in {
+ class Example extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ val z = UInt(8.W)
+ val a = z
+ out := in
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ chirrtl should include("out <= in")
+ }
+}
diff --git a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
index fa2c6f08..9b2dd600 100644
--- a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
+++ b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
@@ -104,4 +104,21 @@ class TruthTableSpec extends AnyFlatSpec {
assert(t.toString contains "111->?")
assert(t.toString contains " 0")
}
+
+ "Using TruthTable.fromEspressoOutput" should "merge rows on conflict" in {
+ val mapping = List(
+ (BitPat("b110"), BitPat("b001")),
+ (BitPat("b111"), BitPat("b001")),
+ (BitPat("b111"), BitPat("b010")),
+ (BitPat("b111"), BitPat("b100"))
+ )
+
+ assert(
+ TruthTable.fromEspressoOutput(mapping, BitPat("b?")) ==
+ TruthTable.fromString("""110->001
+ |111->111
+ |?
+ |""".stripMargin)
+ )
+ }
}