From 1ee9adbec48bc8393e1c3d0ed86a548f8510d13f Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 12 May 2022 17:31:59 +0000 Subject: Support separately elaborating definition and instance in ChiselStage (backport #2512) (#2520) * Support separately elaborating definition and instance in ChiselStage (#2512) (cherry picked from commit a0aa4d1550e3fbde199a98529cffeb176fb4bed8) # Conflicts: # core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala # core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala # core/src/main/scala/chisel3/internal/Builder.scala * fixing imports (#2522) Co-authored-by: Deborah Soung --- .../hierarchy/SeparateElaborationSpec.scala | 356 +++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala (limited to 'src') 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..7555a1c4 --- /dev/null +++ b/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala @@ -0,0 +1,356 @@ +// 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" + ) + } + +} -- cgit v1.2.3 From 99ae2eeb9decb3bc3a789053889f608bb1a103b9 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 13 May 2022 19:45:59 -0700 Subject: Deprecate named arguments for methods moving to macros in 3.6 (#2530) These methods will start using def macros and since def macros do not supported named arguments this will be a source-incompatible change. This deprecation will warn users that they need to remove any uses of named arguments on these methods.--- src/main/scala/chisel3/util/Bitwise.scala | 15 ++++++++----- src/main/scala/chisel3/util/Cat.scala | 6 +++-- src/main/scala/chisel3/util/Reg.scala | 37 ++++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Bitwise.scala b/src/main/scala/chisel3/util/Bitwise.scala index 8abe3645..92ebddb4 100644 --- a/src/main/scala/chisel3/util/Bitwise.scala +++ b/src/main/scala/chisel3/util/Bitwise.scala @@ -24,13 +24,16 @@ object FillInterleaved { * * Output data-equivalent to in(size(in)-1) (n times) ## ... ## in(1) (n times) ## in(0) (n times) */ - def apply(n: Int, in: UInt): UInt = apply(n, in.asBools) + def apply(@deprecatedName('n, "Chisel 3.5") n: Int, @deprecatedName('in, "Chisel 3.5") in: UInt): UInt = + apply(n, in.asBools) /** Creates n repetitions of each bit of x in order. * * Output data-equivalent to in(size(in)-1) (n times) ## ... ## in(1) (n times) ## in(0) (n times) */ - def apply(n: Int, in: Seq[Bool]): UInt = Cat(in.map(Fill(n, _)).reverse) + def apply(@deprecatedName('n, "Chisel 3.5") n: Int, @deprecatedName('in, "Chisel 3.5") in: Seq[Bool]): UInt = Cat( + in.map(Fill(n, _)).reverse + ) } /** Returns the number of bits set (value is 1 or true) in the input signal. @@ -45,9 +48,9 @@ object FillInterleaved { * }}} */ object PopCount { - def apply(in: Iterable[Bool]): UInt = SeqUtils.count(in.toSeq) + def apply(@deprecatedName('in, "Chisel 3.5") in: Iterable[Bool]): UInt = SeqUtils.count(in.toSeq) - def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_))) + def apply(@deprecatedName('in, "Chisel 3.5") in: Bits): UInt = apply((0 until in.getWidth).map(in(_))) } /** Create repetitions of the input using a tree fanout topology. @@ -65,7 +68,7 @@ object Fill { * Output data-equivalent to x ## x ## ... ## x (n repetitions). * @throws java.lang.IllegalArgumentException if `n` is less than zero */ - def apply(n: Int, x: UInt): UInt = { + def apply(@deprecatedName('n, "Chisel 3.5") n: Int, @deprecatedName('x, "Chisel 3.5") x: UInt): UInt = { n match { case _ if n < 0 => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") case 0 => UInt(0.W) @@ -111,5 +114,5 @@ object Reverse { Cat(doit(in(half - 1, 0), half), doit(in(length - 1, half), length - half)) } - def apply(in: UInt): UInt = doit(in, in.getWidth) + def apply(@deprecatedName('in, "Chisel 3.5") in: UInt): UInt = doit(in, in.getWidth) } diff --git a/src/main/scala/chisel3/util/Cat.scala b/src/main/scala/chisel3/util/Cat.scala index c5adce56..3224ec03 100644 --- a/src/main/scala/chisel3/util/Cat.scala +++ b/src/main/scala/chisel3/util/Cat.scala @@ -19,7 +19,9 @@ object Cat { /** Concatenates the argument data elements, in argument order, together. The first argument * forms the most significant bits, while the last argument forms the least significant bits. */ - def apply[T <: Bits](a: T, r: T*): UInt = apply(a :: r.toList) + def apply[T <: Bits](@deprecatedName('a, "Chisel 3.5") a: T, @deprecatedName('r, "Chisel 3.5") r: T*): UInt = apply( + a :: r.toList + ) /** Concatenates the data elements of the input sequence, in reverse sequence order, together. * The first element of the sequence forms the most significant bits, while the last element @@ -28,5 +30,5 @@ object Cat { * Equivalent to r(0) ## r(1) ## ... ## r(n-1). * @note This returns a `0.U` if applied to a zero-element `Vec`. */ - def apply[T <: Bits](r: Seq[T]): UInt = SeqUtils.asUInt(r.reverse) + def apply[T <: Bits](@deprecatedName('r, "Chisel 3.5") r: Seq[T]): UInt = SeqUtils.asUInt(r.reverse) } diff --git a/src/main/scala/chisel3/util/Reg.scala b/src/main/scala/chisel3/util/Reg.scala index ddb74dd6..89381c11 100644 --- a/src/main/scala/chisel3/util/Reg.scala +++ b/src/main/scala/chisel3/util/Reg.scala @@ -12,7 +12,10 @@ object RegEnable { * val regWithEnable = RegEnable(nextVal, ena) * }}} */ - def apply[T <: Data](next: T, enable: Bool): T = { + def apply[T <: Data]( + @deprecatedName('next, "Chisel 3.5") next: T, + @deprecatedName('enable, "Chisel 3.5") enable: Bool + ): T = { val r = Reg(chiselTypeOf(next)) when(enable) { r := next } r @@ -24,7 +27,11 @@ object RegEnable { * val regWithEnableAndReset = RegEnable(nextVal, 0.U, ena) * }}} */ - def apply[T <: Data](next: T, init: T, enable: Bool): T = { + def apply[T <: Data]( + @deprecatedName('next, "Chisel 3.5") next: T, + @deprecatedName('init, "Chisel 3.5") init: T, + @deprecatedName('enable, "Chisel 3.5") enable: Bool + ): T = { val r = RegInit(init) when(enable) { r := next } r @@ -43,7 +50,11 @@ object ShiftRegister { * val regDelayTwo = ShiftRegister(nextVal, 2, ena) * }}} */ - def apply[T <: Data](in: T, n: Int, en: Bool = true.B): T = ShiftRegisters(in, n, en).lastOption.getOrElse(in) + def apply[T <: Data]( + @deprecatedName('in, "Chisel 3.5") in: T, + @deprecatedName('n, "Chisel 3.5") n: Int, + @deprecatedName('en, "Chisel 3.5") en: Bool = true.B + ): T = ShiftRegisters(in, n, en).lastOption.getOrElse(in) /** Returns the n-cycle delayed version of the input signal with reset initialization. * @@ -56,7 +67,12 @@ object ShiftRegister { * val regDelayTwoReset = ShiftRegister(nextVal, 2, 0.U, ena) * }}} */ - def apply[T <: Data](in: T, n: Int, resetData: T, en: Bool): T = + def apply[T <: Data]( + @deprecatedName('in, "Chisel 3.5") in: T, + @deprecatedName('n, "Chisel 3.5") n: Int, + @deprecatedName('resetData, "Chisel 3.5") resetData: T, + @deprecatedName('en, "Chisel 3.5") en: Bool + ): T = ShiftRegisters(in, n, resetData, en).lastOption.getOrElse(in) } @@ -68,7 +84,11 @@ object ShiftRegisters { * @param n number of cycles to delay * @param en enable the shift */ - def apply[T <: Data](in: T, n: Int, en: Bool = true.B): Seq[T] = + def apply[T <: Data]( + @deprecatedName('in, "Chisel 3.5") in: T, + @deprecatedName('n, "Chisel 3.5") n: Int, + @deprecatedName('en, "Chisel 3.5") en: Bool = true.B + ): Seq[T] = Seq.iterate(in, n + 1)(util.RegEnable(_, en)).drop(1) /** Returns delayed input signal registers with reset initialization from 1 to n. @@ -78,6 +98,11 @@ object ShiftRegisters { * @param resetData reset value for each register in the shift * @param en enable the shift */ - def apply[T <: Data](in: T, n: Int, resetData: T, en: Bool): Seq[T] = + def apply[T <: Data]( + @deprecatedName('in, "Chisel 3.5") in: T, + @deprecatedName('n, "Chisel 3.5") n: Int, + @deprecatedName('resetData, "Chisel 3.5") resetData: T, + @deprecatedName('en, "Chisel 3.5") en: Bool + ): Seq[T] = Seq.iterate(in, n + 1)(util.RegEnable(_, resetData, en)).drop(1) } -- cgit v1.2.3 From 7825b432ece7abee9c955f2429046d1c48222437 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 19 May 2022 18:32:30 +0000 Subject: Support := views to DontCare (#2536) (#2539) (cherry picked from commit 77a6c93592d5766d66f199720fc6d69478005091) Co-authored-by: Jack Koenig --- .../scala/chiselTests/experimental/DataView.scala | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src') 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 { -- cgit v1.2.3 From 2453ac10fae363455398dd1ef5bcdb79e6d23f27 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Tue, 24 May 2022 22:02:52 +0000 Subject: Support Vecs of empty Bundles (#2543) (#2545) (cherry picked from commit a1e3a6b5324997864168111bee8c02a60abb0acc) Co-authored-by: Jack Koenig --- src/test/scala/chiselTests/Vec.scala | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src') 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]") + } + } } -- cgit v1.2.3 From 3aed65709aedc22810926751db33fe9ba767a03b Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 27 May 2022 22:06:36 +0000 Subject: Make ExtModule port naming consistent with Module (#2548) (#2549) ExtModule now uses the same namePorts implementation as regular Modules. Previously, ExtModules only allowed port naming via runtime reflection. This meant that .suggestName and other naming APIs do not work. It also breaks FlatIO for ExtModule which is a potential replacement API for BlackBox's special `val io` handling. (cherry picked from commit 83cccfb782d9141bf2c843246c2a525c62392924) Co-authored-by: Jack Koenig --- src/test/scala/chiselTests/ExtModule.scala | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'src') 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") + } } -- cgit v1.2.3 From 0c811b490f47f20f2e81c58706924e56611b6ba2 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Sun, 29 May 2022 22:07:56 +0000 Subject: Deprecate accessing the name of non-hardware Data (#2550) (#2552) This includes (and is tested) for both the old .*Name APIs and .toTarget (cherry picked from commit 6e0d8d6b12e9d8f94c2cc43b92b2366ec70dfd50) Co-authored-by: Jack Koenig --- src/test/scala/chiselTests/InstanceNameSpec.scala | 20 ++++++--- src/test/scala/chiselTests/ToTargetSpec.scala | 52 +++++++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 src/test/scala/chiselTests/ToTargetSpec.scala (limited to 'src') 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/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") + } +} -- cgit v1.2.3 From 97fde23f666a560d4eba9333e4230f901d7f5361 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 1 Jun 2022 20:32:31 +0000 Subject: Add formatted Printable interpolator `cf` (#2528) (#2553) This is a formatted version of the p"..." interpolator analogous to Scala's f"..." interpolator. The primary difference is that it supports formatting interpolated variables by following the variable with "%". For example: printf(cf"myWire = $myWire%x\n") This will format the hardware value "myWire" as a hexidecimal value in the emitted Verilog. Note that literal "%" must be escaped as "%%". Scala types and format specifiers are supported and are handled in the same manner as in standard Scala f"..." interpolators. (cherry picked from commit 037f7b2ff3a46184d1b82e1b590a7572bfa6a76b) Co-authored-by: Girish Pai --- src/test/scala/chiselTests/PrintableSpec.scala | 207 ++++++++++++++++++++----- 1 file changed, 168 insertions(+), 39 deletions(-) (limited to 'src') 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())) => + } + } } -- cgit v1.2.3 From 5bec54e535dca53c9347caddb0b395c4651a0919 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 2 Jun 2022 18:06:03 +0000 Subject: Support VerificationStatement in the naming plugin (#2555) (#2557) Previously, verification statements (assert, assume, cover, and printf) were only named via reflection. (cherry picked from commit 7fa2691f670813eef4ec59fc27c4e4f625d598de) Co-authored-by: Jack Koenig --- src/test/scala/chiselTests/VerificationSpec.scala | 10 +++++----- .../scala/chiselTests/naming/NamePluginSpec.scala | 19 +++++++++++++++++++ src/test/scala/chiselTests/naming/PrefixSpec.scala | 21 +++++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) (limited to 'src') 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/naming/NamePluginSpec.scala b/src/test/scala/chiselTests/naming/NamePluginSpec.scala index 18359fd2..482ef62b 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 { diff --git a/src/test/scala/chiselTests/naming/PrefixSpec.scala b/src/test/scala/chiselTests/naming/PrefixSpec.scala index f9a78f0e..1e628391 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} @@ -391,6 +392,26 @@ 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") } } -- cgit v1.2.3 From 63f25ac4b4d7c9bd530ff1875ad38d835a82e051 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 3 Jun 2022 18:33:13 +0000 Subject: Deprecate implicit .U() and .S() syntax for literal bit extracts (backport #2534) (#2559) * Deprecate .U() and .S() syntax for literal bit extracts (#2534) (cherry picked from commit cadaf33a650ef898fdab2f81244e4ad6a07a9ea8) # Conflicts: # macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala * Fix backport conflict (#2560) Co-authored-by: Jared Barocsi <82000041+jared-barocsi@users.noreply.github.com>--- src/test/scala/chiselTests/SIntOps.scala | 15 ++++++++++++--- src/test/scala/chiselTests/UIntOps.scala | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/SIntOps.scala b/src/test/scala/chiselTests/SIntOps.scala index 55b4c915..580a6e34 100644 --- a/src/test/scala/chiselTests/SIntOps.scala +++ b/src/test/scala/chiselTests/SIntOps.scala @@ -85,9 +85,18 @@ 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({ + val lit = -5.S + lit(1) === true.B + }) + assert({ + val lit = -5.S + lit(2) === false.B + }) + assert({ + val lit = -5.S + lit(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/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala index 0010e9ac..6569c9e7 100644 --- a/src/test/scala/chiselTests/UIntOps.scala +++ b/src/test/scala/chiselTests/UIntOps.scala @@ -172,9 +172,18 @@ 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({ + val lit = "b101010".U + lit(2) === false.B + }) + assert({ + val lit = "b101010".U + lit(3) === true.B + }) + assert({ + val lit = "b101010".U + lit(100) === false.B + }) assert("b101010".U(3, 0) === "b1010".U) assert("b101010".U(9, 0) === "b0000101010".U) -- cgit v1.2.3 From 42f5d89045e7db323670964a982c59319cf9001f Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Mon, 6 Jun 2022 23:02:01 +0000 Subject: Add --warn:reflective-naming (backport #2561) (#2565) * Factor buildName into reusable function The new function is chisel3.internal.buildName. (cherry picked from commit 370ca8ac68f6d888dd99e1b9e63f0371add398cf) * Add --warn:reflective-naming This new argument (and associated annotation) will turn on a warning whenever reflective naming changes the name of a signal. This is provided to help migrate from Chisel 3.5 to 3.6 since reflective naming is removed in Chisel 3.6. (cherry picked from commit 97afd9b9a1155fa7cd5cedf19f9e0c15fbe899ec) Co-authored-by: Jack Koenig --- .../chisel3/aop/injecting/InjectingAspect.scala | 3 +- .../scala/chisel3/stage/ChiselAnnotations.scala | 16 ++ src/main/scala/chisel3/stage/ChiselCli.scala | 1 + src/main/scala/chisel3/stage/ChiselOptions.scala | 23 +-- src/main/scala/chisel3/stage/package.scala | 11 +- .../scala/chisel3/stage/phases/Elaborate.scala | 4 +- .../chiselTests/naming/ReflectiveNamingSpec.scala | 161 +++++++++++++++++++++ 7 files changed, 202 insertions(+), 17 deletions(-) create mode 100644 src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala (limited to 'src') diff --git a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala index ba873c23..087bdae2 100644 --- a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala +++ b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala @@ -58,7 +58,8 @@ abstract class InjectorAspect[T <: RawModule, M <: RawModule]( final def toAnnotation(modules: Iterable[M], circuit: String, moduleNames: Seq[String]): AnnotationSeq = { RunFirrtlTransformAnnotation(new InjectingTransform) +: modules.map { module => val chiselOptions = view[ChiselOptions](annotationsInAspect) - val dynamicContext = new DynamicContext(annotationsInAspect, chiselOptions.throwOnFirstError) + val dynamicContext = + new DynamicContext(annotationsInAspect, chiselOptions.throwOnFirstError, chiselOptions.warnReflectiveNaming) // Add existing module names into the namespace. If injection logic instantiates new modules // which would share the same name, they will get uniquified accordingly moduleNames.foreach { n => diff --git a/src/main/scala/chisel3/stage/ChiselAnnotations.scala b/src/main/scala/chisel3/stage/ChiselAnnotations.scala index e046319d..eda05a7d 100644 --- a/src/main/scala/chisel3/stage/ChiselAnnotations.scala +++ b/src/main/scala/chisel3/stage/ChiselAnnotations.scala @@ -79,6 +79,22 @@ case object ThrowOnFirstErrorAnnotation } +/** Warn when reflective naming changes names of signals */ +case object WarnReflectiveNamingAnnotation + extends NoTargetAnnotation + with ChiselOption + with HasShellOptions + with Unserializable { + + val options = Seq( + new ShellOption[Unit]( + longOption = "warn:reflective-naming", + toAnnotationSeq = _ => Seq(this), + helpText = "Warn when reflective naming changes the name of signals (3.6 migration)" + ) + ) +} + /** An [[firrtl.annotations.Annotation]] storing a function that returns a Chisel module * @param gen a generator function */ diff --git a/src/main/scala/chisel3/stage/ChiselCli.scala b/src/main/scala/chisel3/stage/ChiselCli.scala index f38bf50c..8c5eb79a 100644 --- a/src/main/scala/chisel3/stage/ChiselCli.scala +++ b/src/main/scala/chisel3/stage/ChiselCli.scala @@ -10,6 +10,7 @@ trait ChiselCli { this: Shell => NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation, ThrowOnFirstErrorAnnotation, + WarnReflectiveNamingAnnotation, ChiselOutputFileAnnotation, ChiselGeneratorAnnotation ) diff --git a/src/main/scala/chisel3/stage/ChiselOptions.scala b/src/main/scala/chisel3/stage/ChiselOptions.scala index 7e4305fa..a03f3d7b 100644 --- a/src/main/scala/chisel3/stage/ChiselOptions.scala +++ b/src/main/scala/chisel3/stage/ChiselOptions.scala @@ -5,24 +5,27 @@ package chisel3.stage import chisel3.internal.firrtl.Circuit class ChiselOptions private[stage] ( - val runFirrtlCompiler: Boolean = true, - val printFullStackTrace: Boolean = false, - val throwOnFirstError: Boolean = false, - val outputFile: Option[String] = None, - val chiselCircuit: Option[Circuit] = None) { + val runFirrtlCompiler: Boolean = true, + val printFullStackTrace: Boolean = false, + val throwOnFirstError: Boolean = false, + val warnReflectiveNaming: Boolean = false, + val outputFile: Option[String] = None, + val chiselCircuit: Option[Circuit] = None) { private[stage] def copy( - runFirrtlCompiler: Boolean = runFirrtlCompiler, - printFullStackTrace: Boolean = printFullStackTrace, - throwOnFirstError: Boolean = throwOnFirstError, - outputFile: Option[String] = outputFile, - chiselCircuit: Option[Circuit] = chiselCircuit + runFirrtlCompiler: Boolean = runFirrtlCompiler, + printFullStackTrace: Boolean = printFullStackTrace, + throwOnFirstError: Boolean = throwOnFirstError, + warnReflectiveNaming: Boolean = warnReflectiveNaming, + outputFile: Option[String] = outputFile, + chiselCircuit: Option[Circuit] = chiselCircuit ): ChiselOptions = { new ChiselOptions( runFirrtlCompiler = runFirrtlCompiler, printFullStackTrace = printFullStackTrace, throwOnFirstError = throwOnFirstError, + warnReflectiveNaming = warnReflectiveNaming, outputFile = outputFile, chiselCircuit = chiselCircuit ) diff --git a/src/main/scala/chisel3/stage/package.scala b/src/main/scala/chisel3/stage/package.scala index b1064c05..10c8c524 100644 --- a/src/main/scala/chisel3/stage/package.scala +++ b/src/main/scala/chisel3/stage/package.scala @@ -15,11 +15,12 @@ package object stage { def view(options: AnnotationSeq): ChiselOptions = options.collect { case a: ChiselOption => a } .foldLeft(new ChiselOptions()) { (c, x) => x match { - case NoRunFirrtlCompilerAnnotation => c.copy(runFirrtlCompiler = false) - case PrintFullStackTraceAnnotation => c.copy(printFullStackTrace = true) - case ThrowOnFirstErrorAnnotation => c.copy(throwOnFirstError = true) - case ChiselOutputFileAnnotation(f) => c.copy(outputFile = Some(f)) - case ChiselCircuitAnnotation(a) => c.copy(chiselCircuit = Some(a)) + case NoRunFirrtlCompilerAnnotation => c.copy(runFirrtlCompiler = false) + case PrintFullStackTraceAnnotation => c.copy(printFullStackTrace = true) + case ThrowOnFirstErrorAnnotation => c.copy(throwOnFirstError = true) + case WarnReflectiveNamingAnnotation => c.copy(warnReflectiveNaming = true) + case ChiselOutputFileAnnotation(f) => c.copy(outputFile = Some(f)) + case ChiselCircuitAnnotation(a) => c.copy(chiselCircuit = Some(a)) } } diff --git a/src/main/scala/chisel3/stage/phases/Elaborate.scala b/src/main/scala/chisel3/stage/phases/Elaborate.scala index 55331cb4..ba29e5f2 100644 --- a/src/main/scala/chisel3/stage/phases/Elaborate.scala +++ b/src/main/scala/chisel3/stage/phases/Elaborate.scala @@ -29,8 +29,10 @@ class Elaborate extends Phase { case ChiselGeneratorAnnotation(gen) => val chiselOptions = view[ChiselOptions](annotations) try { + val context = + new DynamicContext(annotations, chiselOptions.throwOnFirstError, chiselOptions.warnReflectiveNaming) val (circuit, dut) = - Builder.build(Module(gen()), new DynamicContext(annotations, chiselOptions.throwOnFirstError)) + Builder.build(Module(gen()), context) Seq(ChiselCircuitAnnotation(circuit), DesignAnnotation(dut)) } catch { /* if any throwable comes back and we're in "stack trace trimming" mode, then print an error and trim the stack trace 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") + } +} -- cgit v1.2.3 From 205d8bb34b2ac2acaef6d318a4f9e3aee181110e Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Tue, 7 Jun 2022 23:11:54 +0000 Subject: Add single argument Bits.extract (#2566) (#2568) (cherry picked from commit 255c56c3955a8c16191a6751e7d547cfcfd96705) Co-authored-by: Jared Barocsi <82000041+jared-barocsi@users.noreply.github.com>--- src/test/scala/chiselTests/SIntOps.scala | 15 +++------------ src/test/scala/chiselTests/UIntOps.scala | 15 +++------------ 2 files changed, 6 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/SIntOps.scala b/src/test/scala/chiselTests/SIntOps.scala index 580a6e34..ebbd2012 100644 --- a/src/test/scala/chiselTests/SIntOps.scala +++ b/src/test/scala/chiselTests/SIntOps.scala @@ -85,18 +85,9 @@ class SIntOpsTester(c: SIntOps) extends Tester(c) { */ class SIntLitExtractTester extends BasicTester { - assert({ - val lit = -5.S - lit(1) === true.B - }) - assert({ - val lit = -5.S - lit(2) === false.B - }) - assert({ - val lit = -5.S - lit(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/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala index 6569c9e7..2f55da9a 100644 --- a/src/test/scala/chiselTests/UIntOps.scala +++ b/src/test/scala/chiselTests/UIntOps.scala @@ -172,18 +172,9 @@ class MatchedRotateLeftAndRight(w: Int = 13) extends BasicTester { } class UIntLitExtractTester extends BasicTester { - assert({ - val lit = "b101010".U - lit(2) === false.B - }) - assert({ - val lit = "b101010".U - lit(3) === true.B - }) - assert({ - val lit = "b101010".U - lit(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) -- cgit v1.2.3 From a689c7c0dd336fe0b9db6171786993b190a700f8 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 8 Jun 2022 20:09:45 +0000 Subject: Added migration for inferModuleReset (#2571) (#2573) Co-authored-by: Jack Koenig (cherry picked from commit 3c6c044b6bdee850ad9ba375324abaf3813c557d) Co-authored-by: Adam Izraelevitz --- .../chiselTests/MigrateCompileOptionsSpec.scala | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala (limited to 'src') diff --git a/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala b/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala new file mode 100644 index 00000000..3757c360 --- /dev/null +++ b/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chiselTests + +import chisel3.stage.ChiselStage + +import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks + +class MigrateCompileOptionsSpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyChecks with Utils { + import Chisel.{defaultCompileOptions => _, _} + import chisel3.RequireSyncReset + + behavior.of("Migrating infer resets") + + 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 + } + + it should "error if migrating, but not extended RequireSyncReset" in { + implicit val options = migrateIR + class Foo extends Module { + val io = new Bundle {} + } + intercept[Exception] { + ChiselStage.elaborate(new Foo) + } + } + it should "not error if migrating, and you mix with RequireSyncReset" in { + implicit val options = migrateIR + class Foo extends Module with RequireSyncReset { + val io = new Bundle {} + } + ChiselStage.elaborate(new Foo) + } +} -- cgit v1.2.3 From 4b8981d627fc307161ff39b78836e37212803756 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Sat, 11 Jun 2022 00:13:36 +0000 Subject: Micro-optimize BitPat.rawString (#2577) (#2578) BitPat.rawString is called a lot when decoding and is used for certain BitPat operations. We should use it less but this is at least a bandaid. (cherry picked from commit c11af20fe5b211ec72ba00f3ce0880d7933e566b) Co-authored-by: Jack Koenig --- src/main/scala/chisel3/util/BitPat.scala | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index d27fee14..33dd5b2b 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -348,15 +348,29 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int) override def isEmpty: Boolean = false /** Generate raw string of a [[BitPat]]. */ - def rawString: String = Seq - .tabulate(width) { i => - (value.testBit(width - i - 1), mask.testBit(width - i - 1)) match { - case (true, true) => "1" - case (false, true) => "0" - case (_, false) => "?" - } + def rawString: String = _rawString + + // This is micro-optimized and memoized because it is used for lots of BitPat operations + private lazy val _rawString: String = { + val sb = new StringBuilder(width) + var i = 0 + while (i < width) { + val bitIdx = width - i - 1 + val char = + if (mask.testBit(bitIdx)) { + if (value.testBit(bitIdx)) { + '1' + } else { + '0' + } + } else { + '?' + } + sb += char + i += 1 } - .mkString + sb.result() + } override def toString = s"BitPat($rawString)" } -- cgit v1.2.3 From 13641d95951b189d7f5b0d4d99ace45f8b8f6282 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Mon, 13 Jun 2022 19:11:33 +0000 Subject: Add ImplicitInvalidate, to help migrate the explicitInvalidate compiler option (#2575) (#2579) * Added ImplicitInvalidate trait with tests (cherry picked from commit 1356ced1b89ca35ae0cb1d1ab45227ec1776d5e7) Co-authored-by: Adam Izraelevitz --- .../chiselTests/MigrateCompileOptionsSpec.scala | 138 +++++++++++++++++---- 1 file changed, 114 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala b/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala index 3757c360..091f7f28 100644 --- a/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala +++ b/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala @@ -3,41 +3,131 @@ package chiselTests import chisel3.stage.ChiselStage +import chisel3.ImplicitInvalidate +import chisel3.ExplicitCompileOptions import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks -class MigrateCompileOptionsSpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyChecks with Utils { - import Chisel.{defaultCompileOptions => _, _} - import chisel3.RequireSyncReset +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 - behavior.of("Migrating infer resets") + override val migrateInferModuleReset = true + } - 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 + 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 - override val migrateInferModuleReset = true + 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) + } + } } +} - it should "error if migrating, but not extended RequireSyncReset" in { - implicit val options = migrateIR - class Foo extends Module { - val io = new Bundle {} +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) } } - intercept[Exception] { - ChiselStage.elaborate(new Foo) + it("(0.b): Not error if migrating, and you mix with RequireSyncReset") { + ChiselStage.elaborate(new FooWithRequireSyncReset) } } - it should "not error if migrating, and you mix with RequireSyncReset" in { - implicit val options = migrateIR - class Foo extends Module with RequireSyncReset { - val io = new Bundle {} + + 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) } - ChiselStage.elaborate(new Foo) } } -- cgit v1.2.3 From d001b34f816f1f65d0625aebf33e5cfc5ba93e49 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 16 Jun 2022 23:15:42 +0000 Subject: Define leading '_' as API for creating temporaries (backport #2580) (#2581) * Define leading '_' as API for creating temporaries Chisel and FIRRTL have long used signals with names beginning with an underscore as an API to specify that the name does not really matter. Tools like Verilator follow a similar convention and exclude signals with underscore names from waveform dumps by default. With the introduction of compiler-plugin prefixing in Chisel 3.4, the convention remained but was hard for users to use unless the unnnamed signal existed outside of any prefix domain. Notably, unnamed signals are most useful when creating wires inside of utility methods which almost always results in the signal ending up with a prefix. With this commit, Chisel explicitly recognizes signals whos val names start with an underscore and preserve that underscore regardless of any prefixing. Chisel will also ignore such underscores when generating prefixes based on the temporary signal, preventing accidental double underscores in the names of signals that are prefixed by the temporary. (cherry picked from commit bd94366290886f3489d58f88b9768c7c11fa2cb6) * Remove unused defaultPrefix argument from _computeName (cherry picked from commit ec178aa20a830df2c8c756b9e569709a59073554) # Conflicts: # core/src/main/scala/chisel3/Module.scala # core/src/main/scala/chisel3/experimental/hierarchy/ModuleClone.scala * Resolve backport conflicts * Waive false positive binary compatibility errors Co-authored-by: Jack Koenig --- .../scala/chiselTests/naming/NamePluginSpec.scala | 19 +++++ src/test/scala/chiselTests/naming/PrefixSpec.scala | 93 ++++++++++++++++++++-- 2 files changed, 107 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/naming/NamePluginSpec.scala b/src/test/scala/chiselTests/naming/NamePluginSpec.scala index 482ef62b..a787bb80 100644 --- a/src/test/scala/chiselTests/naming/NamePluginSpec.scala +++ b/src/test/scala/chiselTests/naming/NamePluginSpec.scala @@ -340,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 1e628391..6d52407e 100644 --- a/src/test/scala/chiselTests/naming/PrefixSpec.scala +++ b/src/test/scala/chiselTests/naming/PrefixSpec.scala @@ -233,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")) } } @@ -414,4 +442,59 @@ class PrefixSpec extends ChiselPropSpec with Utils { (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")) + } + } } -- cgit v1.2.3 From ea44af954657f743c45fbc45125e197ac3aadd20 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Sat, 18 Jun 2022 00:08:41 +0000 Subject: Handle varargs constructor arguments in Bundle plugin (#2585) (#2588) Previously, the plugin would crash with a useless internal error. (cherry picked from commit 9fcfb252beb9f06d8d1409fe7db9c8b3b6b962ce) Co-authored-by: Jack Koenig --- src/test/scala/chiselTests/AutoClonetypeSpec.scala | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src') 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) + } } -- cgit v1.2.3 From 7e67ca1ef93e53d4b9b6f8e13a21d69e0c5daac4 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 22 Jun 2022 02:01:31 +0000 Subject: Pass optional name in ImportDefinitionAnno (#2592) (#2594) Used for separate elaboration of Definition and Instance (cherry picked from commit 48d57cc8db6f38fdf0e23b7dce36caa404c871b8) Co-authored-by: Girish Pai --- .../hierarchy/SeparateElaborationSpec.scala | 139 +++++++++++++++++++++ 1 file changed, 139 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala index 7555a1c4..25bbc474 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala @@ -353,4 +353,143 @@ class SeparateElaborationSpec extends ChiselFunSpec with Utils { ) } + 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" + ) + } } -- cgit v1.2.3 From 1924909e9fec213577cc74970f8cd9c2cf9780c4 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 23 Jun 2022 18:50:35 +0000 Subject: Add DataMirror isIO, isReg, isWire (#2601) (#2602) (cherry picked from commit 7fa0d8bf1cafcdf141046476a100abf021bdcac4) Co-authored-by: Zachary Yedidia --- .../chiselTests/experimental/DataMirrorSpec.scala | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/test/scala/chiselTests/experimental/DataMirrorSpec.scala (limited to 'src') 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) + } +} -- cgit v1.2.3 From 3063a1b853726e0bc65d7211ea2e584275774412 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Mon, 27 Jun 2022 16:38:41 +0000 Subject: Deprecate TransitName (backport #2603) (#2606) * Deprecate TransitName (#2603) * Deprecate TransitName * Add @nowarn macros to usages of TransitName in the repo Co-authored-by: Jack Koenig (cherry picked from commit a0b05190e5303ec28a0c7abe645d81e9a72023ff) * Update src/main/scala/chisel3/util/Valid.scala * Update src/main/scala/chisel3/util/Valid.scala Co-authored-by: Megan Wachs --- src/main/scala/chisel3/util/Decoupled.scala | 3 +++ src/main/scala/chisel3/util/TransitName.scala | 11 +++++++++++ src/main/scala/chisel3/util/Valid.scala | 3 +++ 3 files changed, 17 insertions(+) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 5c71a4ea..42717b66 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -9,6 +9,8 @@ import chisel3._ import chisel3.experimental.{requireIsChiselType, DataMirror, Direction} import chisel3.internal.naming._ // can't use chisel3_ version because of compile order +import scala.annotation.nowarn + /** An I/O Bundle containing 'valid' and 'ready' signals that handshake * the transfer of data stored in the 'bits' subfield. * The base protocol implied by the directionality is that @@ -342,6 +344,7 @@ object Queue { * consumer.io.in <> Queue(producer.io.out, 16) * }}} */ + @nowarn("cat=deprecation&msg=TransitName") @chiselName def apply[T <: Data]( enq: ReadyValidIO[T], diff --git a/src/main/scala/chisel3/util/TransitName.scala b/src/main/scala/chisel3/util/TransitName.scala index cc8f2456..8b509db5 100644 --- a/src/main/scala/chisel3/util/TransitName.scala +++ b/src/main/scala/chisel3/util/TransitName.scala @@ -42,6 +42,12 @@ object TransitName { * @param to the thing that will receive the "good" name * @return the `from` parameter */ + @deprecated( + "Use suggestName or rely on the naming plugin instead of this function: \n" + + " val from = {to}\n" + + " val from = prefix(prefixYouWant){to}", + "Chisel 3.5.4" + ) def apply[T <: HasId](from: T, to: HasId): T = { // To transit a name, we need to hook on both the suggestName and autoSeed mechanisms from.addSuggestPostnameHook((given_name: String) => { to.suggestName(given_name) }) @@ -55,6 +61,11 @@ object TransitName { * @param to the thing that will receive the "good" name * @return the `from` parameter */ + @deprecated( + "Use suggestName or rely on the naming plugin instead of this function. Use prefix instead of suffix: \n" + + " val from = prefix(prefixYouWant){to}", + "Chisel 3.5.4" + ) def withSuffix[T <: HasId](suffix: String)(from: T, to: HasId): T = { // To transit a name, we need to hook on both the suggestName and autoSeed mechanisms from.addSuggestPostnameHook((given_name: String) => { to.suggestName(given_name + suffix) }) diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala index eeb2ab68..cb0e166a 100644 --- a/src/main/scala/chisel3/util/Valid.scala +++ b/src/main/scala/chisel3/util/Valid.scala @@ -7,6 +7,8 @@ package chisel3.util import chisel3._ +import scala.annotation.nowarn + /** A [[Bundle]] that adds a `valid` bit to some data. This indicates that the user expects a "valid" interface between * a producer and a consumer. Here, the producer asserts the `valid` bit when data on the `bits` line contains valid * data. This differs from [[DecoupledIO]] or [[IrrevocableIO]] as there is no `ready` line that the consumer can use @@ -116,6 +118,7 @@ object Pipe { * @param latency the number of pipeline stages * @return $returnType */ + @nowarn("cat=deprecation&msg=TransitName") def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int)(implicit compileOptions: CompileOptions): Valid[T] = { require(latency >= 0, "Pipe latency must be greater than or equal to zero!") if (latency == 0) { -- cgit v1.2.3 From 2b977a74293a49e9e2a5d960a6a9c07df22430ce Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 6 Jul 2022 00:28:02 +0000 Subject: Implement trait for Chisel compiler to name arbitrary non-Data types (#2610) (#2617) Co-authored-by: Jack Koenig Co-authored-by: Megan Wachs (cherry picked from commit 3ab34cddd8b87c22d5fc31020f10ddb2f1990d51) Co-authored-by: Jared Barocsi <82000041+jared-barocsi@users.noreply.github.com>--- src/main/scala/chisel3/util/Counter.scala | 4 +-- .../scala/chiselTests/NamingAnnotationTest.scala | 31 ++++++++-------------- 2 files changed, 13 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Counter.scala b/src/main/scala/chisel3/util/Counter.scala index ef1eff9f..0d1b8db1 100644 --- a/src/main/scala/chisel3/util/Counter.scala +++ b/src/main/scala/chisel3/util/Counter.scala @@ -3,6 +3,7 @@ package chisel3.util import chisel3._ +import chisel3.experimental.AffectsChiselPrefix import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order /** Used to generate an inline (logic directly in the containing Module, no internal Module is created) @@ -27,8 +28,7 @@ import chisel3.internal.naming.chiselName // can't use chisel3_ version because * } * }}} */ -@chiselName -class Counter private (r: Range, oldN: Option[Int] = None) { +class Counter private (r: Range, oldN: Option[Int] = None) extends AffectsChiselPrefix { require(r.length > 0, s"Counter range cannot be empty, got: $r") require(r.start >= 0 && r.end >= 0, s"Counter range must be positive, got: $r") 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 -- cgit v1.2.3 From 4f10bdd703d7559cddae50541cf7c8e0a1c1d4c0 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 6 Jul 2022 21:42:13 +0000 Subject: Refactor TruthTable.apply and add factory method for Espresso (backport #2612) (#2620) * Refactor TruthTable.apply and add factory method for Espresso (#2612) Improves performance of creating TruthTables by processing entire BitPats rather than individual bits. New TruthTable factory method enables constructing TruthTables with semantics of OR-ing output BitPats together rather than erroring when multiple terms have the same input BitPat. This alternative factory method matches semantics for the output format of Espresso. Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig (cherry picked from commit 231f14e74f112a9f721e774561126b2bd1250039) # Conflicts: # src/main/scala/chisel3/util/BitPat.scala * Resolve backport conflicts Co-authored-by: Aditya Naik <91489422+adkian-sifive@users.noreply.github.com>--- src/main/scala/chisel3/util/BitPat.scala | 5 + .../experimental/decode/EspressoMinimizer.scala | 2 +- .../util/experimental/decode/TruthTable.scala | 117 ++++++++++++++++----- .../util/experimental/TruthTableSpec.scala | 17 +++ 4 files changed, 112 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 33dd5b2b..7cb80e54 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -5,6 +5,8 @@ package chisel3.util import scala.language.experimental.macros import chisel3._ import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} +import scala.collection.mutable +import scala.util.hashing.MurmurHash3 object BitPat { @@ -253,6 +255,9 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int) def =/=(that: UInt): Bool = macro SourceInfoTransform.thatArg def ##(that: BitPat): BitPat = macro SourceInfoTransform.thatArg + override def hashCode: Int = + MurmurHash3.seqHash(Seq(this.value, this.mask, this.width)) + /** @group SourceInfoTransformMacro */ def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): BitPat = { do_apply(x, x) diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala index 86973e5b..8c85b6d1 100644 --- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala @@ -87,6 +87,6 @@ object EspressoMinimizer extends Minimizer with LazyLogging { logger.trace(s"""espresso output table: |$output |""".stripMargin) - TruthTable(readTable(output), table.default) + TruthTable.fromEspressoOutput(readTable(output), table.default) } } diff --git a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala index 00fa0f9c..2720e690 100644 --- a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala +++ b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala @@ -3,6 +3,7 @@ package chisel3.util.experimental.decode import chisel3.util.BitPat +import scala.collection.mutable sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default: BitPat, val sort: Boolean) { def inputWidth = table.head._1.getWidth @@ -29,40 +30,89 @@ sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default: object TruthTable { - /** Convert a table and default output into a [[TruthTable]]. */ - def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = { + /** Pad the input signals to equalize all input widths. Pads input signals + * to the maximum width found in the table. + * + * @param table the truth table whose rows will be padded + * @return the same truth table but with inputs padded + */ + private def padInputs(table: Iterable[(BitPat, BitPat)]): Iterable[(BitPat, BitPat)] = { val inputWidth = table.map(_._1.getWidth).max - require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.") - val outputWidth = table.map(_._2.getWidth).head - val mergedTable = table.map { - // pad input signals if necessary + table.map { case (in, out) if inputWidth > in.width => (BitPat.N(inputWidth - in.width) ## in, out) case (in, out) => (in, out) } - .groupBy(_._1.toString) - .map { - case (key, values) => - // merge same input inputs. - values.head._1 -> BitPat(s"b${Seq - .tabulate(outputWidth) { i => - val outputSet = values - .map(_._2) - .map(_.rawString) - .map(_(i)) - .toSet - .filterNot(_ == '?') - require( - outputSet.size != 2, - s"TruthTable conflict in :\n${values.map { case (i, o) => s"${i.rawString}->${o.rawString}" }.mkString("\n")}" - ) - outputSet.headOption.getOrElse('?') - } - .mkString}") - } - .toSeq + } + + /** For each duplicated input, collect the outputs into a single Seq. + * + * @param table the truth table + * @return a Seq of tuple of length 2, where the first element is the + * input and the second element is a Seq of OR-ed outputs + * for the input + */ + private def mergeTableOnInputs(table: Iterable[(BitPat, BitPat)]): Seq[(BitPat, Seq[BitPat])] = { + groupByIntoSeq(table)(_._1).map { + case (input, mappings) => + input -> mappings.map(_._2) + } + } + + /** Merge two BitPats by OR-ing the values and masks, and setting the + * width to the max width among the two + */ + private def merge(a: BitPat, b: BitPat): BitPat = { + new BitPat(a.value | b.value, a.mask | b.mask, a.width.max(b.width)) + } + + /** Public method for calling with the Espresso decoder format fd + * + * For Espresso, for each output, a 1 means this product term belongs to the ON-set, + * a 0 means this product term has no meaning for the value of this function. + * This is the same as the fd (or f) type in espresso. + * + * @param table the truth table + * @param default the default BitPat is made up of a single bit type, either "?", "0" or "1". + * A default of "?" sets Espresso to fr-format, while a "0" or "1" sets it to the + * fd-format. + * @param sort whether to sort the final truth table using BitPat.bitPatOrder + * @return a fully built TruthTable + */ + def fromEspressoOutput(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = { + apply_impl(table, default, sort, false) + } + + /** Public apply method to TruthTable. Calls apply_impl with the default value true of checkCollisions */ + def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = { + apply_impl(table, default, sort, true) + } + + /** Convert a table and default output into a [[TruthTable]]. */ + private def apply_impl( + table: Iterable[(BitPat, BitPat)], + default: BitPat, + sort: Boolean, + checkCollisions: Boolean + ): TruthTable = { + val paddedTable = padInputs(table) + + require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.") + + val mergedTable = mergeTableOnInputs(paddedTable) + + val finalTable: Seq[(BitPat, BitPat)] = mergedTable.map { + case (input, outputs) => + val (result, noCollisions) = outputs.tail.foldLeft((outputs.head, checkCollisions)) { + case ((acc, ok), o) => (merge(acc, o), ok && acc.overlap(o)) + } + // Throw an error if checkCollisions is true but there are bits with a non-zero overlap. + require(!checkCollisions || noCollisions, s"TruthTable conflict on merged row:\n $input -> $outputs") + (input, result) + } + import BitPat.bitPatOrder - new TruthTable(if (sort) mergedTable.sorted else mergedTable, default, sort) + new TruthTable(if (sort) finalTable.sorted else finalTable, default, sort) } /** Parse TruthTable from its string representation. */ @@ -140,4 +190,15 @@ object TruthTable { bitPat(tables.flatMap { case (table, indexes) => table.default.rawString.zip(indexes) }) ) } + + /** Similar to Seq.groupBy except that it preserves ordering of elements within each group */ + private def groupByIntoSeq[A, K](xs: Iterable[A])(f: A => K): Seq[(K, Seq[A])] = { + val map = mutable.LinkedHashMap.empty[K, mutable.ListBuffer[A]] + for (x <- xs) { + val key = f(x) + val l = map.getOrElseUpdate(key, mutable.ListBuffer.empty[A]) + l += x + } + map.view.map({ case (k, vs) => k -> vs.toList }).toList + } } 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) + ) + } } -- cgit v1.2.3 From 94aeeb1a5c2fe38777a9004ba36f8b353e96b292 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 8 Jul 2022 23:44:45 +0000 Subject: CompileOptions: add and use emitStrictConnects (#2622) (#2623) (cherry picked from commit 11e8cc60d6268301cff352b8a1d7c4d672b5be11) Co-authored-by: Megan Wachs --- .../CompatibilityInteroperabilitySpec.scala | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src') 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)) + } } -- cgit v1.2.3 From dbffb8779efca6bea8699ed80a04b1d47d657d93 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 13 Jul 2022 20:39:44 +0000 Subject: New enhanced API for specifying Chisel to Firrtl Annotations (#2628) (#2631) (cherry picked from commit 4b10cf7a276e90b280c1fd57070566acac3d80d3) Co-authored-by: Girish Pai --- .../scala/chiselTests/NewAnnotationsSpec.scala | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/test/scala/chiselTests/NewAnnotationsSpec.scala (limited to 'src') 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") + + } + } +} -- cgit v1.2.3 From 80035d2a7b94faf9bfef962f83f9257f57419a35 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Thu, 14 Jul 2022 08:30:13 -0700 Subject: 3.5x: Make explicit copy constructors for ExplicitCompileOptions (#2629) * Add copy constructors for compile options * Add tests for the copy constructors Co-authored-by: Jiuyang Liu --- .../scala/chiselTests/CompileOptionsTest.scala | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src') 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) + } + } -- cgit v1.2.3 From f46d02f55bd22ffda32b20e8cc4b40aa96b03ee0 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 21 Jul 2022 14:16:11 -0700 Subject: Deprecate chiselName and NoChiselNamePrefix trait (#2627) (#2633) Also remove all non-testing uses of chiselName. (cherry picked from commit 1c5d1b5317a0c9fe7ef9d15138065a817380a1e4) Co-authored-by: Jared Barocsi <82000041+jared-barocsi@users.noreply.github.com>--- src/main/scala/chisel3/util/Arbiter.scala | 3 --- src/main/scala/chisel3/util/CircuitMath.scala | 2 -- src/main/scala/chisel3/util/Counter.scala | 3 --- src/main/scala/chisel3/util/Decoupled.scala | 2 -- src/test/scala/chiselTests/StrongEnum.scala | 5 ++--- 5 files changed, 2 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala index 220a12b1..06821a25 100644 --- a/src/main/scala/chisel3/util/Arbiter.scala +++ b/src/main/scala/chisel3/util/Arbiter.scala @@ -6,7 +6,6 @@ package chisel3.util import chisel3._ -import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order /** IO bundle definition for an Arbiter, which takes some number of ready-valid inputs and outputs * (selects) at most one. @@ -115,7 +114,6 @@ class LockingArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T * consumer.io.in <> arb.io.out * }}} */ -@chiselName class RRArbiter[T <: Data](val gen: T, val n: Int) extends LockingRRArbiter[T](gen, n, 1) /** Hardware module that is used to sequence n producers into 1 consumer. @@ -131,7 +129,6 @@ class RRArbiter[T <: Data](val gen: T, val n: Int) extends LockingRRArbiter[T](g * consumer.io.in <> arb.io.out * }}} */ -@chiselName class Arbiter[T <: Data](val gen: T, val n: Int) extends Module { val io = IO(new ArbiterIO(gen, n)) diff --git a/src/main/scala/chisel3/util/CircuitMath.scala b/src/main/scala/chisel3/util/CircuitMath.scala index df60f059..9e4890a9 100644 --- a/src/main/scala/chisel3/util/CircuitMath.scala +++ b/src/main/scala/chisel3/util/CircuitMath.scala @@ -6,7 +6,6 @@ package chisel3.util import chisel3._ -import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order /** Returns the base-2 integer logarithm of an UInt. * @@ -22,7 +21,6 @@ object Log2 { /** Returns the base-2 integer logarithm of the least-significant `width` bits of an UInt. */ - @chiselName def apply(x: Bits, width: Int): UInt = { if (width < 2) { 0.U diff --git a/src/main/scala/chisel3/util/Counter.scala b/src/main/scala/chisel3/util/Counter.scala index 0d1b8db1..be6e3257 100644 --- a/src/main/scala/chisel3/util/Counter.scala +++ b/src/main/scala/chisel3/util/Counter.scala @@ -4,7 +4,6 @@ package chisel3.util import chisel3._ import chisel3.experimental.AffectsChiselPrefix -import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order /** Used to generate an inline (logic directly in the containing Module, no internal Module is created) * hardware counter. @@ -113,7 +112,6 @@ object Counter { * @return tuple of the counter value and whether the counter will wrap (the value is at * maximum and the condition is true). */ - @chiselName def apply(cond: Bool, n: Int): (UInt, Bool) = { val c = new Counter(n) val wrap = WireInit(false.B) @@ -129,7 +127,6 @@ object Counter { * @return tuple of the counter value and whether the counter will wrap (the value is at * maximum and the condition is true). */ - @chiselName def apply(r: Range, enable: Bool = true.B, reset: Bool = false.B): (UInt, Bool) = { val c = new Counter(r) val wrap = WireInit(false.B) diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 42717b66..f02a4116 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -233,7 +233,6 @@ class QueueIO[T <: Data]( * consumer.io.in <> q.io.deq * }}} */ -@chiselName class Queue[T <: Data]( val gen: T, val entries: Int, @@ -345,7 +344,6 @@ object Queue { * }}} */ @nowarn("cat=deprecation&msg=TransitName") - @chiselName def apply[T <: Data]( enq: ReadyValidIO[T], entries: Int = 2, 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) -- cgit v1.2.3 From e52739f2fe587cedd657a331b7d7ba0c75b919c6 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 28 Jul 2022 22:27:29 +0000 Subject: Implement DecoupledIO.map utility (#2646) (#2649) (cherry picked from commit b20df1d6cda03f6eef28ee480e0aade914c5face) Co-authored-by: Jared Barocsi <82000041+jared-barocsi@users.noreply.github.com>--- src/main/scala/chisel3/util/Decoupled.scala | 17 ++++- src/test/scala/chiselTests/DecoupledSpec.scala | 91 ++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index f02a4116..b21bd04f 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -99,7 +99,22 @@ object ReadyValidIO { * of ready or valid. * @param gen the type of data to be wrapped in DecoupledIO */ -class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen) +class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen) { + + /** Applies the supplied functor to the bits of this interface, returning a new + * typed DecoupledIO interface. + * @param f The function to apply to this DecoupledIO's 'bits' with return type B + * @return a new DecoupledIO of type B + */ + def map[B <: Data](f: T => B): DecoupledIO[B] = { + val _map_bits = f(bits) + val _map = Wire(Decoupled(chiselTypeOf(_map_bits))) + _map.bits := _map_bits + _map.valid := valid + ready := _map.ready + _map + } +} /** This factory adds a decoupled handshaking protocol to a data bundle. */ object Decoupled { 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""") + } } -- cgit v1.2.3