summaryrefslogtreecommitdiff
path: root/src/test/scala
diff options
context:
space:
mode:
authorJack2022-11-11 06:53:04 +0000
committerJack2022-11-11 06:53:04 +0000
commit3ce953c81f06519351c48277e3474b5720ec07ff (patch)
treeac79dcb80d0528c2ae86ca21da4cf424715ab645 /src/test/scala
parentadccde9998c91875e5490cff6d5822ffacc593ed (diff)
parentc8046636a25474be4c547c6fe9c6d742ea7b1d13 (diff)
Merge branch '3.5.x' into 3.5-release
Diffstat (limited to 'src/test/scala')
-rw-r--r--src/test/scala/chiselTests/Assert.scala118
-rw-r--r--src/test/scala/chiselTests/AutoClonetypeSpec.scala41
-rw-r--r--src/test/scala/chiselTests/BulkConnectSpec.scala15
-rw-r--r--src/test/scala/chiselTests/ChiselSpec.scala5
-rw-r--r--src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala427
-rw-r--r--src/test/scala/chiselTests/CompatibilitySpec.scala22
-rw-r--r--src/test/scala/chiselTests/DataEqualitySpec.scala257
-rw-r--r--src/test/scala/chiselTests/Direction.scala145
-rw-r--r--src/test/scala/chiselTests/ExtModule.scala17
-rw-r--r--src/test/scala/chiselTests/IntervalSpec.scala7
-rw-r--r--src/test/scala/chiselTests/MultiClockSpec.scala8
-rw-r--r--src/test/scala/chiselTests/Printf.scala39
-rw-r--r--src/test/scala/chiselTests/RecordSpec.scala213
-rw-r--r--src/test/scala/chiselTests/StrongEnum.scala68
-rw-r--r--src/test/scala/chiselTests/ToTargetSpec.scala17
-rw-r--r--src/test/scala/chiselTests/Vec.scala8
-rw-r--r--src/test/scala/chiselTests/VecLiteralSpec.scala4
-rw-r--r--src/test/scala/chiselTests/WarningSpec.scala42
-rw-r--r--src/test/scala/chiselTests/WireSpec.scala16
-rw-r--r--src/test/scala/chiselTests/aop/InjectionSpec.scala1
-rw-r--r--src/test/scala/chiselTests/experimental/DataMirrorSpec.scala33
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala34
-rw-r--r--src/test/scala/chiselTests/experimental/FlatIOSpec.scala17
-rw-r--r--src/test/scala/chiselTests/experimental/ForceNames.scala17
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/Examples.scala66
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala10
-rw-r--r--src/test/scala/chiselTests/naming/PrefixSpec.scala50
27 files changed, 1655 insertions, 42 deletions
diff --git a/src/test/scala/chiselTests/Assert.scala b/src/test/scala/chiselTests/Assert.scala
index 1849ddf8..5e7b6496 100644
--- a/src/test/scala/chiselTests/Assert.scala
+++ b/src/test/scala/chiselTests/Assert.scala
@@ -61,6 +61,87 @@ class BadUnescapedPercentAssertTester extends BasicTester {
stop()
}
+class PrintableFormattedAssertTester extends BasicTester {
+ val foobar = Wire(UInt(32.W))
+ foobar := 123.U
+ assert(foobar === 123.U, cf"Error! Wire foobar =/= $foobar%x This is 100%% wrong.\n")
+ stop()
+}
+
+class PrintableBadUnescapedPercentAssertTester extends BasicTester {
+ assert(1.U === 1.U, p"I'm 110% sure this is an invalid message")
+ stop()
+}
+
+class PrintableAssumeTester extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ val w = Wire(UInt(8.W))
+ w := 255.U
+ assume(w === 255.U, cf"Assumption failed, Wire w =/= $w%x")
+
+ out := in
+}
+
+class PrintableScopeTester extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ out := in
+
+ val w = Wire(UInt(8.W))
+ w := 255.U
+
+ val printableWire = cf"$w"
+ val printablePort = cf"$in"
+}
+
+class AssertPrintableWireScope extends BasicTester {
+ val mod = Module(new PrintableScopeTester)
+ assert(1.U === 2.U, mod.printableWire)
+ stop()
+}
+
+class AssertPrintablePortScope extends BasicTester {
+ val mod = Module(new PrintableScopeTester)
+ mod.in := 255.U
+ assert(1.U === 1.U, mod.printablePort)
+ stop()
+}
+
+class AssertPrintableFailingWhenScope extends BasicTester {
+ val mod = Module(new PrintableWhenScopeTester)
+ assert(1.U === 1.U, mod.printable)
+ stop()
+}
+
+class AssumePrintableWireScope extends BasicTester {
+ val mod = Module(new PrintableScopeTester)
+ assume(1.U === 1.U, mod.printableWire)
+ stop()
+}
+
+class AssumePrintablePortScope extends BasicTester {
+ val mod = Module(new PrintableScopeTester)
+ mod.in := 255.U
+ assume(1.U === 1.U, mod.printablePort)
+ stop()
+}
+
+class PrintableWhenScopeTester extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ out := in
+
+ val w = Wire(UInt(8.W))
+ w := 255.U
+ var printable = cf""
+ when(true.B) {
+ printable = cf"$w"
+ }
+}
+
class AssertSpec extends ChiselFlatSpec with Utils {
"A failing assertion" should "fail the testbench" in {
assert(!runTester { new FailingAssertTester })
@@ -71,12 +152,37 @@ class AssertSpec extends ChiselFlatSpec with Utils {
"An assertion" should "not assert until we come out of reset" in {
assertTesterPasses { new PipelinedResetTester }
}
+
+ "Assert Printables" should "respect port scoping" in {
+ assertTesterPasses { new AssertPrintablePortScope }
+ }
+ "Assert Printables" should "respect wire scoping" in {
+ a[ChiselException] should be thrownBy { ChiselStage.elaborate(new AssertPrintableWireScope) }
+ }
+ "Assume Printables" should "respect port scoping" in {
+ assertTesterPasses { new AssumePrintablePortScope }
+ }
+
+ "Assume Printables" should "respect wire scoping" in {
+ a[ChiselException] should be thrownBy { ChiselStage.elaborate(new AssumePrintableWireScope) }
+ }
+
+ "Assert Printables" should "respect when scope" in {
+ a[ChiselException] should be thrownBy { ChiselStage.elaborate(new AssertPrintableFailingWhenScope) }
+ }
+
"Assertions" should "allow the modulo operator % in the message" in {
assertTesterPasses { new ModuloAssertTester }
}
they should "allow printf-style format strings with arguments" in {
assertTesterPasses { new FormattedAssertTester }
}
+ they should "allow printf-style format strings in Assumes" in {
+ val chirrtl = ChiselStage.emitChirrtl(new PrintableAssumeTester)
+ chirrtl should include(
+ """assume(w === 255.U, cf\"Assumption failed, Wire w =/= $w%%%%x\")\n", w)"""
+ )
+ }
they should "not allow unescaped % in the message" in {
a[java.util.UnknownFormatConversionException] should be thrownBy {
extractCause[java.util.UnknownFormatConversionException] {
@@ -84,4 +190,16 @@ class AssertSpec extends ChiselFlatSpec with Utils {
}
}
}
+
+ they should "allow printable format strings with arguments" in {
+ assertTesterPasses { new FormattedAssertTester }
+ }
+ they should "not allow unescaped % in the printable message" in {
+ a[java.util.UnknownFormatConversionException] should be thrownBy {
+ extractCause[java.util.UnknownFormatConversionException] {
+ ChiselStage.elaborate { new BadUnescapedPercentAssertTester }
+ }
+ }
+ }
+
}
diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
index 5d2cd496..353ae58c 100644
--- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala
+++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
@@ -6,6 +6,8 @@ import chisel3._
import chisel3.testers.TestUtils
import chisel3.util.QueueIO
import chisel3.stage.ChiselStage.elaborate
+import chisel3.experimental.AutoCloneType
+import scala.collection.immutable.ListMap
class BundleWithIntArg(val i: Int) extends Bundle {
val out = UInt(i.W)
@@ -72,6 +74,25 @@ class InheritingBundle extends QueueIO(UInt(8.W), 8) {
val error = Output(Bool())
}
+class RecordAutoCloneType[T <: Data](gen: T) extends Record with AutoCloneType {
+ lazy val elements = ListMap("value" -> gen)
+ // This is a weird thing to do, but as only Bundles have these methods, it should be legal
+ protected def _elementsImpl: Iterable[(String, Any)] = elements
+ protected def _usingPlugin = false
+}
+
+// Records that don't mixin AutoCloneType should still be able to implement the related methods
+// NOTE: This is a very weird thing to do, don't do it.
+class RecordWithVerbotenMethods(w: Int) extends Record {
+ lazy val elements = ListMap("value" -> UInt(w.W))
+ override def cloneType: this.type = (new RecordWithVerbotenMethods(w)).asInstanceOf[this.type]
+ // Verboten methods
+ protected def _usingPlugin = false
+ protected override def _cloneTypeImpl = this.cloneType
+
+ protected def _elementsImpl: Iterable[(String, Any)] = Nil
+}
+
class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Bundles with Scala args" should "not need clonetype" in {
@@ -400,4 +421,24 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
}
elaborate(new MyModule)
}
+
+ it should "support Records that mixin AutoCloneType" in {
+ class MyModule extends Module {
+ val gen = new RecordAutoCloneType(UInt(8.W))
+ val in = IO(Input(gen))
+ val out = IO(Output(gen))
+ out := in
+ }
+ elaborate(new MyModule)
+ }
+
+ it should "support Records that don't mixin AutoCloneType and use forbidden methods" in {
+ class MyModule extends Module {
+ val gen = new RecordWithVerbotenMethods(8)
+ val in = IO(Input(gen))
+ val out = IO(Output(gen))
+ out := in
+ }
+ elaborate(new MyModule)
+ }
}
diff --git a/src/test/scala/chiselTests/BulkConnectSpec.scala b/src/test/scala/chiselTests/BulkConnectSpec.scala
index 281890d4..0a1616d3 100644
--- a/src/test/scala/chiselTests/BulkConnectSpec.scala
+++ b/src/test/scala/chiselTests/BulkConnectSpec.scala
@@ -54,7 +54,15 @@ class BulkConnectSpec extends ChiselPropSpec {
})
chirrtl should include("out.buzz.foo <= in.buzz.foo")
+ chirrtl should include("out.fizz <= in.fizz")
+ chirrtl should include("deq.bits <- enq.bits")
+ chirrtl should include("deq.valid <= enq.valid")
+ chirrtl should include("enq.ready <= deq.ready")
+
chirrtl shouldNot include("deq <= enq")
+ chirrtl shouldNot include("deq.bits.foo <= enq.bits.foo")
+ chirrtl shouldNot include("deq.bits.foo <- enq.bits.foo")
+ chirrtl shouldNot include("deq.bits.bar")
}
property("Chisel connects should not emit FIRRTL bulk connects between differing FIRRTL types") {
@@ -74,7 +82,9 @@ class BulkConnectSpec extends ChiselPropSpec {
out <> in
})
// out <- in is illegal FIRRTL
- chirrtl should include("out.foo.bar <= in.foo.bar")
+ exactly(2, chirrtl.split('\n')) should include("out.foo.bar <= in.foo.bar")
+ chirrtl shouldNot include("out <= in")
+ chirrtl shouldNot include("out <- in")
}
property("Chisel connects should not emit a FIRRTL bulk connect for a bidirectional MonoConnect") {
@@ -91,6 +101,9 @@ class BulkConnectSpec extends ChiselPropSpec {
})
chirrtl shouldNot include("wire <= enq")
+ chirrtl should include("wire.bits <= enq.bits")
+ chirrtl should include("wire.valid <= enq.valid")
+ chirrtl should include("wire.ready <= enq.ready")
chirrtl should include("deq <= enq")
}
diff --git a/src/test/scala/chiselTests/ChiselSpec.scala b/src/test/scala/chiselTests/ChiselSpec.scala
index 6f560b94..e00afcf6 100644
--- a/src/test/scala/chiselTests/ChiselSpec.scala
+++ b/src/test/scala/chiselTests/ChiselSpec.scala
@@ -38,7 +38,10 @@ trait ChiselRunners extends Assertions with BackendCompilationUtilities {
annotations: AnnotationSeq = Seq()
): Boolean = {
// Change this to enable Treadle as a backend
- val defaultBackend = chisel3.testers.TesterDriver.defaultBackend
+ val defaultBackend = {
+ val useTreadle = sys.env.get("CHISEL3_CI_USE_TREADLE").isDefined
+ if (useTreadle) chisel3.testers.TreadleBackend else chisel3.testers.TesterDriver.defaultBackend
+ }
val hasBackend = TestUtils.containsBackend(annotations)
val annos: Seq[Annotation] = if (hasBackend) annotations else defaultBackend +: annotations
TesterDriver.execute(() => t, additionalVResources, annos)
diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
index 1e199297..d388c093 100644
--- a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
@@ -3,6 +3,7 @@
package chiselTests
import scala.collection.immutable.ListMap
+import chisel3.stage.ChiselStage.emitChirrtl
// Keep Chisel._ separate from chisel3._ below
object CompatibilityComponents {
@@ -390,4 +391,430 @@ class CompatibilityInteroperabilitySpec extends ChiselFlatSpec {
compile(new Top(true))
compile(new Top(false))
}
+
+ "A Chisel.Bundle with only unspecified directions" should "work with D/I" in {
+
+ object Compat {
+ import Chisel._
+ import chisel3.experimental.hierarchy.{instantiable, public}
+
+ class CompatBiDirUnspecifiedBundle extends Bundle {
+ val out = Bool()
+ val in = Flipped(Bool())
+ }
+
+ @instantiable
+ class CompatModule extends Module {
+ @public val io = IO(new CompatBiDirUnspecifiedBundle)
+ }
+ }
+
+ object Chisel3 {
+ import chisel3._
+ import chisel3.experimental.hierarchy.Instance
+ class Example extends Module {
+ val mod = Module(new Compat.CompatModule())
+ mod.io.in <> DontCare
+ val inst = Instance(mod.toDefinition)
+ inst.io.in <> mod.io.out
+ mod.io.in <> inst.io.out
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A Chisel.Bundle with mixed Specified and Unspecified directions" should "work with D/I" in {
+
+ object Compat {
+ import Chisel._
+ import chisel3.experimental.hierarchy.{instantiable, public}
+
+ class CompatBiDirMixedBundle extends Bundle {
+ val out = Bool()
+ val in = Flipped(Bool())
+ val explicit = Output(Bool())
+ }
+
+ @instantiable
+ class CompatModule extends Module {
+ @public val io = IO(new CompatBiDirMixedBundle)
+ }
+ }
+
+ object Chisel3 {
+ import chisel3._
+ import chisel3.experimental.hierarchy.Instance
+ class Example extends Module {
+ val mod = Module(new Compat.CompatModule)
+ mod.io.in <> DontCare
+ val inst = Instance(mod.toDefinition)
+ inst.io.in <> mod.io.out
+ mod.io.in <> inst.io.out
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A Chisel.Bundle with only unspecified vec direction" should "work with D/I" in {
+
+ object Compat {
+ import Chisel._
+ import chisel3.experimental.hierarchy.{instantiable, public}
+
+ class CompatBiDirUnspecifiedVecBundle extends Bundle {
+ val out = Vec(3, Bool())
+ val in = Flipped(Vec(3, Bool()))
+ }
+
+ @instantiable
+ class CompatModule extends Module {
+ @public val io = IO(new CompatBiDirUnspecifiedVecBundle)
+ }
+ }
+
+ object Chisel3 {
+ import chisel3._
+ import chisel3.experimental.hierarchy.Instance
+ class Example extends Module {
+ val mod = Module(new Compat.CompatModule())
+ mod.io.in <> DontCare
+ val inst = Instance(mod.toDefinition)
+ inst.io.in <> mod.io.out
+ mod.io.in <> inst.io.out
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A chisel3.Bundle with only unspecified directions" should "work with D/I" in {
+
+ object Chisel3 {
+ import chisel3._
+ import chisel3.experimental.hierarchy.{instantiable, public, Instance}
+
+ class BiDirUnspecifiedBundle extends Bundle {
+ val out = Bool()
+ val in = Flipped(Bool())
+ }
+
+ @instantiable
+ class MyModule extends Module {
+ @public val io = IO(new BiDirUnspecifiedBundle)
+ io <> DontCare
+ }
+
+ class Example extends Module {
+ val mod = Module(new MyModule())
+ mod.io.in <> DontCare
+ val inst = Instance(mod.toDefinition)
+ inst.io.in <> mod.io.out
+ mod.io.in <> inst.io.out
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A chisel3.Bundle with mixed Specified and Unspecified directions" should "work with D/I" in {
+
+ object Chisel3 {
+ import chisel3._
+ import chisel3.experimental.hierarchy.{instantiable, public, Instance}
+
+ class BiDirMixedBundle extends Bundle {
+ val out = Bool()
+ val in = Flipped(Bool())
+ val explicit = Output(Bool())
+ }
+
+ @instantiable
+ class MyModule extends Module {
+ @public val io = IO(new BiDirMixedBundle)
+ io <> DontCare
+ }
+ class Example extends Module {
+ val mod = Module(new MyModule)
+ mod.io.in <> DontCare
+ val inst = Instance(mod.toDefinition)
+ inst.io.in <> mod.io.out
+ mod.io.in <> inst.io.out
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A chisel3.Bundle with only unspecified vec direction" should "work with D/I" in {
+
+ object Chisel3 {
+ import chisel3._
+ import chisel3.experimental.hierarchy.{instantiable, public, Instance}
+
+ class BiDirUnspecifiedVecBundle extends Bundle {
+ val out = Vec(3, Bool())
+ val in = Flipped(Vec(3, Bool()))
+ }
+
+ @instantiable
+ class MyModule extends Module {
+ @public val io = IO(new BiDirUnspecifiedVecBundle)
+ io <> DontCare
+ }
+
+ class Example extends Module {
+ val mod = Module(new MyModule())
+ mod.io.in <> DontCare
+ val inst = Instance(mod.toDefinition)
+ inst.io.in <> mod.io.out
+ mod.io.in <> inst.io.out
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A chisel3.Bundle with only unspecified vec direction within an unspecified direction parent Bundle" should "work with D/I" in {
+
+ object Chisel3 {
+ import chisel3._
+ import chisel3.experimental.hierarchy.{instantiable, public, Instance}
+
+ class UnspecifiedVecBundle extends Bundle {
+ val vec = Vec(3, Bool())
+ }
+
+ class UnspecifiedParentBundle extends Bundle {
+ val out = new UnspecifiedVecBundle
+ }
+
+ @instantiable
+ class MyModule extends Module {
+ @public val io = IO(new UnspecifiedParentBundle)
+ io <> DontCare
+ }
+
+ class Example extends Module {
+ val mod = Module(new MyModule())
+
+ val wire = Wire(new UnspecifiedParentBundle)
+ wire.out.vec <> mod.io.out.vec
+ val inst = Instance(mod.toDefinition)
+ wire.out.vec <> inst.io.out.vec
+
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A undirectioned Chisel.Bundle used in a MixedVec " should "bulk connect in import chisel3._ code correctly" in {
+
+ object Compat {
+
+ import Chisel._
+ import chisel3.util.MixedVec
+
+ class ChiselModule extends Module {
+ val io = IO(new Bundle {
+ val out = MixedVec(Seq.fill(3) { Bool() })
+ val in = Flipped(MixedVec(Seq.fill(3) { Bool() }))
+ })
+ io.out := RegNext(io.in)
+ }
+
+ }
+ object Chisel3 {
+ import chisel3._
+
+ class Chisel3Module extends Compat.ChiselModule
+
+ class Example extends Module {
+ val oldMod = Module(new Compat.ChiselModule)
+ val newMod = Module(new Chisel3Module)
+
+ oldMod.io.in <> DontCare
+ newMod.io.in <> DontCare
+
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A undirectioned Chisel.Bundle with Records with undirectioned and directioned fields " should "work" in {
+
+ object Compat {
+
+ import Chisel._
+
+ class ChiselModule(gen: () => Data) extends Module {
+ val io = IO(new Bundle {
+ val mixed = new Chisel3.MyRecord(gen)
+ })
+ }
+
+ }
+ object Chisel3 {
+ import chisel3._
+ import scala.collection.immutable.SeqMap
+
+ class MyRecord(gen: () => Data) extends Record with chisel3.experimental.AutoCloneType {
+ val elements = SeqMap("genDirectioned" -> Output(gen()), "genUndirectioned" -> gen())
+ }
+
+ class Example extends Module {
+ val newMod = Module(new Compat.ChiselModule(() => Bool()))
+ }
+ }
+ compile(new Chisel3.Example)
+ }
+
+ "A BlackBox with Chisel._ fields in its IO" should "bulk connect in import chisel3._ code correctly" in {
+ object Compat {
+ import Chisel._
+ class LegacyChiselIO extends Bundle {
+ val foo = Output(Bool())
+ val bar = Output(Bool())
+ }
+ }
+ object Chisel3 {
+ import chisel3._
+ import chisel3.util.Valid
+
+ class FooModuleIO extends Bundle {
+ val quz = Input(new QuzIO)
+ val foo = Output(Bool())
+ val bar = Input(Bool())
+ }
+ class QuzIO extends Bundle {
+ val q = Flipped(Valid(new Compat.LegacyChiselIO))
+ }
+ class FooModule extends Module {
+ val io = IO(new FooModuleIO)
+ io <> DontCare
+ }
+ class FooMirrorBlackBox extends BlackBox {
+ val io = IO(Flipped(new FooModuleIO))
+ }
+ class Top extends Module {
+ val foo = Module(new FooModule)
+ val mirror = Module(new FooMirrorBlackBox)
+ foo.io <> mirror.io
+ }
+ }
+ val chirrtl = emitChirrtl(new Chisel3.Top)
+ chirrtl should include("foo.io.bar <= mirror.bar")
+ chirrtl should include("mirror.foo <= foo.io.foo")
+ chirrtl should include("foo.io.quz.q.bits <- mirror.quz.q.bits")
+ chirrtl should include("foo.io.quz.q.valid <= mirror.quz.q.valid")
+ }
+
+ "A chisel3.Bundle bulk connected to a Chisel Bundle in either direction" should "work even with mismatched fields" in {
+ object Compat {
+ import Chisel._
+ class FooBundle extends Bundle {
+ val foo = UInt(width = 8)
+ }
+ }
+ object Chisel3 {
+ import chisel3._
+ class BarBundle extends Bundle {
+ val bar = UInt(8.W)
+ }
+ class MyModule(swap: Boolean) extends Module {
+ val in = IO(Input(if (swap) new Compat.FooBundle else new BarBundle))
+ val out = IO(Output(if (swap) new BarBundle else new Compat.FooBundle))
+ out <> DontCare
+ out <> in
+ }
+ }
+ val chirrtl0 = emitChirrtl(new Chisel3.MyModule(true))
+ chirrtl0 shouldNot include("<=")
+ chirrtl0 should include("out <- in")
+ val chirrtl1 = emitChirrtl(new Chisel3.MyModule(true))
+ chirrtl1 shouldNot include("<=")
+ chirrtl1 should include("out <- in")
+ }
+
+ it should "work with missing fields in the Chisel._" in {
+ object Compat {
+ import Chisel._
+ class FooBundle extends Bundle {
+ val foo = UInt(width = 8)
+ }
+ }
+ object Chisel3 {
+ import chisel3._
+ class FooBarBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = UInt(8.W)
+ }
+
+ class MyModule(swap: Boolean) extends Module {
+ val in = IO(Input(if (swap) new Compat.FooBundle else new FooBarBundle))
+ val out = IO(Output(if (swap) new FooBarBundle else new Compat.FooBundle))
+ out <> DontCare
+ out <> in
+ }
+ }
+ val chirrtl0 = emitChirrtl(new Chisel3.MyModule(true))
+ chirrtl0 shouldNot include("<=")
+ chirrtl0 should include("out <- in")
+ val chirrtl1 = emitChirrtl(new Chisel3.MyModule(true))
+ chirrtl1 shouldNot include("<=")
+ chirrtl1 should include("out <- in")
+ }
+
+ it should "work with missing fields in the chisel3._" in {
+ object Compat {
+ import Chisel._
+ class FooBundle extends Bundle {
+ val foo = UInt(width = 8)
+ }
+ }
+ object Chisel3 {
+ import chisel3._
+ class FooBarBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = UInt(8.W)
+ }
+
+ class MyModule(swap: Boolean) extends Module {
+ val in = IO(Input(if (swap) new Compat.FooBundle else new FooBarBundle))
+ val out = IO(Output(if (swap) new FooBarBundle else new Compat.FooBundle))
+ out <> DontCare
+ out <> in
+ }
+ }
+ val chirrtl0 = emitChirrtl(new Chisel3.MyModule(true))
+ chirrtl0 shouldNot include("<=")
+ chirrtl0 should include("out <- in")
+ val chirrtl1 = emitChirrtl(new Chisel3.MyModule(true))
+ chirrtl1 shouldNot include("<=")
+ chirrtl1 should include("out <- in")
+ }
+
+ it should "emit FIRRTL connects if possible" in {
+ object Compat {
+ import Chisel._
+ class FooBarBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = Flipped(UInt(8.W))
+ }
+ }
+ object Chisel3 {
+ import chisel3._
+ class FooBarBundle extends Bundle {
+ val foo = Output(UInt(8.W))
+ val bar = Input(UInt(8.W))
+ }
+ class MyModule(swap: Boolean) extends Module {
+ val in = IO(Flipped((if (swap) new Compat.FooBarBundle else new FooBarBundle)))
+ val out = IO(if (swap) new FooBarBundle else new Compat.FooBarBundle)
+ out <> DontCare
+ out <> in
+ }
+ }
+ val chirrtl0 = emitChirrtl(new Chisel3.MyModule(true))
+ chirrtl0 should include("out <= in")
+ chirrtl0 shouldNot include("out <- in")
+ val chirrtl1 = emitChirrtl(new Chisel3.MyModule(true))
+ chirrtl1 should include("out <= in")
+ chirrtl1 shouldNot include("out <- in")
+ }
}
diff --git a/src/test/scala/chiselTests/CompatibilitySpec.scala b/src/test/scala/chiselTests/CompatibilitySpec.scala
index 41cfbec4..5a3b43e6 100644
--- a/src/test/scala/chiselTests/CompatibilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilitySpec.scala
@@ -614,4 +614,26 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck
ChiselStage.elaborate(new MyModule)
}
+ behavior.of("BlackBox")
+
+ it should "have invalidated ports in a compatibility context" in {
+ class ExtModuleInvalidatedTester extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ val inst = Module(new BlackBox {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ })
+ inst.io.in := io.in
+ io.out := inst.io.out
+ }
+
+ val chirrtl = ChiselStage.emitChirrtl(new ExtModuleInvalidatedTester)
+ chirrtl should include("inst.in is invalid")
+ chirrtl should include("inst.out is invalid")
+ }
}
diff --git a/src/test/scala/chiselTests/DataEqualitySpec.scala b/src/test/scala/chiselTests/DataEqualitySpec.scala
new file mode 100644
index 00000000..4ac3292d
--- /dev/null
+++ b/src/test/scala/chiselTests/DataEqualitySpec.scala
@@ -0,0 +1,257 @@
+package chiselTests
+
+import chisel3._
+import chisel3.experimental.VecLiterals._
+import chisel3.experimental.BundleLiterals._
+import chisel3.experimental.{Analog, ChiselEnum, ChiselRange, FixedPoint, Interval}
+import chisel3.stage.ChiselStage
+import chisel3.testers.BasicTester
+import chisel3.util.Valid
+
+class EqualityModule(lhsGen: => Data, rhsGen: => Data) extends Module {
+ val out = IO(Output(Bool()))
+
+ val lhs = lhsGen
+ val rhs = rhsGen
+
+ out := lhs === rhs
+}
+
+class EqualityTester(lhsGen: => Data, rhsGen: => Data) extends BasicTester {
+ val module = Module(new EqualityModule(lhsGen, rhsGen))
+
+ assert(module.out)
+
+ stop()
+}
+
+class AnalogBundle extends Bundle {
+ val analog = Analog(32.W)
+}
+
+class AnalogExceptionModule extends Module {
+ class AnalogExceptionModuleIO extends Bundle {
+ val bundle1 = new AnalogBundle
+ val bundle2 = new AnalogBundle
+ }
+
+ val io = IO(new AnalogExceptionModuleIO)
+}
+
+class AnalogExceptionTester extends BasicTester {
+ val module = Module(new AnalogExceptionModule)
+
+ module.io.bundle1 <> DontCare
+ module.io.bundle2 <> DontCare
+
+ assert(module.io.bundle1 === module.io.bundle2)
+
+ stop()
+}
+
+class DataEqualitySpec extends ChiselFlatSpec with Utils {
+ object MyEnum extends ChiselEnum {
+ val sA, sB = Value
+ }
+ object MyEnumB extends ChiselEnum {
+ val sA, sB = Value
+ }
+ class MyBundle extends Bundle {
+ val a = UInt(8.W)
+ val b = Bool()
+ val c = MyEnum()
+ }
+ class LongBundle extends Bundle {
+ val a = UInt(48.W)
+ val b = SInt(32.W)
+ val c = FixedPoint(16.W, 4.BP)
+ }
+ class RuntimeSensitiveBundle(gen: => Bundle) extends Bundle {
+ val a = UInt(8.W)
+ val b: Bundle = gen
+ }
+
+ behavior.of("UInt === UInt")
+ it should "pass with equal values" in {
+ assertTesterPasses {
+ new EqualityTester(0.U, 0.U)
+ }
+ }
+ it should "fail with differing values" in {
+ assertTesterFails {
+ new EqualityTester(0.U, 1.U)
+ }
+ }
+
+ behavior.of("SInt === SInt")
+ it should "pass with equal values" in {
+ assertTesterPasses {
+ new EqualityTester(0.S, 0.S)
+ }
+ }
+ it should "fail with differing values" in {
+ assertTesterFails {
+ new EqualityTester(0.S, 1.S)
+ }
+ }
+
+ behavior.of("Reset === Reset")
+ it should "pass with equal values" in {
+ assertTesterPasses {
+ new EqualityTester(true.B, true.B)
+ }
+ }
+ it should "fail with differing values" in {
+ assertTesterFails {
+ new EqualityTester(true.B, false.B)
+ }
+ }
+
+ behavior.of("AsyncReset === AsyncReset")
+ it should "pass with equal values" in {
+ assertTesterPasses {
+ new EqualityTester(true.B.asAsyncReset, true.B.asAsyncReset)
+ }
+ }
+ it should "fail with differing values" in {
+ assertTesterFails {
+ new EqualityTester(true.B.asAsyncReset, false.B.asAsyncReset)
+ }
+ }
+
+ behavior.of("Interval === Interval")
+ it should "pass with equal values" in {
+ assertTesterPasses {
+ new EqualityTester(2.I, 2.I)
+ }
+ }
+ it should "fail with differing values" in {
+ assertTesterFails {
+ new EqualityTester(2.I, 3.I)
+ }
+ }
+
+ behavior.of("FixedPoint === FixedPoint")
+ it should "pass with equal values" in {
+ assertTesterPasses {
+ new EqualityTester(4.5.F(16.W, 4.BP), 4.5.F(16.W, 4.BP))
+ }
+ }
+ it should "fail with differing values" in {
+ assertTesterFails {
+ new EqualityTester(4.5.F(16.W, 4.BP), 4.6.F(16.W, 4.BP))
+ }
+ }
+
+ behavior.of("ChiselEnum === ChiselEnum")
+ it should "pass with equal values" in {
+ assertTesterPasses {
+ new EqualityTester(MyEnum.sA, MyEnum.sA)
+ }
+ }
+ it should "fail with differing values" in {
+ assertTesterFails {
+ new EqualityTester(MyEnum.sA, MyEnum.sB)
+ }
+ }
+
+ behavior.of("Vec === Vec")
+ it should "pass with equal sizes, equal values" in {
+ assertTesterPasses {
+ new EqualityTester(
+ Vec(3, UInt(8.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U),
+ Vec(3, UInt(8.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U)
+ )
+ }
+ }
+ it should "fail with equal sizes, differing values" in {
+ assertTesterFails {
+ new EqualityTester(
+ Vec(3, UInt(8.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U),
+ Vec(3, UInt(8.W)).Lit(0 -> 0.U, 1 -> 1.U, 2 -> 2.U)
+ )
+ }
+ }
+ it should "throw a ChiselException with differing sizes" in {
+ (the[ChiselException] thrownBy extractCause[ChiselException] {
+ assertTesterFails {
+ new EqualityTester(
+ Vec(3, UInt(8.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U),
+ Vec(4, UInt(8.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U, 3 -> 4.U)
+ )
+ }
+ }).getMessage should include("Vec sizes differ")
+ }
+
+ behavior.of("Bundle === Bundle")
+ it should "pass with equal type, equal values" in {
+ assertTesterPasses {
+ new EqualityTester(
+ (new MyBundle).Lit(_.a -> 42.U, _.b -> false.B, _.c -> MyEnum.sB),
+ (new MyBundle).Lit(_.a -> 42.U, _.b -> false.B, _.c -> MyEnum.sB)
+ )
+ }
+ }
+ it should "fail with equal type, differing values" in {
+ assertTesterFails {
+ new EqualityTester(
+ (new MyBundle).Lit(_.a -> 42.U, _.b -> false.B, _.c -> MyEnum.sB),
+ (new MyBundle).Lit(_.a -> 42.U, _.b -> false.B, _.c -> MyEnum.sA)
+ )
+ }
+ }
+ it should "throw a ChiselException with differing runtime types" in {
+ (the[ChiselException] thrownBy extractCause[ChiselException] {
+ assertTesterFails {
+ new EqualityTester(
+ (new RuntimeSensitiveBundle(new MyBundle)).Lit(
+ _.a -> 1.U,
+ _.b -> (new MyBundle).Lit(
+ _.a -> 42.U,
+ _.b -> false.B,
+ _.c -> MyEnum.sB
+ )
+ ),
+ (new RuntimeSensitiveBundle(new LongBundle)).Lit(
+ _.a -> 1.U,
+ _.b -> (new LongBundle).Lit(
+ _.a -> 42.U,
+ _.b -> 0.S,
+ _.c -> 4.5.F(16.W, 4.BP)
+ )
+ )
+ )
+ }
+ }).getMessage should include("Runtime types differ")
+ }
+
+ behavior.of("DontCare === DontCare")
+ it should "pass with two invalids" in {
+ assertTesterPasses {
+ new EqualityTester(Valid(UInt(8.W)).Lit(_.bits -> 123.U), Valid(UInt(8.W)).Lit(_.bits -> 123.U))
+ }
+ }
+ it should "exhibit the same behavior as comparing two invalidated wires" in {
+ // Also check that two invalidated wires are equal
+ assertTesterPasses {
+ new EqualityTester(WireInit(UInt(8.W), DontCare), WireInit(UInt(8.W), DontCare))
+ }
+
+ // Compare the verilog generated from both test cases and verify that they both are equal to true
+ val verilog1 = ChiselStage.emitVerilog(
+ new EqualityModule(Valid(UInt(8.W)).Lit(_.bits -> 123.U), Valid(UInt(8.W)).Lit(_.bits -> 123.U))
+ )
+ val verilog2 =
+ ChiselStage.emitVerilog(new EqualityModule(WireInit(UInt(8.W), DontCare), WireInit(UInt(8.W), DontCare)))
+
+ verilog1 should include("assign out = 1'h1;")
+ verilog2 should include("assign out = 1'h1;")
+ }
+
+ behavior.of("Analog === Analog")
+ it should "throw a ChiselException" in {
+ (the[ChiselException] thrownBy extractCause[ChiselException] {
+ assertTesterFails { new AnalogExceptionTester }
+ }).getMessage should include("Equality isn't defined for Analog values")
+ }
+}
diff --git a/src/test/scala/chiselTests/Direction.scala b/src/test/scala/chiselTests/Direction.scala
index 0c657273..ddbd99d2 100644
--- a/src/test/scala/chiselTests/Direction.scala
+++ b/src/test/scala/chiselTests/Direction.scala
@@ -4,9 +4,12 @@ package chiselTests
import org.scalatest._
import chisel3._
+import chisel3.experimental.OpaqueType
import chisel3.stage.ChiselStage
import org.scalatest.matchers.should.Matchers
+import scala.collection.immutable.SeqMap
+
class DirectionedBundle extends Bundle {
val in = Input(UInt(32.W))
val out = Output(UInt(32.W))
@@ -83,15 +86,15 @@ class DirectionSpec extends ChiselPropSpec with Matchers with Utils {
})
}
- property("Empty Vecs with no direction on the sample_element *should* cause direction errors") {
- an[Exception] should be thrownBy extractCause[Exception] {
- ChiselStage.elaborate(new Module {
- val io = IO(new Bundle {
- val foo = Input(UInt(8.W))
- val x = Vec(0, UInt(8.W))
- })
+ property(
+ "Empty Vecs with no direction on the sample_element should not cause direction errors, as Chisel and chisel3 directions are merged"
+ ) {
+ ChiselStage.elaborate(new Module {
+ val io = IO(new Bundle {
+ val foo = Input(UInt(8.W))
+ val x = Vec(0, UInt(8.W))
})
- }
+ })
}
property("Empty Bundles should not cause direction errors") {
@@ -117,15 +120,15 @@ class DirectionSpec extends ChiselPropSpec with Matchers with Utils {
})
}
- property("Explicitly directioned but empty Bundles should cause direction errors") {
- an[Exception] should be thrownBy extractCause[Exception] {
- ChiselStage.elaborate(new Module {
- val io = IO(new Bundle {
- val foo = UInt(8.W)
- val x = Input(new Bundle {})
- })
+ property(
+ "Explicitly directioned but empty Bundles should not cause direction errors because Chisel and chisel3 directionality are merged"
+ ) {
+ ChiselStage.elaborate(new Module {
+ val io = IO(new Bundle {
+ val foo = UInt(8.W)
+ val x = Input(new Bundle {})
})
- }
+ })
}
import chisel3.experimental.{DataMirror, Direction}
@@ -327,4 +330,114 @@ class DirectionSpec extends ChiselPropSpec with Matchers with Utils {
}
}
}
+ property("Can now describe a Decoupled bundle using Flipped, not Input/Output in chisel3") {
+ class Decoupled extends Bundle {
+ val bits = UInt(3.W)
+ val valid = Bool()
+ val ready = Flipped(Bool())
+ }
+ class MyModule extends RawModule {
+ val incoming = IO(Flipped(new Decoupled))
+ val outgoing = IO(new Decoupled)
+
+ outgoing <> incoming
+ }
+
+ val emitted: String = ChiselStage.emitChirrtl(new MyModule)
+
+ // Check that emitted directions are correct.
+ assert(emitted.contains("input incoming : { bits : UInt<3>, valid : UInt<1>, flip ready : UInt<1>}"))
+ assert(emitted.contains("output outgoing : { bits : UInt<3>, valid : UInt<1>, flip ready : UInt<1>}"))
+ assert(emitted.contains("outgoing <= incoming"))
+ }
+ property("Can now mix Input/Output and Flipped within the same bundle") {
+ class Decoupled extends Bundle {
+ val bits = UInt(3.W)
+ val valid = Bool()
+ val ready = Flipped(Bool())
+ }
+ class DecoupledAndMonitor extends Bundle {
+ val producer = new Decoupled()
+ val consumer = Flipped(new Decoupled())
+ val monitor = Input(new Decoupled()) // Same as Flipped(stripFlipsIn(..))
+ val driver = Output(new Decoupled()) // Same as stripFlipsIn(..)
+ }
+ class MyModule extends RawModule {
+ val io = IO(Flipped(new DecoupledAndMonitor()))
+ io.consumer <> io.producer
+ io.monitor.bits := io.driver.bits
+ io.monitor.valid := io.driver.valid
+ io.monitor.ready := io.driver.ready
+ }
+
+ val emitted: String = ChiselStage.emitChirrtl(new MyModule)
+
+ assert(
+ emitted.contains(
+ "input io : { producer : { bits : UInt<3>, valid : UInt<1>, flip ready : UInt<1>}, flip consumer : { bits : UInt<3>, valid : UInt<1>, flip ready : UInt<1>}, flip monitor : { bits : UInt<3>, valid : UInt<1>, ready : UInt<1>}, driver : { bits : UInt<3>, valid : UInt<1>, ready : UInt<1>}}"
+ )
+ )
+ assert(emitted.contains("io.consumer <= io.producer"))
+ assert(emitted.contains("io.monitor.bits <= io.driver.bits"))
+ assert(emitted.contains("io.monitor.valid <= io.driver.valid"))
+ assert(emitted.contains("io.monitor.ready <= io.driver.ready"))
+ }
+ property("Bugfix: marking Vec fields with mixed directionality as Output/Input clears inner directions") {
+ class Decoupled extends Bundle {
+ val bits = UInt(3.W)
+ val valid = Bool()
+ val ready = Flipped(Bool())
+ }
+ class Coercing extends Bundle {
+ val source = Output(Vec(1, new Decoupled()))
+ val sink = Input(Vec(1, new Decoupled()))
+ }
+ class MyModule extends RawModule {
+ val io = IO(new Coercing())
+ val source = IO(Output(Vec(1, new Decoupled())))
+ val sink = IO(Input(Vec(1, new Decoupled())))
+ }
+
+ val emitted: String = ChiselStage.emitChirrtl(new MyModule)
+
+ assert(
+ emitted.contains(
+ "output io : { source : { bits : UInt<3>, valid : UInt<1>, ready : UInt<1>}[1], flip sink : { bits : UInt<3>, valid : UInt<1>, ready : UInt<1>}[1]}"
+ )
+ )
+ assert(
+ emitted.contains(
+ "output source : { bits : UInt<3>, valid : UInt<1>, ready : UInt<1>}[1]"
+ )
+ )
+ assert(
+ emitted.contains(
+ "input sink : { bits : UInt<3>, valid : UInt<1>, ready : UInt<1>}[1]"
+ )
+ )
+ }
+ property("Bugfix: clearing all flips inside an opaque type") {
+
+ class Decoupled extends Bundle {
+ val bits = UInt(3.W)
+ val valid = Bool()
+ val ready = Flipped(Bool())
+ }
+ class MyOpaqueType extends Record with OpaqueType {
+ val k = new Decoupled()
+ val elements = SeqMap("" -> k)
+ override def cloneType: this.type = (new MyOpaqueType).asInstanceOf[this.type]
+ }
+ class MyModule extends RawModule {
+ val w = Wire(new MyOpaqueType())
+ }
+
+ val emitted: String = ChiselStage.emitChirrtl(new MyModule)
+
+ assert(
+ emitted.contains(
+ "wire w : { bits : UInt<3>, valid : UInt<1>, flip ready : UInt<1>}"
+ )
+ )
+ }
}
diff --git a/src/test/scala/chiselTests/ExtModule.scala b/src/test/scala/chiselTests/ExtModule.scala
index b5a8ff7c..3ab4cc32 100644
--- a/src/test/scala/chiselTests/ExtModule.scala
+++ b/src/test/scala/chiselTests/ExtModule.scala
@@ -88,6 +88,17 @@ class ExtModuleWithFlatIOTester extends Module {
io <> inst.badIO
}
+class ExtModuleInvalidatedTester extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ val inst = Module(new ExtModule {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ })
+ inst.in := in
+ out := inst.out
+}
+
class ExtModuleSpec extends ChiselFlatSpec {
"A ExtModule inverter" should "work" in {
assertTesterPasses({ new ExtModuleTester }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
@@ -117,4 +128,10 @@ class ExtModuleSpec extends ChiselFlatSpec {
chirrtl should include("inst.in <= io.in")
chirrtl shouldNot include("badIO")
}
+
+ it should "not have invalidated ports in a chisel3._ context" in {
+ val chirrtl = ChiselStage.emitChirrtl(new ExtModuleInvalidatedTester)
+ chirrtl shouldNot include("inst.in is invalid")
+ chirrtl shouldNot include("inst.out is invalid")
+ }
}
diff --git a/src/test/scala/chiselTests/IntervalSpec.scala b/src/test/scala/chiselTests/IntervalSpec.scala
index c0338f6d..a2d36579 100644
--- a/src/test/scala/chiselTests/IntervalSpec.scala
+++ b/src/test/scala/chiselTests/IntervalSpec.scala
@@ -211,7 +211,7 @@ class ClipSqueezeWrapDemo(
val wrapped = counter.wrap(0.U.asInterval(targetRange))
when(counter === startValue) {
- printf(s"Target range is $range\n")
+ printf(cf"Target range is $range\n")
printf("value clip squeeze wrap\n")
}
@@ -245,10 +245,7 @@ class SqueezeFunctionalityTester(range: IntervalRange, startNum: BigDecimal, end
squeezeTemplate := toSqueeze.squeeze(squeezeInterval)
printf(
- s"SqueezeTest %d %d.squeeze($range) => %d\n",
- counter,
- toSqueeze.asSInt(),
- squeezeTemplate.asSInt()
+ cf"SqueezeTest $counter%d ${toSqueeze.asSInt()}%d.squeeze($range) => ${squeezeTemplate.asSInt()}%d\n"
)
}
diff --git a/src/test/scala/chiselTests/MultiClockSpec.scala b/src/test/scala/chiselTests/MultiClockSpec.scala
index 381b4009..29ec6509 100644
--- a/src/test/scala/chiselTests/MultiClockSpec.scala
+++ b/src/test/scala/chiselTests/MultiClockSpec.scala
@@ -166,14 +166,6 @@ class MultiClockSpec extends ChiselFlatSpec with Utils {
}
"Differing clocks at memory and read accessor instantiation" should "warn" in {
- class modMemReadDifferingClock extends Module {
- val myClock = IO(Input(Clock()))
- val mem = withClock(myClock) { Mem(4, UInt(8.W)) }
- val readVal = mem.read(0.U)
- }
- val (logMemReadDifferingClock, _) = grabLog(ChiselStage.elaborate(new modMemReadDifferingClock))
- logMemReadDifferingClock should include("memory is different")
-
class modSyncReadMemReadDifferingClock extends Module {
val myClock = IO(Input(Clock()))
val mem = withClock(myClock) { SyncReadMem(4, UInt(8.W)) }
diff --git a/src/test/scala/chiselTests/Printf.scala b/src/test/scala/chiselTests/Printf.scala
index 4171f97f..6c9f05f0 100644
--- a/src/test/scala/chiselTests/Printf.scala
+++ b/src/test/scala/chiselTests/Printf.scala
@@ -4,6 +4,7 @@ package chiselTests
import chisel3._
import chisel3.testers.BasicTester
+import chisel3.stage.ChiselStage
class SinglePrintfTester() extends BasicTester {
val x = 254.U
@@ -28,6 +29,38 @@ class ASCIIPrintableTester extends BasicTester {
stop()
}
+class ScopeTesterModule extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ out := in
+
+ val w = Wire(UInt(8.W))
+ w := 125.U
+
+ val p = cf"$in"
+ val wp = cf"$w"
+}
+
+class PrintablePrintfScopeTester extends BasicTester {
+ ChiselStage.elaborate {
+ new Module {
+ val mod = Module(new ScopeTesterModule)
+ printf(mod.p)
+ }
+ }
+ stop()
+}
+
+class PrintablePrintfWireScopeTester extends BasicTester {
+ ChiselStage.elaborate {
+ new Module {
+ val mod = Module(new ScopeTesterModule)
+ printf(mod.wp)
+ }
+ }
+ stop()
+}
+
class PrintfSpec extends ChiselFlatSpec {
"A printf with a single argument" should "run" in {
assertTesterPasses { new SinglePrintfTester }
@@ -41,4 +74,10 @@ class PrintfSpec extends ChiselFlatSpec {
"A printf with Printable ASCII characters 1-127" should "run" in {
assertTesterPasses { new ASCIIPrintableTester }
}
+ "A printf with Printable" should "respect port scopes" in {
+ assertTesterPasses { new PrintablePrintfScopeTester }
+ }
+ "A printf with Printable" should "respect wire scopes" in {
+ a[ChiselException] should be thrownBy { assertTesterPasses { new PrintablePrintfWireScopeTester } }
+ }
}
diff --git a/src/test/scala/chiselTests/RecordSpec.scala b/src/test/scala/chiselTests/RecordSpec.scala
index 30b55812..3414ec8a 100644
--- a/src/test/scala/chiselTests/RecordSpec.scala
+++ b/src/test/scala/chiselTests/RecordSpec.scala
@@ -6,7 +6,7 @@ import chisel3._
import chisel3.stage.ChiselStage
import chisel3.testers.BasicTester
import chisel3.util.{Counter, Queue}
-import chisel3.experimental.DataMirror
+import chisel3.experimental.{DataMirror, OpaqueType}
import scala.collection.immutable.SeqMap
@@ -108,6 +108,123 @@ trait RecordSpecUtils {
require(DataMirror.checkTypeEquivalence(wire0, wire1))
require(!DataMirror.checkTypeEquivalence(wire1, wire2))
}
+
+ class SingleElementRecord extends Record with OpaqueType {
+ private val underlying = UInt(8.W)
+ val elements = SeqMap("" -> underlying)
+ override def cloneType: this.type = (new SingleElementRecord).asInstanceOf[this.type]
+
+ def +(that: SingleElementRecord): SingleElementRecord = {
+ val _w = Wire(new SingleElementRecord)
+ _w.underlying := this.underlying + that.underlying
+ _w
+ }
+ }
+
+ class SingleElementRecordModule extends Module {
+ val in1 = IO(Input(new SingleElementRecord))
+ val in2 = IO(Input(new SingleElementRecord))
+ val out = IO(Output(new SingleElementRecord))
+
+ val r = new SingleElementRecord
+
+ out := in1 + in2
+ }
+
+ class InnerRecord extends Record with OpaqueType {
+ val k = new InnerInnerRecord
+ val elements = SeqMap("" -> k)
+ override def cloneType: this.type = (new InnerRecord).asInstanceOf[this.type]
+ }
+
+ class InnerInnerRecord extends Record with OpaqueType {
+ val k = new SingleElementRecord
+ val elements = SeqMap("" -> k)
+ override def cloneType: this.type = (new InnerInnerRecord).asInstanceOf[this.type]
+ }
+
+ class NestedRecordModule extends Module {
+ val in = IO(Input(new InnerRecord))
+ val out = IO(Output(new InnerRecord))
+ val inst = Module(new InnerModule)
+ inst.io.foo := in
+ out := inst.io.bar
+ }
+ class InnerModule extends Module {
+ val io = IO(new Bundle {
+ val foo = Input(new InnerRecord)
+ val bar = Output(new InnerRecord)
+ })
+
+ // DO NOT do this; just for testing element connections
+ io.bar.elements.head._2 := io.foo.elements.head._2
+ }
+
+ class NamedSingleElementRecord extends Record with OpaqueType {
+ private val underlying = UInt(8.W)
+ val elements = SeqMap("unused" -> underlying)
+
+ override def cloneType: this.type = (new NamedSingleElementRecord).asInstanceOf[this.type]
+ }
+
+ class NamedSingleElementModule extends Module {
+ val in = IO(Input(new NamedSingleElementRecord))
+ val out = IO(Output(new NamedSingleElementRecord))
+ out := in
+ }
+
+ class ErroneousOverride extends Record with OpaqueType {
+ private val underlyingA = UInt(8.W)
+ private val underlyingB = UInt(8.W)
+ val elements = SeqMap("x" -> underlyingA, "y" -> underlyingB)
+
+ override def opaqueType = true
+ override def cloneType: this.type = (new ErroneousOverride).asInstanceOf[this.type]
+ }
+
+ class ErroneousOverrideModule extends Module {
+ val in = IO(Input(new ErroneousOverride))
+ val out = IO(Output(new ErroneousOverride))
+ out := in
+ }
+
+ class NotActuallyOpaqueType extends Record with OpaqueType {
+ private val underlyingA = UInt(8.W)
+ private val underlyingB = UInt(8.W)
+ val elements = SeqMap("x" -> underlyingA, "y" -> underlyingB)
+
+ override def opaqueType = false
+ override def cloneType: this.type = (new NotActuallyOpaqueType).asInstanceOf[this.type]
+ }
+
+ class NotActuallyOpaqueTypeModule extends Module {
+ val in = IO(Input(new NotActuallyOpaqueType))
+ val out = IO(Output(new NotActuallyOpaqueType))
+ out := in
+ }
+
+ // Illustrate how to dyanmically decide between OpaqueType or not
+ sealed trait MaybeBoxed[T <: Data] extends Record {
+ def underlying: T
+ def boxed: Boolean
+ }
+ object MaybeBoxed {
+ def apply[T <: Data](gen: T, boxed: Boolean): MaybeBoxed[T] = {
+ if (boxed) new Boxed(gen) else new Unboxed(gen)
+ }
+ }
+ class Boxed[T <: Data](gen: T) extends MaybeBoxed[T] {
+ def boxed = true
+ lazy val elements = SeqMap("underlying" -> gen.cloneType)
+ def underlying = elements.head._2
+ override def cloneType: this.type = (new Boxed(gen)).asInstanceOf[this.type]
+ }
+ class Unboxed[T <: Data](gen: T) extends MaybeBoxed[T] with OpaqueType {
+ def boxed = false
+ lazy val elements = SeqMap("" -> gen.cloneType)
+ def underlying = elements.head._2
+ override def cloneType: this.type = (new Unboxed(gen)).asInstanceOf[this.type]
+ }
}
class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils {
@@ -133,7 +250,7 @@ class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils {
class AliasedFieldRecord extends Record {
val foo = UInt(8.W)
val elements = SeqMap("foo" -> foo, "bar" -> foo)
- override def cloneType: AliasedFieldRecord.this.type = this
+ override def cloneType: AliasedFieldRecord.this.type = (new AliasedFieldRecord).asInstanceOf[this.type]
}
val e = intercept[AliasedAggregateFieldException] {
@@ -146,6 +263,85 @@ class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils {
e.getMessage should include("contains aliased fields named (bar,foo)")
}
+ they should "support OpaqueType for maps with single unnamed elements" in {
+ val singleElementChirrtl = ChiselStage.emitChirrtl { new SingleElementRecordModule }
+ singleElementChirrtl should include("input in1 : UInt<8>")
+ singleElementChirrtl should include("input in2 : UInt<8>")
+ singleElementChirrtl should include("add(in1, in2)")
+ }
+
+ they should "work correctly for toTarget in nested OpaqueType Records" in {
+ var mod: NestedRecordModule = null
+ ChiselStage.elaborate { mod = new NestedRecordModule; mod }
+ val testStrings = Seq(
+ mod.inst.io.foo.toTarget.serialize,
+ mod.inst.io.foo.k.toTarget.serialize,
+ mod.inst.io.foo.k.k.toTarget.serialize,
+ mod.inst.io.foo.elements.head._2.toTarget.serialize,
+ mod.inst.io.foo.k.elements.head._2.toTarget.serialize,
+ mod.inst.io.foo.k.k.elements.head._2.toTarget.serialize
+ )
+ testStrings.foreach(x => assert(x == "~NestedRecordModule|InnerModule>io.foo"))
+ }
+
+ they should "work correctly when connecting nested OpaqueType elements" in {
+ val nestedRecordChirrtl = ChiselStage.emitChirrtl { new NestedRecordModule }
+ nestedRecordChirrtl should include("input in : UInt<8>")
+ nestedRecordChirrtl should include("output out : UInt<8>")
+ nestedRecordChirrtl should include("inst.io.foo <= in")
+ nestedRecordChirrtl should include("out <= inst.io.bar")
+ nestedRecordChirrtl should include("output io : { flip foo : UInt<8>, bar : UInt<8>}")
+ nestedRecordChirrtl should include("io.bar <= io.foo")
+ }
+
+ they should "throw an error when map contains a named element and OpaqueType is mixed in" in {
+ (the[Exception] thrownBy extractCause[Exception] {
+ ChiselStage.elaborate { new NamedSingleElementModule }
+ }).getMessage should include("Opaque types must have exactly one element with an empty name")
+ }
+
+ they should "throw an error when map contains more than one element and OpaqueType is mixed in" in {
+ (the[Exception] thrownBy extractCause[Exception] {
+ ChiselStage.elaborate { new ErroneousOverrideModule }
+ }).getMessage should include("Opaque types must have exactly one element with an empty name")
+ }
+
+ they should "work correctly when an OpaqueType overrides the def as false" in {
+ val chirrtl = ChiselStage.emitChirrtl(new NotActuallyOpaqueTypeModule)
+ chirrtl should include("input in : { y : UInt<8>, x : UInt<8>}")
+ chirrtl should include("output out : { y : UInt<8>, x : UInt<8>}")
+ chirrtl should include("out <= in")
+ }
+
+ they should "support conditional OpaqueTypes via traits and factory methods" in {
+ class MyModule extends Module {
+ val in0 = IO(Input(MaybeBoxed(UInt(8.W), true)))
+ val out0 = IO(Output(MaybeBoxed(UInt(8.W), true)))
+ val in1 = IO(Input(MaybeBoxed(UInt(8.W), false)))
+ val out1 = IO(Output(MaybeBoxed(UInt(8.W), false)))
+ out0 := in0
+ out1 := in1
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include("input in0 : { underlying : UInt<8>}")
+ chirrtl should include("input in1 : UInt<8>")
+ }
+
+ they should "work with .toTarget" in {
+ var m: SingleElementRecordModule = null
+ ChiselStage.elaborate { m = new SingleElementRecordModule; m }
+ val q = m.in1.toTarget.toString
+ assert(q == "~SingleElementRecordModule|SingleElementRecordModule>in1")
+ }
+
+ they should "work (but warn) with .toTarget on non-data OpaqueType Record" in {
+ var m: SingleElementRecordModule = null
+ ChiselStage.elaborate { m = new SingleElementRecordModule; m }
+ val (log, q) = grabLog(m.r.toTarget)
+ log should include(".toTarget of non-hardware Data is deprecated")
+ assert(q.toString == "~SingleElementRecordModule|SingleElementRecordModule>r")
+ }
+
they should "follow UInt serialization/deserialization API" in {
assertTesterPasses { new RecordSerializationTest }
}
@@ -184,4 +380,17 @@ class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils {
"CustomBundle" should "check the types" in {
ChiselStage.elaborate { new RecordTypeTester }
}
+
+ "Record with unstable elements" should "error" in {
+ class MyRecord extends Record {
+ def elements = SeqMap("a" -> UInt(8.W))
+ override def cloneType: this.type = (new MyRecord).asInstanceOf[this.type]
+ }
+ val e = the[ChiselException] thrownBy {
+ ChiselStage.elaborate(new Module {
+ val io = IO(Input(new MyRecord))
+ })
+ }
+ e.getMessage should include("does not return the same objects when calling .elements multiple times")
+ }
}
diff --git a/src/test/scala/chiselTests/StrongEnum.scala b/src/test/scala/chiselTests/StrongEnum.scala
index 44ed77f9..e9f412fe 100644
--- a/src/test/scala/chiselTests/StrongEnum.scala
+++ b/src/test/scala/chiselTests/StrongEnum.scala
@@ -5,6 +5,7 @@ package chiselTests
import chisel3._
import chisel3.experimental.ChiselEnum
import chisel3.experimental.AffectsChiselPrefix
+import chisel3.experimental.suppressEnumCastWarning
import chisel3.internal.firrtl.UnknownWidth
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util._
@@ -163,6 +164,27 @@ class StrongEnumFSM extends Module {
}
}
+object Opcode extends ChiselEnum {
+ val load = Value(0x03.U)
+ val imm = Value(0x13.U)
+ val auipc = Value(0x17.U)
+ val store = Value(0x23.U)
+ val reg = Value(0x33.U)
+ val lui = Value(0x37.U)
+ val br = Value(0x63.U)
+ val jalr = Value(0x67.U)
+ val jal = Value(0x6f.U)
+}
+
+class LoadStoreExample extends Module {
+ val io = IO(new Bundle {
+ val opcode = Input(Opcode())
+ val load_or_store = Output(Bool())
+ })
+ io.load_or_store := io.opcode.isOneOf(Opcode.load, Opcode.store)
+ printf(p"${io.opcode}")
+}
+
class CastToUIntTester extends BasicTester {
for ((enum, lit) <- EnumExample.all.zip(EnumExample.litValues)) {
val mod = Module(new CastToUInt)
@@ -481,6 +503,46 @@ class StrongEnumSpec extends ChiselFlatSpec with Utils {
(log should not).include("warn")
}
+ it should "suppress warning using suppressEnumCastWarning" in {
+ object TestEnum extends ChiselEnum {
+ val e0, e1, e2 = Value
+ }
+
+ class MyModule extends Module {
+ val in = IO(Input(UInt(2.W)))
+ val out = IO(Output(TestEnum()))
+ suppressEnumCastWarning {
+ val res = TestEnum(in)
+ out := res
+ }
+ }
+ val (log, _) = grabLog(ChiselStage.elaborate(new MyModule))
+ (log should not).include("warn")
+ }
+
+ it should "suppress exactly one warning using suppressEnumCastWarning" in {
+ object TestEnum1 extends ChiselEnum {
+ val e0, e1, e2 = Value
+ }
+ object TestEnum2 extends ChiselEnum {
+ val e0, e1, e2 = Value
+ }
+
+ class MyModule extends Module {
+ val in = IO(Input(UInt(2.W)))
+ val out1 = IO(Output(TestEnum1()))
+ val out2 = IO(Output(TestEnum2()))
+ suppressEnumCastWarning {
+ out1 := TestEnum1(in)
+ }
+ out2 := TestEnum2(in)
+ }
+ val (log, _) = grabLog(ChiselStage.elaborate(new MyModule))
+ log should include("warn")
+ log should include("TestEnum2") // not suppressed
+ (log should not).include("TestEnum1") // suppressed
+ }
+
"Casting a UInt to an Enum with .safe" should "NOT warn" in {
object MyEnum extends ChiselEnum {
val e0, e1, e2 = Value
@@ -514,6 +576,12 @@ class StrongEnumSpec extends ChiselFlatSpec with Utils {
it should "correctly check if the enumeration is one of the values in a given sequence" in {
assertTesterPasses(new IsOneOfTester)
}
+
+ it should "work with Printables" in {
+ ChiselStage.emitChirrtl(new LoadStoreExample) should include(
+ """printf(clock, UInt<1>("h1"), "%c%c%c%c%c", _chiselTestsOpcodePrintable[0], _chiselTestsOpcodePrintable[1], _chiselTestsOpcodePrintable[2], _chiselTestsOpcodePrintable[3], _chiselTestsOpcodePrintable[4])"""
+ )
+ }
}
class StrongEnumAnnotator extends Module {
diff --git a/src/test/scala/chiselTests/ToTargetSpec.scala b/src/test/scala/chiselTests/ToTargetSpec.scala
index dc4ec448..de46cdcb 100644
--- a/src/test/scala/chiselTests/ToTargetSpec.scala
+++ b/src/test/scala/chiselTests/ToTargetSpec.scala
@@ -49,4 +49,21 @@ class ToTargetSpec extends ChiselFlatSpec with Utils {
val q = m.q.toTarget.toString
assert(q == s"~$mn|Queue")
}
+
+ it should "warn on non-hardware types and provide information" in {
+ class Example extends Module {
+ val tpe = UInt(8.W)
+
+ val in = IO(Input(tpe))
+ val out = IO(Output(tpe))
+ out := in
+ }
+
+ var e: Example = null
+ chisel3.stage.ChiselStage.elaborate { e = new Example; e }
+ val (log, foo) = grabLog(e.tpe.toTarget)
+ log should include(
+ "Accessing the .instanceName or .toTarget of non-hardware Data is deprecated: 'tpe', in module 'Example'"
+ )
+ }
}
diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala
index 02743187..e46774dd 100644
--- a/src/test/scala/chiselTests/Vec.scala
+++ b/src/test/scala/chiselTests/Vec.scala
@@ -6,7 +6,7 @@ import org.scalacheck._
import chisel3._
import chisel3.stage.ChiselStage
-import chisel3.testers.BasicTester
+import chisel3.testers.{BasicTester, TesterDriver}
import chisel3.util._
import org.scalacheck.Shrink
import scala.annotation.tailrec
@@ -111,7 +111,7 @@ class FillTester(n: Int, value: Int) extends BasicTester {
val x = VecInit(Array.fill(n)(value.U))
val u = VecInit.fill(n)(value.U)
- assert(x.asUInt() === u.asUInt(), s"Expected Vec to be filled like $x, instead VecInit.fill created $u")
+ assert(x.asUInt() === u.asUInt(), cf"Expected Vec to be filled like $x, instead VecInit.fill created $u")
stop()
}
@@ -235,7 +235,7 @@ class IterateTester(start: Int, len: Int)(f: UInt => UInt) extends BasicTester {
val testVec = VecInit.iterate(start.U, len)(f)
assert(
controlVec.asUInt() === testVec.asUInt(),
- s"Expected Vec to be filled like $controlVec, instead creaeted $testVec\n"
+ cf"Expected Vec to be filled like $controlVec, instead created $testVec\n"
)
stop()
}
@@ -456,7 +456,7 @@ class VecSpec extends ChiselPropSpec with Utils {
}
property("Infering widths on huge Vecs should not cause a stack overflow") {
- assertTesterPasses { new HugeVecTester(10000) }
+ assertTesterPasses(new HugeVecTester(10000), annotations = TesterDriver.verilatorOnly)
}
property("A Reg of a Vec of a single 1 bit element should compile and work") {
diff --git a/src/test/scala/chiselTests/VecLiteralSpec.scala b/src/test/scala/chiselTests/VecLiteralSpec.scala
index fa97a8c8..e2eb791d 100644
--- a/src/test/scala/chiselTests/VecLiteralSpec.scala
+++ b/src/test/scala/chiselTests/VecLiteralSpec.scala
@@ -205,7 +205,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
assertTesterPasses {
new BasicTester {
- chisel3.assert(outsideVecLit(0) === 0xdd.U, s"v(0)")
+ chisel3.assert(outsideVecLit(0) === 0xdd.U, "v(0)")
stop()
}
}
@@ -216,7 +216,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
assertTesterPasses {
new BasicTester {
- chisel3.assert(outsideVecLit(0) === 0xdd.U, s"v(0)")
+ chisel3.assert(outsideVecLit(0) === 0xdd.U, "v(0)")
chisel3.assert(outsideVecLit(1) === 0xcc.U)
chisel3.assert(outsideVecLit(2) === 0xbb.U)
chisel3.assert(outsideVecLit(3) === 0xaa.U)
diff --git a/src/test/scala/chiselTests/WarningSpec.scala b/src/test/scala/chiselTests/WarningSpec.scala
new file mode 100644
index 00000000..1cef1ffc
--- /dev/null
+++ b/src/test/scala/chiselTests/WarningSpec.scala
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3._
+import chisel3.util._
+import chisel3.stage.ChiselStage
+import chisel3.experimental.ChiselEnum
+import chisel3.experimental.EnumType
+
+class WarningSpec extends ChiselFlatSpec with Utils {
+ behavior.of("Warnings")
+
+ object MyEnum extends ChiselEnum {
+ val e0, e1, e2 = Value
+ }
+
+ class MyModule extends Module {
+ val in = IO(Input(UInt(2.W)))
+ val out1 = IO(Output(MyEnum()))
+ val out2 = IO(Output(MyEnum()))
+ def func(out: EnumType): Unit = {
+ out := MyEnum(in)
+ }
+ func(out1)
+ func(out2)
+ }
+
+ "Warnings" should "be de-duplicated" in {
+ val (log, _) = grabLog(ChiselStage.elaborate(new MyModule))
+ def countSubstring(s: String, sub: String) =
+ s.sliding(sub.length).count(_ == sub)
+ countSubstring(log, "Casting non-literal UInt") should be(1)
+ }
+
+ "Warnings" should "be treated as errors with warningsAsErrors" in {
+ a[ChiselException] should be thrownBy extractCause[ChiselException] {
+ val args = Array("--warnings-as-errors")
+ (new ChiselStage).emitChirrtl(new MyModule, args)
+ }
+ }
+}
diff --git a/src/test/scala/chiselTests/WireSpec.scala b/src/test/scala/chiselTests/WireSpec.scala
index 11a1f1a1..058a7f08 100644
--- a/src/test/scala/chiselTests/WireSpec.scala
+++ b/src/test/scala/chiselTests/WireSpec.scala
@@ -3,6 +3,7 @@
package chiselTests
import chisel3._
+import chisel3.stage.ChiselStage
class WireSpec extends ChiselFlatSpec {
"WireDefault.apply" should "work" in {
@@ -17,4 +18,19 @@ class WireSpec extends ChiselFlatSpec {
it should "not allow init argument to affect type inference" in {
assertDoesNotCompile("val x: UInt = WireDefault(UInt(4.W), 2.S)")
}
+ it should "have source locator information on wires" in {
+ class Dummy extends chisel3.Module {
+ val in = IO(Input(Bool()))
+ val out = IO(Output(Bool()))
+
+ val wire = WireInit(Bool(), true.B)
+ val wire2 = Wire(Bool())
+ wire2 := in
+ out := in & wire & wire2
+ }
+
+ val chirrtl = ChiselStage.emitChirrtl(new Dummy)
+ chirrtl should include("wire wire : UInt<1> @[WireSpec.scala")
+ chirrtl should include("wire wire2 : UInt<1> @[WireSpec.scala")
+ }
}
diff --git a/src/test/scala/chiselTests/aop/InjectionSpec.scala b/src/test/scala/chiselTests/aop/InjectionSpec.scala
index 9b29b0ba..1b69efa3 100644
--- a/src/test/scala/chiselTests/aop/InjectionSpec.scala
+++ b/src/test/scala/chiselTests/aop/InjectionSpec.scala
@@ -108,6 +108,7 @@ class InjectionSpec extends ChiselFlatSpec with Utils {
{ _: SubmoduleManipulationTester =>
// By creating a second SubmoduleA, the module names would conflict unless they were uniquified
val moduleSubmoduleC = Module(new SubmoduleC)
+ moduleSubmoduleC.io <> DontCare
//if we're here then we've elaborated correctly
stop()
}
diff --git a/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala b/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala
index 731596ec..09fdf3c4 100644
--- a/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala
+++ b/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala
@@ -8,7 +8,26 @@ import chisel3.stage.ChiselStage
import chisel3.experimental.DataMirror
import chiselTests.ChiselFlatSpec
+object DataMirrorSpec {
+ import org.scalatest.matchers.should.Matchers._
+ class GrandChild(parent: RawModule) extends Module {
+ DataMirror.getParent(this) should be(Some(parent))
+ }
+ class Child(parent: RawModule) extends Module {
+ val inst = Module(new GrandChild(this))
+ DataMirror.getParent(inst) should be(Some(this))
+ DataMirror.getParent(this) should be(Some(parent))
+ }
+ class Parent extends Module {
+ val inst = Module(new Child(this))
+ DataMirror.getParent(inst) should be(Some(this))
+ DataMirror.getParent(this) should be(None)
+ }
+}
+
class DataMirrorSpec extends ChiselFlatSpec {
+ import DataMirrorSpec._
+
behavior.of("DataMirror")
def assertBinding(x: Data, io: Boolean, wire: Boolean, reg: Boolean) = {
@@ -55,4 +74,18 @@ class DataMirrorSpec extends ChiselFlatSpec {
}
ChiselStage.elaborate(new MyModule)
}
+
+ it should "support getParent for normal modules" in {
+ ChiselStage.elaborate(new Parent)
+ }
+
+ it should "support getParent for normal modules even when used in a D/I context" in {
+ import chisel3.experimental.hierarchy._
+ class Top extends Module {
+ val defn = Definition(new Parent)
+ val inst = Instance(defn)
+ DataMirror.getParent(this) should be(None)
+ }
+ ChiselStage.elaborate(new Top)
+ }
}
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
index ac8357f0..cefc893c 100644
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ b/src/test/scala/chiselTests/experimental/DataView.scala
@@ -7,7 +7,7 @@ import chisel3._
import chisel3.experimental.dataview._
import chisel3.experimental.conversions._
import chisel3.experimental.DataMirror.internal.chiselTypeClone
-import chisel3.experimental.HWTuple2
+import chisel3.experimental.{Analog, HWTuple2}
import chisel3.stage.ChiselStage
import chisel3.util.{Decoupled, DecoupledIO}
@@ -91,6 +91,16 @@ class DataViewSpec extends ChiselFlatSpec {
chirrtl should include("bar <= in")
}
+ it should "handle viewing Analogs as Analogs" in {
+ class MyModule extends Module {
+ val foo = IO(Analog(8.W))
+ val bar = IO(Analog(8.W))
+ foo <> bar.viewAs[Analog]
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include("attach (foo, bar)")
+ }
+
it should "handle viewing Bundles as their same concrete type" in {
class MyBundle extends Bundle {
val foo = UInt(8.W)
@@ -177,6 +187,28 @@ class DataViewSpec extends ChiselFlatSpec {
chirrtl should include("fooOut.foo <= barIn.foo")
}
+ it should "be easy to make a PartialDataView viewing a Bundle as a Parent Bundle type" in {
+ class Foo(x: Int) extends Bundle {
+ val foo = UInt(x.W)
+ }
+ class Bar(val x: Int) extends Foo(x) {
+ val bar = UInt(x.W)
+ }
+ implicit val view = PartialDataView.supertype[Bar, Foo](b => new Foo(b.x))
+ class MyModule extends Module {
+ val fooIn = IO(Input(new Foo(8)))
+ val barOut = IO(Output(new Bar(8)))
+ barOut.viewAs[Foo] := fooIn
+
+ val barIn = IO(Input(new Bar(8)))
+ val fooOut = IO(Output(new Foo(8)))
+ fooOut := barIn.viewAs[Foo]
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include("barOut.foo <= fooIn.foo")
+ chirrtl should include("fooOut.foo <= barIn.foo")
+ }
+
it should "error if viewing a parent Bundle as a child Bundle type" in {
assertTypeError("""
class Foo extends Bundle {
diff --git a/src/test/scala/chiselTests/experimental/FlatIOSpec.scala b/src/test/scala/chiselTests/experimental/FlatIOSpec.scala
index dfce447f..ebb7cbdb 100644
--- a/src/test/scala/chiselTests/experimental/FlatIOSpec.scala
+++ b/src/test/scala/chiselTests/experimental/FlatIOSpec.scala
@@ -5,7 +5,7 @@ package chiselTests.experimental
import chisel3._
import chisel3.util.Valid
import chisel3.stage.ChiselStage.emitChirrtl
-import chisel3.experimental.FlatIO
+import chisel3.experimental.{Analog, FlatIO}
import chiselTests.ChiselFlatSpec
class FlatIOSpec extends ChiselFlatSpec {
@@ -48,4 +48,19 @@ class FlatIOSpec extends ChiselFlatSpec {
val chirrtl = emitChirrtl(new MyModule)
chirrtl should include("out[addr] <= in[addr]")
}
+
+ it should "support Analog members" in {
+ class MyBundle extends Bundle {
+ val foo = Output(UInt(8.W))
+ val bar = Analog(8.W)
+ }
+ class MyModule extends RawModule {
+ val in = IO(Flipped(new MyBundle))
+ val out = IO(new MyBundle)
+ out <> in
+ }
+ val chirrtl = emitChirrtl(new MyModule)
+ chirrtl should include("out.foo <= in.foo")
+ chirrtl should include("attach (out.bar, in.bar)")
+ }
}
diff --git a/src/test/scala/chiselTests/experimental/ForceNames.scala b/src/test/scala/chiselTests/experimental/ForceNames.scala
index 233b4a5f..9ba825c4 100644
--- a/src/test/scala/chiselTests/experimental/ForceNames.scala
+++ b/src/test/scala/chiselTests/experimental/ForceNames.scala
@@ -59,7 +59,7 @@ object ForceNamesHierarchy {
}
}
-class ForceNamesSpec extends ChiselFlatSpec {
+class ForceNamesSpec extends ChiselFlatSpec with Utils {
def run[T <: RawModule](
dut: => T,
@@ -110,4 +110,19 @@ class ForceNamesSpec extends ChiselFlatSpec {
)
}
}
+
+ "Force Name of non-hardware value" should "warn" in {
+ class Example extends Module {
+ val tpe = UInt(8.W)
+ forceName(tpe, "foobar")
+
+ val in = IO(Input(tpe))
+ val out = IO(Output(tpe))
+ out := in
+ }
+
+ val (log, foo) = grabLog(chisel3.stage.ChiselStage.elaborate(new Example))
+ log should include("deprecated")
+ log should include("Using forceName 'foobar' on non-hardware value UInt<8>")
+ }
}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
index fa26cbde..27725c49 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
@@ -271,4 +271,70 @@ object Examples {
@public val mem = Mem(8, UInt(32.W))
@public val syncReadMem = SyncReadMem(8, UInt(32.W))
}
+
+ @instantiable
+ class LeafInstantiable(val bundle: Data) {
+ @public val bundle = bundle
+ }
+
+ @instantiable
+ class NestedInstantiable(val in: LeafInstantiable, val out: LeafInstantiable) {
+ @public val in = in
+ @public val out = out
+ }
+
+ @instantiable
+ class AddOneNestedInstantiableData(width: Int) extends Module {
+ @public val in = IO(Input(UInt(width.W)))
+ @public val out = IO(Output(UInt(width.W)))
+ out := in + 1.U
+
+ @public val leafOut = new LeafInstantiable(out)
+ @public val leafIn = new LeafInstantiable(in)
+ @public val nested = new NestedInstantiable(in = leafIn, out = leafOut)
+
+ }
+
+ class AddTwoNestedInstantiableData(width: Int) extends Module {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt(width.W)))
+ val addOneDef = Definition(new AddOneNestedInstantiableData(width))
+ val i0 = Instance(addOneDef)
+ val i1 = Instance(addOneDef)
+ i0.in := in
+ i1.in := i0.out
+ out := i1.out
+
+ // both are equivalent to the above
+ i1.leafIn.bundle := i0.leafOut.bundle
+ i1.nested.in.bundle := i0.nested.out.bundle
+ }
+
+ class AddTwoNestedInstantiableDataSubmodule(addOneDef: Definition[AddOneNestedInstantiableData]) extends Module {
+ val in = IO(Input(UInt(addOneDef.in.getWidth.W)))
+ val out = IO(Output(UInt(addOneDef.out.getWidth.W)))
+ val i0 = Instance(addOneDef)
+ val i1 = Instance(addOneDef)
+ i0.in := in
+ i1.in := i0.out
+ out := i1.out
+
+ // both are equivalent to the above
+ i1.leafIn.bundle := i0.leafOut.bundle
+ i1.nested.in.bundle := i0.nested.out.bundle
+ }
+
+ class AddTwoNestedInstantiableDataWrapper(width: Int) extends Module {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt(width.W)))
+
+ val original = Module(new AddOneNestedInstantiableData(width))
+ val copy = Module(new AddTwoNestedInstantiableDataSubmodule(original.toDefinition))
+
+ original.in := in
+ copy.in := original.out
+ out := copy.out
+
+ }
+
}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
index 8d8f7ea5..6596cd51 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
@@ -364,6 +364,16 @@ class InstanceSpec extends ChiselFunSpec with Utils {
annos should contain(MarkAnnotation("~Top|Top/i:HasMems>mem".rt, "Mem"))
annos should contain(MarkAnnotation("~Top|Top/i:HasMems>syncReadMem".rt, "SyncReadMem"))
}
+ it("(3.p): should make connectable IOs on nested IsInstantiables that have IO Datas in them") {
+ val (chirrtl, _) = getFirrtlAndAnnos(new AddTwoNestedInstantiableData(4))
+ exactly(3, chirrtl.serialize.split('\n')) should include("i1.in <= i0.out")
+ }
+ it(
+ "(3.q): should make connectable IOs on nested IsInstantiables's Data when the Instance and Definition do not have the same parent"
+ ) {
+ val (chirrtl, _) = getFirrtlAndAnnos(new AddTwoNestedInstantiableDataWrapper(4))
+ exactly(3, chirrtl.serialize.split('\n')) should include("i1.in <= i0.out")
+ }
}
describe("4: toInstance") {
it("4.0: should work on modules") {
diff --git a/src/test/scala/chiselTests/naming/PrefixSpec.scala b/src/test/scala/chiselTests/naming/PrefixSpec.scala
index 6d52407e..d8cb3348 100644
--- a/src/test/scala/chiselTests/naming/PrefixSpec.scala
+++ b/src/test/scala/chiselTests/naming/PrefixSpec.scala
@@ -7,6 +7,7 @@ import chisel3.stage.ChiselStage
import chisel3.aop.Select
import chisel3.experimental.{dump, noPrefix, prefix, treedump}
import chiselTests.{ChiselPropSpec, Utils}
+import chisel3.experimental.AffectsChiselPrefix
class PrefixSpec extends ChiselPropSpec with Utils {
implicit val minimumMajorVersion: Int = 12
@@ -497,4 +498,53 @@ class PrefixSpec extends ChiselPropSpec with Utils {
Select.wires(top).map(_.instanceName) should be(List("a_b_c_d"))
}
}
+
+ property("Prefixing of AffectsChiselPrefix objects should work") {
+ class NotAData extends AffectsChiselPrefix {
+ val value = Wire(UInt(3.W))
+ }
+ class NotADataUnprefixed {
+ val value = Wire(UInt(3.W))
+ }
+ class Test extends Module {
+ {
+ val nonData = new NotAData
+ // Instance name of nonData.value should be nonData_value
+ nonData.value := RegNext(3.U)
+
+ val nonData2 = new NotADataUnprefixed
+ // Instance name of nonData2.value should be value
+ nonData2.value := RegNext(3.U)
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("nonData_value", "value"))
+ }
+ }
+ property("Prefixing should not be affected by repeated calls of suggestName") {
+ class Test extends Module {
+ val in = IO(Input(UInt(3.W)))
+ val prefixed = {
+ val wire = Wire(UInt(3.W)).suggestName("wire") // "prefixed_wire"
+ wire := in
+
+ val thisShouldNotBeHere = {
+ // Second suggestName doesn't modify the instanceName since it was
+ // already suggested, but also should not modify the prefix either
+
+ // Incorrect behavior would rename the wire to
+ // "prefixed_thisShouldNotBeHere_wire"
+ wire.suggestName("wire")
+
+ val out = IO(Output(UInt(3.W)))
+ out := wire
+ out
+ }
+ thisShouldNotBeHere
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("prefixed_wire"))
+ }
+ }
}