From 042be4b2d8a846d12c5c5dfd64f10b5caee93125 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 19 Jan 2022 01:41:59 +0000 Subject: util: add GrayCode (#2353) (#2354) (cherry picked from commit 91d7baa8e7162d736f46b6d4964b09016d2dd172) Co-authored-by: Kevin Laeufer --- src/main/scala/chisel3/util/GrayCode.scala | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/main/scala/chisel3/util/GrayCode.scala (limited to 'src') diff --git a/src/main/scala/chisel3/util/GrayCode.scala b/src/main/scala/chisel3/util/GrayCode.scala new file mode 100644 index 00000000..ef310ee9 --- /dev/null +++ b/src/main/scala/chisel3/util/GrayCode.scala @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3.util + +import chisel3._ + +object BinaryToGray { + + /** Turns a binary number into gray code. */ + def apply(in: UInt): UInt = in ^ (in >> 1) +} + +object GrayToBinary { + + /** Inverts the [[BinaryToGray]] operation. */ + def apply(in: UInt, width: Int): UInt = apply(in(width - 1, 0)) + + /** Inverts the [[BinaryToGray]] operation. */ + def apply(in: UInt): UInt = if (in.getWidth < 2) { in } + else { + val bits = in.getWidth - 2 to 0 by -1 + Cat(bits.scanLeft(in.head(1)) { case (prev, ii) => prev ^ in(ii) }) + } +} -- cgit v1.2.3 From a737281f670aa34152ce971b57f926ecc9307a8c Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 20 Jan 2022 19:44:41 +0000 Subject: Fix Compatibility Module io wrapping (#2355) (#2358) The new reflection based IO autowrapping for compatibility mode Modules would previously throw a NullPointerExceptions if any hardware were constructed in the Module before "val io" was initialized. The logic is now more robust for this case. Co-authored-by: Schuyler Eldridge (cherry picked from commit 50e6099fbecc041973564514e55f67ffe069459b) Co-authored-by: Jack Koenig --- src/test/scala/chiselTests/CompatibilitySpec.scala | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/CompatibilitySpec.scala b/src/test/scala/chiselTests/CompatibilitySpec.scala index d134c380..41cfbec4 100644 --- a/src/test/scala/chiselTests/CompatibilitySpec.scala +++ b/src/test/scala/chiselTests/CompatibilitySpec.scala @@ -238,10 +238,10 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck "A Module without val io" should "throw an exception" in { class ModuleWithoutValIO extends Module { - val foo = new Bundle { + val foo = IO(new Bundle { val in = UInt(width = 32).asInput val out = Bool().asOutput - } + }) foo.out := foo.in(1) } val e = intercept[Exception]( @@ -595,4 +595,23 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck verilog should include("output [7:0] io_bar") } + it should "properly handle hardware construction before val io is initialized" in { + class MyModule extends Module { + val foo = Wire(init = UInt(8)) + val io = new Bundle { + val in = UInt(INPUT, width = 8) + val en = Bool(INPUT) + val out = UInt(OUTPUT, width = 8) + } + io.out := foo + when(io.en) { + io.out := io.in + } + } + // Just check that this doesn't crash during elaboration. For more info see: + // https://github.com/chipsalliance/chisel3/issues/1802 + // + ChiselStage.elaborate(new MyModule) + } + } -- cgit v1.2.3 From db0fe3fb23c3f50be0aeb859b19cb96967e15186 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 26 Jan 2022 19:52:36 +0000 Subject: Expand supported val modifiers for @public (#2365) (#2367) (cherry picked from commit 13fb4595b3b21beadaad5ba5c5d131138099d6e1) Co-authored-by: Adam Izraelevitz --- .../experimental/hierarchy/InstanceSpec.scala | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala index f62d1e49..45d1f85f 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala @@ -298,6 +298,28 @@ class InstanceSpec extends ChiselFunSpec with Utils { annos should contain(MarkAnnotation("~Top|Top/i:HasEither>x".rt, "xright")) annos should contain(MarkAnnotation("~Top|Top/i:HasEither>y".rt, "yleft")) } + it("3.12: should properly support val modifiers") { + class SupClass extends Module { + val value = 10 + val overriddenVal = 10 + } + trait SupTrait { + def x: Int + def y: Int + } + @instantiable class SubClass() extends SupClass with SupTrait { + // This errors + //@public private val privateVal = 10 + // This errors + //@public protected val protectedVal = 10 + @public override val overriddenVal = 12 + @public final val finalVal = 12 + @public lazy val lazyValue = 12 + @public val value = value + @public final override lazy val x: Int = 3 + @public override final lazy val y: Int = 4 + } + } } describe("4: toInstance") { it("4.0: should work on modules") { -- cgit v1.2.3 From 91ad2312cab72442fcfec9c28576b5464669f8fd Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 28 Jan 2022 00:20:24 +0000 Subject: Fix Decoder bug for constant 0 and DC (#2363) (#2371) * Fix the QMC bug for constant and dontcare output. * Fix the Espresso bug for constant and dontcare output. (cherry picked from commit 46b53320e9ec09fc26d63259f1821f4234640839) Co-authored-by: Jiuyang Liu --- .../experimental/decode/EspressoMinimizer.scala | 11 ++++- .../util/experimental/decode/QMCMinimizer.scala | 49 ++++++++++++++-------- 2 files changed, 41 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala index de2f207b..86973e5b 100644 --- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala @@ -57,11 +57,20 @@ object EspressoMinimizer extends Minimizer with LazyLogging { def readTable(espressoTable: String) = { def bitPat(espresso: String): BitPat = BitPat("b" + espresso.replace('-', '?')) - espressoTable + val out = espressoTable .split("\n") .filterNot(_.startsWith(".")) .map(_.split(' ')) .map(row => bitPat(row(0)) -> bitPat(row(1))) + // special case for 0 and DontCare, if output is not couple to input + if (out.isEmpty) + Array( + ( + BitPat(s"b${"?" * table.inputWidth}"), + BitPat(s"b${"0" * table.outputWidth}") + ) + ) + else out } val input = writeTable(table) diff --git a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala index a3481869..26a072f1 100644 --- a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala @@ -304,24 +304,37 @@ object QMCMinimizer extends Minimizer { ) }) - minimized.tail.foldLeft(table.copy(table = Seq(minimized.head))) { - case (tb, t) => - if (tb.table.exists(x => x._1 == t._1)) { - tb.copy(table = tb.table.map { - case (k, v) => - if (k == t._1) { - def ones(bitPat: BitPat) = bitPat.rawString.zipWithIndex.collect { case ('1', x) => x } - ( - k, - BitPat( - "b" + (0 until v.getWidth).map(i => if ((ones(v) ++ ones(t._2)).contains(i)) "1" else "?").mkString + // special case for 0 and DontCare, if output is not couple to input + if (minimized.isEmpty) + table.copy( + Seq( + ( + BitPat(s"b${"?" * table.inputWidth}"), + BitPat(s"b${"0" * table.outputWidth}") + ) + ) + ) + else + minimized.tail.foldLeft(table.copy(table = Seq(minimized.head))) { + case (tb, t) => + if (tb.table.exists(x => x._1 == t._1)) { + tb.copy(table = tb.table.map { + case (k, v) => + if (k == t._1) { + def ones(bitPat: BitPat) = bitPat.rawString.zipWithIndex.collect { case ('1', x) => x } + ( + k, + BitPat( + "b" + (0 until v.getWidth) + .map(i => if ((ones(v) ++ ones(t._2)).contains(i)) "1" else "?") + .mkString + ) ) - ) - } else (k, v) - }) - } else { - tb.copy(table = tb.table :+ t) - } - } + } else (k, v) + }) + } else { + tb.copy(table = tb.table :+ t) + } + } } } -- cgit v1.2.3 From ea1ced34b5c9e42412cc0ac3e7431cd3194ccbc3 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Tue, 1 Feb 2022 19:56:13 +0000 Subject: Chisel plugin bundle elements handler (#2306) (#2380) Adds generation of `Bundle.elements` method to the chores done by the compiler plugin For each `Bundle` find the relevant visible Chisel field members and construct a hard-coded list of the elements and their names implemented as `_elementsImpl` For more details: See plugins/README.md - Should be no change in API - Handles inheritance and mixins - Handles Seq[Data] - Tests in BundleElementSpec Co-authored-by: chick Co-authored-by: Jack Koenig (cherry picked from commit 237200a420581519f29149cbae9b3e968c0d01fc) Co-authored-by: Chick Markley --- .../scala/chiselTests/BundleElementsSpec.scala | 564 +++++++++++++++++++++ src/test/scala/chiselTests/BundleSpec.scala | 10 +- 2 files changed, 571 insertions(+), 3 deletions(-) create mode 100644 src/test/scala/chiselTests/BundleElementsSpec.scala (limited to 'src') diff --git a/src/test/scala/chiselTests/BundleElementsSpec.scala b/src/test/scala/chiselTests/BundleElementsSpec.scala new file mode 100644 index 00000000..fab2e733 --- /dev/null +++ b/src/test/scala/chiselTests/BundleElementsSpec.scala @@ -0,0 +1,564 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chiselTests + +import chisel3._ +import chisel3.experimental.{ChiselEnum, FixedPoint} +import chisel3.stage.ChiselStage +import chisel3.util.Decoupled +import org.scalatest.exceptions.TestFailedException +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers + +import scala.language.reflectiveCalls + +/* Rich and complicated bundle examples + */ +trait BpipSuperTraitWithField { + val bpipSuperTraitGood = SInt(17.W) + def bpipSuperTraitBad = SInt(22.W) +} + +trait BpipTraitWithField extends BpipSuperTraitWithField { + val bpipTraitGood = SInt(17.W) + def bpipTraitBad = SInt(22.W) +} + +class BpipOneField extends Bundle with BpipTraitWithField { + val bpipOneFieldOne = SInt(8.W) + val bpipOneFieldTwo = SInt(8.W) +} + +class BpipTwoField extends BpipOneField { + val bpipTwoFieldOne = SInt(8.W) + val bpipTwoFieldTwo = Vec(4, UInt(12.W)) + val myInt = 7 + val baz = Decoupled(UInt(16.W)) +} + +class BpipDecoupled extends BpipOneField { + val bpipDecoupledSInt = SInt(8.W) + val bpipDecoupledVec = Vec(4, UInt(12.W)) + val bpipDecoupledDecoupled = Decoupled(UInt(16.W)) +} + +class HasDecoupledBundleByInheritance extends Module { + val out1 = IO(Output(new BpipDecoupled)) + assertElementsMatchExpected(out1)( + "bpipDecoupledDecoupled" -> _.bpipDecoupledDecoupled, + "bpipDecoupledVec" -> _.bpipDecoupledVec, + "bpipDecoupledSInt" -> _.bpipDecoupledSInt, + "bpipOneFieldTwo" -> _.bpipOneFieldTwo, + "bpipOneFieldOne" -> _.bpipOneFieldOne, + "bpipTraitGood" -> _.bpipTraitGood, + "bpipSuperTraitGood" -> _.bpipSuperTraitGood + ) +} + +/* plugin should not affect the seq detection */ +class DebugProblem3 extends Module { + val out1 = IO(Output(new BpipTwoField)) + assertElementsMatchExpected(out1)( + "baz" -> _.baz, + "bpipTwoFieldTwo" -> _.bpipTwoFieldTwo, + "bpipTwoFieldOne" -> _.bpipTwoFieldOne, + "bpipOneFieldTwo" -> _.bpipOneFieldTwo, + "bpipOneFieldOne" -> _.bpipOneFieldOne, + "bpipTraitGood" -> _.bpipTraitGood, + "bpipSuperTraitGood" -> _.bpipSuperTraitGood + ) +} + +class BpipBadSeqBundle extends Bundle { + val bpipBadSeqBundleGood = UInt(999.W) + val bpipBadSeqBundleBad = Seq(UInt(16.W), UInt(8.W), UInt(4.W)) +} + +class HasBadSeqBundle extends Module { + val out1 = IO(Output(new BpipBadSeqBundle)) +} + +class BpipBadSeqBundleWithIgnore extends Bundle with IgnoreSeqInBundle { + val goodFieldWithIgnore = UInt(999.W) + val badSeqFieldWithIgnore = Seq(UInt(16.W), UInt(8.W), UInt(4.W)) +} + +class UsesIgnoreSeqInBundle extends Module { + val out1 = IO(Output(new BpipBadSeqBundleWithIgnore)) +} + +/* This is mostly a test of the field order */ +class BpipP8_1 extends Bundle { + val field_1_1 = UInt(11.W) + val field_1_2 = UInt(12.W) +} + +class BpipP8_2 extends BpipP8_1 { + val field_2_1 = UInt(11.W) + val field_2_2 = UInt(12.W) +} + +class BpipP8_3 extends BpipP8_2 { + val field_3_1 = UInt(11.W) + val field_3_2 = UInt(12.W) +} + +/* plugin should not affect the seq detection */ +class ForFieldOrderingTest extends Module { + val out1 = IO(Output(new BpipP8_3)) + out1 := DontCare + assertElementsMatchExpected(out1)( + "field_3_2" -> _.field_3_2, + "field_3_1" -> _.field_3_1, + "field_2_2" -> _.field_2_2, + "field_2_1" -> _.field_2_1, + "field_1_2" -> _.field_1_2, + "field_1_1" -> _.field_1_1 + ) +} + +/* plugin should allow parameter var fields */ +class HasValParamsToBundle extends Module { + // The following block does not work, suggesting that ParamIsField is not a case we need to solve + class BpipParamIsField0(val paramField0: UInt) extends Bundle + class BpipParamIsField1(val paramField1: UInt) extends BpipParamIsField0(UInt(66.W)) + + val out3 = IO(Output(new BpipParamIsField1(UInt(10.W)))) + val out4 = IO(Output(new BpipParamIsField1(UInt(10.W)))) + out3 := DontCare + assertElementsMatchExpected(out3)("paramField0" -> _.paramField0, "paramField1" -> _.paramField1) + assertElementsMatchExpected(out4)("paramField0" -> _.paramField0, "paramField1" -> _.paramField1) +} + +class HasGenParamsPassedToSuperclasses extends Module { + + class OtherBundle extends Bundle { + val otherField = UInt(55.W) + } + + class BpipWithGen[T <: Data, TT <: Data](gen: T, gen2: => TT) extends Bundle { + val superFoo = gen + val superQux = gen2 + } + +// class BpipDemoBundle[T <: Data](gen: T, gen2: => T) extends BpipTwoField with BpipVarmint { + class BpipUsesWithGen[T <: Data](gen: T, gen2: => T) extends BpipWithGen(gen, gen2) { + // val foo = gen + val bar = Bool() + val qux = gen2 + val bad = 444 + val baz = Decoupled(UInt(16.W)) + } + + val out1 = IO(Output(new BpipUsesWithGen(UInt(4.W), new OtherBundle))) + val out2 = IO(Output(new BpipUsesWithGen(UInt(4.W), FixedPoint(10.W, 4.BP)))) + + out1 := DontCare + + assertElementsMatchExpected(out1)( + "baz" -> _.baz, + "qux" -> _.qux, + "bar" -> _.bar, + "superQux" -> _.superQux, + "superFoo" -> _.superFoo + ) + assertElementsMatchExpected(out2)( + "baz" -> _.baz, + "qux" -> _.qux, + "bar" -> _.bar, + "superQux" -> _.superQux, + "superFoo" -> _.superFoo + ) +} + +/* Testing whether gen fields superFoo and superQux can be found when they are + * declared in a superclass + * + */ +class UsesGenFiedldsInSuperClass extends Module { + class BpipWithGen[T <: Data](gen: T) extends Bundle { + val superFoo = gen + val superQux = gen + } + + class BpipUsesWithGen[T <: Data](gen: T) extends BpipWithGen(gen) {} + + val out = IO(Output(new BpipUsesWithGen(UInt(4.W)))) + + out := DontCare + + assertElementsMatchExpected(out)() +} + +/* Testing whether gen fields superFoo and superQux can be found when they are + * declared in a superclass + * + */ +class BpipBadBundleWithHardware extends Bundle { + val bpipWithHardwareGood = UInt(8.W) + val bpipWithHardwareBad = 244.U(16.W) +} + +class HasHardwareFieldsInBundle extends Module { + val out = IO(Output(new BpipBadBundleWithHardware)) + assertElementsMatchExpected(out)() +} + +/* This is legal because of => + */ +class UsesBundleWithGeneratorField extends Module { + class BpipWithGen[T <: Data](gen: => T) extends Bundle { + val superFoo = gen + val superQux = gen + } + + class BpipUsesWithGen[T <: Data](gen: => T) extends BpipWithGen(gen) + + val out = IO(Output(new BpipUsesWithGen(UInt(4.W)))) + + out := DontCare + + assertElementsMatchExpected(out)("superQux" -> _.superQux, "superFoo" -> _.superFoo) +} + +/* Testing whether gen fields superFoo and superQux can be found when they are + * declared in a superclass + * + */ +class BundleElementsSpec extends AnyFreeSpec with Matchers { + + /** Tests a whole bunch of different Bundle constructions + */ + class BpipIsComplexBundle extends Module { + + trait BpipVarmint { + val varmint = Bool() + + def vermin = Bool() + + private val puppy = Bool() + } + + abstract class BpipAbstractBundle extends Bundle { + def doNothing: Unit + + val fromAbstractBundle = UInt(22.W) + } + + class BpipOneField extends Bundle { + val fieldOne = SInt(8.W) + } + + class BpipTwoField extends BpipOneField { + val fieldTwo = SInt(8.W) + val fieldThree = Vec(4, UInt(12.W)) + } + + class BpipAnimalBundle(w1: Int, w2: Int) extends Bundle { + val dog = SInt(w1.W) + val fox = UInt(w2.W) + } + + class BpipDemoBundle[T <: Data](gen: T, gen2: => T) extends BpipTwoField with BpipVarmint { + val foo = gen + val bar = Bool() + val qux = gen2 + val bad = 44 + val baz = Decoupled(UInt(16.W)) + val animals = new BpipAnimalBundle(4, 8) + } + + val out = IO(Output(new BpipDemoBundle(UInt(4.W), FixedPoint(10.W, 4.BP)))) + + val out2 = IO(Output(new BpipAbstractBundle { + override def doNothing: Unit = () + + val notAbstract: Bool = Bool() + })) + + val out4 = IO(Output(new BpipAnimalBundle(99, 100))) + val out5 = IO(Output(new BpipTwoField)) + + out := DontCare + out5 := DontCare + + assertElementsMatchExpected(out)( + "animals" -> _.animals, + "baz" -> _.baz, + "qux" -> _.qux, + "bar" -> _.bar, + "varmint" -> _.varmint, + "fieldThree" -> _.fieldThree, + "fieldTwo" -> _.fieldTwo, + "fieldOne" -> _.fieldOne, + "foo" -> _.foo + ) + assertElementsMatchExpected(out5)("fieldThree" -> _.fieldThree, "fieldTwo" -> _.fieldTwo, "fieldOne" -> _.fieldOne) + assertElementsMatchExpected(out2)("notAbstract" -> _.notAbstract, "fromAbstractBundle" -> _.fromAbstractBundle) + assertElementsMatchExpected(out4)("fox" -> _.fox, "dog" -> _.dog) + } + + "Complex Bundle with inheritance, traits and params. DebugProblem1" in { + ChiselStage.emitFirrtl(new BpipIsComplexBundle) + } + + "Decoupled Bundle with inheritance" in { + ChiselStage.emitFirrtl(new HasDecoupledBundleByInheritance) + } + + "Simple bundle inheritance. DebugProblem3" in { + ChiselStage.emitFirrtl(new DebugProblem3) + } + + "Bundles containing Seq[Data] should be compile erorr. HasBadSeqBundle" in { + intercept[ChiselException] { + ChiselStage.emitFirrtl(new HasBadSeqBundle) + } + } + + "IgnoreSeqInBundle allows Seq[Data] in bundle" in { + ChiselStage.emitFirrtl(new UsesIgnoreSeqInBundle) + } + + "Simple field ordering test." in { + ChiselStage.emitFirrtl(new ForFieldOrderingTest) + } + + "Val params to Bundle should be an Exception." in { + ChiselStage.emitFirrtl(new HasValParamsToBundle) + } + + "Should handle gen params passed to superclasses" in { + ChiselStage.emitFirrtl(new HasGenParamsPassedToSuperclasses) + } + + "Aliased fields should be detected and throw an exception, because gen: Data, with no =>" in { + intercept[AliasedAggregateFieldException] { + ChiselStage.emitFirrtl(new UsesGenFiedldsInSuperClass) + } + } + + "Error when bundle fields are hardware, such as literal values. HasHardwareFieldsInBundle" in { + val e = intercept[ExpectedChiselTypeException] { + ChiselStage.emitFirrtl(new HasHardwareFieldsInBundle) + } + e.getMessage should include( + "Bundle: BpipBadBundleWithHardware contains hardware fields: bpipWithHardwareBad: UInt<16>(244)" + ) + } + + "Aliased fields not created when using gen: => Data" in { + ChiselStage.emitFirrtl(new UsesBundleWithGeneratorField) + } + + class OptionBundle(val hasIn: Boolean) extends Bundle { + val in = if (hasIn) { + Some(Input(Bool())) + } else { + None + } + val out = Output(Bool()) + } + + class UsesBundleWithOptionFields extends Module { + val outTrue = IO(Output(new OptionBundle(hasIn = true))) + val outFalse = IO(Output(new OptionBundle(hasIn = false))) + //NOTE: The _.in.get _.in is an optional field + assertElementsMatchExpected(outTrue)("out" -> _.out, "in" -> _.in.get) + assertElementsMatchExpected(outFalse)("out" -> _.out) + } + + "plugin should work with Bundles with Option fields" in { + ChiselStage.emitFirrtl(new UsesBundleWithOptionFields) + } + + "plugin should work with enums in bundles" in { + object Enum0 extends ChiselEnum { + val s0, s1, s2 = Value + } + + ChiselStage.emitFirrtl(new Module { + val out = IO(Output(new Bundle { + val a = UInt(8.W) + val b = Bool() + val c = Enum0.Type + })) + assertElementsMatchExpected(out)("b" -> _.b, "a" -> _.a) + }) + } + + "plugin will NOT see fields that are Data but declared in some way as Any" in { + //This is not incompatible with chisel not using the plugin, but this code is considered bad practice + + ChiselStage.emitFirrtl(new Module { + val out = IO(Output(new Bundle { + val a = UInt(8.W) + val b: Any = Bool() + })) + + intercept[TestFailedException] { + assert(out.elements.keys.exists(_ == "b")) + } + }) + } + + "plugin tests should fail properly in the following cases" - { + + class BundleAB extends Bundle { + val a = Output(UInt(8.W)) + val b = Output(Bool()) + } + + def checkAssertion(checks: (BundleAB => (String, Data))*)(expectedMessage: String): Unit = { + intercept[AssertionError] { + ChiselStage.emitFirrtl(new Module { + val out = IO(new BundleAB) + assertElementsMatchExpected(out)(checks: _*) + }) + }.getMessage should include(expectedMessage) + } + + "one of the expected data values is wrong" in { + checkAssertion("b" -> _.b, "a" -> _.b)("field 'a' data field BundleElementsSpec_Anon.out.a") + } + + "one of the expected field names in wrong" in { + checkAssertion("b" -> _.b, "z" -> _.a)("field: 'a' did not match expected 'z'") + } + + "fields that are expected are not returned by the elements method" in { + checkAssertion("b" -> _.b, "a" -> _.a, "c" -> _.a)("#elements is missing the 'c' field") + } + + "fields returned by the element are not specified in the expected fields" in { + checkAssertion("b" -> _.b)("expected fields did not include 'a' field found in #elements") + } + + "multiple errors between elements method and expected fields are shown in the assertion error message" in { + checkAssertion()( + "expected fields did not include 'b' field found in #elements," + + " expected fields did not include 'a' field found in #elements" + ) + } + } + + "plugin should error correctly when bundles contain only a Option field" in { + ChiselStage.emitFirrtl(new Module { + val io = IO(new Bundle { + val foo = Input(UInt(8.W)) + val x = new Bundle { + val y = if (false) Some(Input(UInt(8.W))) else None + } + }) + assertElementsMatchExpected(io)("x" -> _.x, "foo" -> _.foo) + assertElementsMatchExpected(io.x)() + }) + } + + "plugin should handle fields using the boolean to option construct" in { + case class ALUConfig( + xLen: Int, + mul: Boolean, + b: Boolean) + + class OptionalBundle extends Bundle { + val optionBundleA = Input(UInt(3.W)) + val optionBundleB = Input(UInt(7.W)) + } + + class ALU(c: ALUConfig) extends Module { + + class BpipOptionBundle extends Bundle with IgnoreSeqInBundle { + val bpipUIntVal = Input(UInt(8.W)) + lazy val bpipUIntLazyVal = Input(UInt(8.W)) + var bpipUIntVar = Input(UInt(8.W)) + + def bpipUIntDef = Input(UInt(8.W)) + + val bpipOptionUInt = Some(Input(UInt(16.W))) + val bpipOptionOfBundle = if (c.b) Some(new OptionalBundle) else None + val bpipSeqData = Seq(UInt(8.W), UInt(8.W)) + } + + val io = IO(new BpipOptionBundle) + assertElementsMatchExpected(io)( + "bpipUIntLazyVal" -> _.bpipUIntLazyVal, + "bpipOptionUInt" -> _.bpipOptionUInt.get, + "bpipUIntVar" -> _.bpipUIntVar, + "bpipUIntVal" -> _.bpipUIntVal + ) + } + + ChiselStage.emitFirrtl(new ALU(ALUConfig(10, mul = true, b = false))) + } + + "TraceSpec test, different version found in TraceSpec.scala" in { + class Bundle0 extends Bundle { + val a = UInt(8.W) + val b = Bool() + val c = Enum0.Type + } + + class Bundle1 extends Bundle { + val a = new Bundle0 + val b = Vec(4, Vec(4, Bool())) + } + + class Module0 extends Module { + val i = IO(Input(new Bundle1)) + val o = IO(Output(new Bundle1)) + val r = Reg(new Bundle1) + o := r + r := i + + assertElementsMatchExpected(i)("b" -> _.b, "a" -> _.a) + assertElementsMatchExpected(o)("b" -> _.b, "a" -> _.a) + assertElementsMatchExpected(r)("b" -> _.b, "a" -> _.a) + } + + class Module1 extends Module { + val i = IO(Input(new Bundle1)) + val m0 = Module(new Module0) + m0.i := i + m0.o := DontCare + assertElementsMatchExpected(i)("b" -> _.b, "a" -> _.a) + } + + object Enum0 extends ChiselEnum { + val s0, s1, s2 = Value + } + + ChiselStage.emitFirrtl(new Module1) + } +} +/* Checks that the elements method of a bundle matches the testers idea of what the bundle field names and their + * associated data match and that they have the same number of fields in the same order + */ +object assertElementsMatchExpected { + def apply[T <: Bundle](bun: T)(checks: (T => (String, Data))*): Unit = { + val expected = checks.map { fn => fn(bun) } + val elements = bun.elements + val missingMsg = "missing field in #elements" + val extraMsg = "extra field in #elements" + val paired = elements.toSeq.zipAll(expected, missingMsg -> UInt(1.W), extraMsg -> UInt(1.W)) + val errorsStrings = paired.flatMap { + case (element, expected) => + val (elementName, elementData) = element + val (expectedName, expectedData) = expected + if (elementName == missingMsg) { + Some(s"#elements is missing the '$expectedName' field") + } else if (expectedName == extraMsg) { + Some(s"expected fields did not include '$elementName' field found in #elements") + } else if (elementName != expectedName) { + Some(s"field: '$elementName' did not match expected '$expectedName'") + } else if (elementData != expectedData) { + Some( + s"field '$elementName' data field ${elementData}(${elementData.hashCode}) did not match expected $expectedData(${expectedData.hashCode})" + ) + } else { + None + } + } + assert(errorsStrings.isEmpty, s"Bundle: ${bun.getClass.getName}: " + errorsStrings.mkString(", ")) + } +} diff --git a/src/test/scala/chiselTests/BundleSpec.scala b/src/test/scala/chiselTests/BundleSpec.scala index 720f877f..5dcbbefa 100644 --- a/src/test/scala/chiselTests/BundleSpec.scala +++ b/src/test/scala/chiselTests/BundleSpec.scala @@ -26,6 +26,10 @@ trait BundleSpecUtils { val bar = Seq(UInt(16.W), UInt(8.W), UInt(4.W)) } + class BadSeqBundleWithIgnoreSeqInBundle extends Bundle with IgnoreSeqInBundle { + val bar = Seq(UInt(16.W), UInt(8.W), UInt(4.W)) + } + class MyModule(output: Bundle, input: Bundle) extends Module { val io = IO(new Bundle { val in = Input(input) @@ -87,7 +91,7 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils { new BasicTester { val m = Module(new Module { val io = IO(new Bundle { - val b = new BadSeqBundle with IgnoreSeqInBundle + val b = new BadSeqBundleWithIgnoreSeqInBundle }) }) stop() @@ -141,7 +145,7 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils { out := in } } - }).getMessage should include("must be a Chisel type, not hardware") + }).getMessage should include("MyBundle contains hardware fields: foo: UInt<7>(123)") } "Bundles" should "not recursively contain aggregates with bound hardware" in { (the[ChiselException] thrownBy extractCause[ChiselException] { @@ -153,7 +157,7 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils { out := in } } - }).getMessage should include("must be a Chisel type, not hardware") + }).getMessage should include("Bundle: MyBundle contains hardware fields: foo: BundleSpec_Anon.out") } "Unbound bundles sharing a field" should "not error" in { ChiselStage.elaborate { -- cgit v1.2.3 From cb77b061e835044b4f3a2b718fb7ce3971b5d06e Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Tue, 1 Feb 2022 20:55:35 +0000 Subject: Optional clock param for memory ports (#2333) (#2382) Warn if clock at memory instantiation differs from clock bound at port creation and port clock is not manually passed Co-authored-by: Jack Koenig (cherry picked from commit 465805ec7b2696a985eaa12cf9c6868f11ac2931) Co-authored-by: Aditya Naik <91489422+adkian-sifive@users.noreply.github.com>--- src/test/scala/chiselTests/MultiClockSpec.scala | 110 +++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/MultiClockSpec.scala b/src/test/scala/chiselTests/MultiClockSpec.scala index 2553f3b3..381b4009 100644 --- a/src/test/scala/chiselTests/MultiClockSpec.scala +++ b/src/test/scala/chiselTests/MultiClockSpec.scala @@ -113,7 +113,7 @@ class MultiClockMemTest extends BasicTester { when(done) { stop() } } -class MultiClockSpec extends ChiselFlatSpec { +class MultiClockSpec extends ChiselFlatSpec with Utils { "withClock" should "scope the clock of registers" in { assertTesterPasses(new ClockDividerTest) @@ -129,6 +129,114 @@ class MultiClockSpec extends ChiselFlatSpec { }) } + "Differing clocks at memory and port instantiation" should "warn" in { + class modMemDifferingClock extends Module { + val myClock = IO(Input(Clock())) + val mem = withClock(myClock) { Mem(4, UInt(8.W)) } + val port0 = mem(0.U) + } + val (logMemDifferingClock, _) = grabLog(ChiselStage.elaborate(new modMemDifferingClock)) + logMemDifferingClock should include("memory is different") + + class modSyncReadMemDifferingClock extends Module { + val myClock = IO(Input(Clock())) + val mem = withClock(myClock) { SyncReadMem(4, UInt(8.W)) } + val port0 = mem(0.U) + } + val (logSyncReadMemDifferingClock, _) = grabLog(ChiselStage.elaborate(new modSyncReadMemDifferingClock)) + logSyncReadMemDifferingClock should include("memory is different") + } + + "Differing clocks at memory and write accessor instantiation" should "warn" in { + class modMemWriteDifferingClock extends Module { + val myClock = IO(Input(Clock())) + val mem = withClock(myClock) { Mem(4, UInt(8.W)) } + mem(1.U) := 1.U + } + val (logMemWriteDifferingClock, _) = grabLog(ChiselStage.elaborate(new modMemWriteDifferingClock)) + logMemWriteDifferingClock should include("memory is different") + + class modSyncReadMemWriteDifferingClock extends Module { + val myClock = IO(Input(Clock())) + val mem = withClock(myClock) { SyncReadMem(4, UInt(8.W)) } + mem.write(1.U, 1.U) + } + val (logSyncReadMemWriteDifferingClock, _) = grabLog(ChiselStage.elaborate(new modSyncReadMemWriteDifferingClock)) + logSyncReadMemWriteDifferingClock should include("memory is different") + } + + "Differing clocks at memory and read accessor instantiation" should "warn" in { + class modMemReadDifferingClock extends Module { + val myClock = IO(Input(Clock())) + val mem = withClock(myClock) { Mem(4, UInt(8.W)) } + val readVal = mem.read(0.U) + } + val (logMemReadDifferingClock, _) = grabLog(ChiselStage.elaborate(new modMemReadDifferingClock)) + logMemReadDifferingClock should include("memory is different") + + class modSyncReadMemReadDifferingClock extends Module { + val myClock = IO(Input(Clock())) + val mem = withClock(myClock) { SyncReadMem(4, UInt(8.W)) } + val readVal = mem.read(0.U) + } + val (logSyncReadMemReadDifferingClock, _) = grabLog(ChiselStage.elaborate(new modSyncReadMemReadDifferingClock)) + logSyncReadMemReadDifferingClock should include("memory is different") + } + + "Passing clock parameter to memory port instantiation" should "not warn" in { + class modMemPortClock extends Module { + val myClock = IO(Input(Clock())) + val mem = Mem(4, UInt(8.W)) + val port0 = mem(0.U, myClock) + } + val (logMemPortClock, _) = grabLog(ChiselStage.elaborate(new modMemPortClock)) + (logMemPortClock should not).include("memory is different") + + class modSyncReadMemPortClock extends Module { + val myClock = IO(Input(Clock())) + val mem = SyncReadMem(4, UInt(8.W)) + val port0 = mem(0.U, myClock) + } + val (logSyncReadMemPortClock, _) = grabLog(ChiselStage.elaborate(new modSyncReadMemPortClock)) + (logSyncReadMemPortClock should not).include("memory is different") + } + + "Passing clock parameter to memory write accessor" should "not warn" in { + class modMemWriteClock extends Module { + val myClock = IO(Input(Clock())) + val mem = Mem(4, UInt(8.W)) + mem.write(0.U, 0.U, myClock) + } + val (logMemWriteClock, _) = grabLog(ChiselStage.elaborate(new modMemWriteClock)) + (logMemWriteClock should not).include("memory is different") + + class modSyncReadMemWriteClock extends Module { + val myClock = IO(Input(Clock())) + val mem = SyncReadMem(4, UInt(8.W)) + mem.write(0.U, 0.U, myClock) + } + val (logSyncReadMemWriteClock, _) = grabLog(ChiselStage.elaborate(new modSyncReadMemWriteClock)) + (logSyncReadMemWriteClock should not).include("memory is different") + } + + "Passing clock parameter to memory read accessor" should "not warn" in { + class modMemReadClock extends Module { + val myClock = IO(Input(Clock())) + val mem = Mem(4, UInt(8.W)) + val readVal = mem.read(0.U, myClock) + } + val (logMemReadClock, _) = grabLog(ChiselStage.elaborate(new modMemReadClock)) + (logMemReadClock should not).include("memory is different") + + class modSyncReadMemReadClock extends Module { + val myClock = IO(Input(Clock())) + val mem = SyncReadMem(4, UInt(8.W)) + val readVal = mem.read(0.U, myClock) + } + val (logSyncReadMemReadClock, _) = grabLog(ChiselStage.elaborate(new modSyncReadMemReadClock)) + (logSyncReadMemReadClock should not).include("memory is different") + } + "withReset" should "scope the reset of registers" in { assertTesterPasses(new WithResetTest) } -- cgit v1.2.3 From 0eba2eb109910c1e4b980ccfc7f3ae85a8d0f223 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Tue, 1 Feb 2022 21:37:08 +0000 Subject: Improve error reporting (backport #2376) (#2379) * Improve error reporting (#2376) * Do not trim stack traces of exceptions with no stack trace This prevents us from accidentally giving stack traces to exceptions that don't have them and giving misleading messages telling users to use --full-stacktrace when it won't actually do anything. Also deprecate ChiselException.chiselStackTrace which is no longer being used anywhere in this codebase. * Add exception class for multiple-errors reported New chisel3.internal.Errors replaces old anonymous class that would show up as chisel3.internal.ErrorLog$$anon$1 in error messages. * Add new option --throw-on-first-error This tells Chisel not to aggregate recoverable errors but instead to throw an exception on the first one. This gives a stack trace for users who need it for debugging. (cherry picked from commit ff2e9c92247b3848659fa09fdd53ddde2120036a) * Waive MiMa false positives The waived change is to a package private constructor. Co-authored-by: Jack Koenig Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- .../chisel3/aop/injecting/InjectingAspect.scala | 6 +- .../scala/chisel3/stage/ChiselAnnotations.scala | 18 +++++ src/main/scala/chisel3/stage/ChiselCli.scala | 1 + src/main/scala/chisel3/stage/ChiselOptions.scala | 3 + src/main/scala/chisel3/stage/package.scala | 5 +- .../scala/chisel3/stage/phases/Elaborate.scala | 14 +++- .../scala/chiselTests/stage/ChiselStageSpec.scala | 83 ++++++++++++++++++++++ 7 files changed, 123 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala index abe208cf..ba873c23 100644 --- a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala +++ b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala @@ -6,9 +6,10 @@ import chisel3.{withClockAndReset, Module, ModuleAspect, RawModule} import chisel3.aop._ import chisel3.internal.{Builder, DynamicContext} import chisel3.internal.firrtl.DefModule -import chisel3.stage.DesignAnnotation +import chisel3.stage.{ChiselOptions, DesignAnnotation} import firrtl.annotations.ModuleTarget import firrtl.stage.RunFirrtlTransformAnnotation +import firrtl.options.Viewer.view import firrtl.{ir, _} import scala.collection.mutable @@ -56,7 +57,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 dynamicContext = new DynamicContext(annotationsInAspect) + val chiselOptions = view[ChiselOptions](annotationsInAspect) + val dynamicContext = new DynamicContext(annotationsInAspect, chiselOptions.throwOnFirstError) // 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 c5811813..e046319d 100644 --- a/src/main/scala/chisel3/stage/ChiselAnnotations.scala +++ b/src/main/scala/chisel3/stage/ChiselAnnotations.scala @@ -61,6 +61,24 @@ case object PrintFullStackTraceAnnotation } +/** On recoverable errors, this will cause Chisel to throw an exception instead of continuing. + */ +case object ThrowOnFirstErrorAnnotation + extends NoTargetAnnotation + with ChiselOption + with HasShellOptions + with Unserializable { + + val options = Seq( + new ShellOption[Unit]( + longOption = "throw-on-first-error", + toAnnotationSeq = _ => Seq(ThrowOnFirstErrorAnnotation), + helpText = "Throw an exception on the first error instead of continuing" + ) + ) + +} + /** 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 26b032bf..f38bf50c 100644 --- a/src/main/scala/chisel3/stage/ChiselCli.scala +++ b/src/main/scala/chisel3/stage/ChiselCli.scala @@ -9,6 +9,7 @@ trait ChiselCli { this: Shell => Seq( NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation, + ThrowOnFirstErrorAnnotation, ChiselOutputFileAnnotation, ChiselGeneratorAnnotation ) diff --git a/src/main/scala/chisel3/stage/ChiselOptions.scala b/src/main/scala/chisel3/stage/ChiselOptions.scala index ed4d0a2f..7e4305fa 100644 --- a/src/main/scala/chisel3/stage/ChiselOptions.scala +++ b/src/main/scala/chisel3/stage/ChiselOptions.scala @@ -7,12 +7,14 @@ 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) { private[stage] def copy( runFirrtlCompiler: Boolean = runFirrtlCompiler, printFullStackTrace: Boolean = printFullStackTrace, + throwOnFirstError: Boolean = throwOnFirstError, outputFile: Option[String] = outputFile, chiselCircuit: Option[Circuit] = chiselCircuit ): ChiselOptions = { @@ -20,6 +22,7 @@ class ChiselOptions private[stage] ( new ChiselOptions( runFirrtlCompiler = runFirrtlCompiler, printFullStackTrace = printFullStackTrace, + throwOnFirstError = throwOnFirstError, outputFile = outputFile, chiselCircuit = chiselCircuit ) diff --git a/src/main/scala/chisel3/stage/package.scala b/src/main/scala/chisel3/stage/package.scala index bf03e2df..b1064c05 100644 --- a/src/main/scala/chisel3/stage/package.scala +++ b/src/main/scala/chisel3/stage/package.scala @@ -15,8 +15,9 @@ package object stage { def view(options: AnnotationSeq): ChiselOptions = options.collect { case a: ChiselOption => a } .foldLeft(new ChiselOptions()) { (c, x) => x match { - case _: NoRunFirrtlCompilerAnnotation.type => c.copy(runFirrtlCompiler = false) - case _: PrintFullStackTraceAnnotation.type => c.copy(printFullStackTrace = true) + 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)) } diff --git a/src/main/scala/chisel3/stage/phases/Elaborate.scala b/src/main/scala/chisel3/stage/phases/Elaborate.scala index 2cfb3200..55331cb4 100644 --- a/src/main/scala/chisel3/stage/phases/Elaborate.scala +++ b/src/main/scala/chisel3/stage/phases/Elaborate.scala @@ -5,7 +5,13 @@ package chisel3.stage.phases import chisel3.Module import chisel3.internal.ExceptionHelpers.ThrowableHelpers import chisel3.internal.{Builder, DynamicContext} -import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselOptions, DesignAnnotation} +import chisel3.stage.{ + ChiselCircuitAnnotation, + ChiselGeneratorAnnotation, + ChiselOptions, + DesignAnnotation, + ThrowOnFirstErrorAnnotation +} import firrtl.AnnotationSeq import firrtl.options.Phase import firrtl.options.Viewer.view @@ -21,14 +27,16 @@ class Elaborate extends Phase { def transform(annotations: AnnotationSeq): AnnotationSeq = annotations.flatMap { case ChiselGeneratorAnnotation(gen) => + val chiselOptions = view[ChiselOptions](annotations) try { - val (circuit, dut) = Builder.build(Module(gen()), new DynamicContext(annotations)) + val (circuit, dut) = + Builder.build(Module(gen()), new DynamicContext(annotations, chiselOptions.throwOnFirstError)) 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 */ case scala.util.control.NonFatal(a) => - if (!view[ChiselOptions](annotations).printFullStackTrace) { + if (!chiselOptions.printFullStackTrace) { a.trimStackTraceToUserCode() } throw (a) diff --git a/src/test/scala/chiselTests/stage/ChiselStageSpec.scala b/src/test/scala/chiselTests/stage/ChiselStageSpec.scala index e88a2385..f0f383da 100644 --- a/src/test/scala/chiselTests/stage/ChiselStageSpec.scala +++ b/src/test/scala/chiselTests/stage/ChiselStageSpec.scala @@ -34,6 +34,14 @@ object ChiselStageSpec { assert(false, "User threw an exception") } + class UserExceptionNoStackTrace extends RawModule { + throw new Exception("Something bad happened") with scala.util.control.NoStackTrace + } + + class RecoverableError extends RawModule { + 3.U >> -1 + } + } class ChiselStageSpec extends AnyFlatSpec with Matchers with Utils { @@ -169,6 +177,32 @@ class ChiselStageSpec extends AnyFlatSpec with Matchers with Utils { (exception.getStackTrace.mkString("\n") should not).include("java") } + it should "NOT add a stack trace to an exception with no stack trace" in { + val exception = intercept[java.lang.Exception] { + ChiselStage.emitChirrtl(new UserExceptionNoStackTrace) + } + + val message = exception.getMessage + info("The exception includes the user's message") + message should include("Something bad happened") + + info("The exception should not contain a stack trace") + exception.getStackTrace should be(Array()) + } + + it should "NOT include a stack trace for recoverable errors" in { + val exception = intercept[java.lang.Exception] { + ChiselStage.emitChirrtl(new RecoverableError) + } + + val message = exception.getMessage + info("The exception includes the standard error message") + message should include("Fatal errors during hardware elaboration. Look above for error list.") + + info("The exception should not contain a stack trace") + exception.getStackTrace should be(Array()) + } + behavior.of("ChiselStage exception handling") it should "truncate a user exception" in { @@ -207,4 +241,53 @@ class ChiselStageSpec extends AnyFlatSpec with Matchers with Utils { exception.getStackTrace.mkString("\n") should include("java") } + it should "NOT add a stack trace to an exception with no stack trace" in { + val exception = intercept[java.lang.Exception] { + (new ChiselStage).emitChirrtl(new UserExceptionNoStackTrace) + } + + val message = exception.getMessage + info("The exception includes the user's message") + message should include("Something bad happened") + + info("The exception should not contain a stack trace") + exception.getStackTrace should be(Array()) + } + + it should "NOT include a stack trace for recoverable errors" in { + val exception = intercept[java.lang.Exception] { + (new ChiselStage).emitChirrtl(new RecoverableError) + } + + val message = exception.getMessage + info("The exception includes the standard error message") + message should include("Fatal errors during hardware elaboration. Look above for error list.") + + info("The exception should not contain a stack trace") + exception.getStackTrace should be(Array()) + } + + it should "include a stack trace for recoverable errors with '--throw-on-first-error'" in { + val exception = intercept[java.lang.Exception] { + (new ChiselStage).emitChirrtl(new RecoverableError, Array("--throw-on-first-error")) + } + + val stackTrace = exception.getStackTrace.mkString("\n") + info("The exception should contain a truncated stack trace") + stackTrace shouldNot include("java") + + info("The stack trace include information about running --full-stacktrace") + stackTrace should include("--full-stacktrace") + } + + it should "include an untruncated stack trace for recoverable errors when given both '--throw-on-first-error' and '--full-stacktrace'" in { + val exception = intercept[java.lang.Exception] { + val args = Array("--throw-on-first-error", "--full-stacktrace") + (new ChiselStage).emitChirrtl(new RecoverableError, args) + } + + val stackTrace = exception.getStackTrace.mkString("\n") + info("The exception should contain a truncated stack trace") + stackTrace should include("java") + } } -- cgit v1.2.3 From 56d789c17cec32cb985ebce2651bf7269f95b5d1 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 3 Feb 2022 17:24:53 +0000 Subject: FillInterleaved documentation: swap order of elements in Seq example (#2393) (#2395) (cherry picked from commit 055a85298c46c6734880cd828af436adbded1d0a) Co-authored-by: John Ingalls <43973001+ingallsj@users.noreply.github.com>--- src/main/scala/chisel3/util/Bitwise.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Bitwise.scala b/src/main/scala/chisel3/util/Bitwise.scala index 0d8318bf..8abe3645 100644 --- a/src/main/scala/chisel3/util/Bitwise.scala +++ b/src/main/scala/chisel3/util/Bitwise.scala @@ -14,7 +14,7 @@ import chisel3._ * FillInterleaved(2, "b1 0 0 1".U) // equivalent to "b11 00 00 11".U * FillInterleaved(2, myUIntWire) // dynamic interleaved fill * - * FillInterleaved(2, Seq(true.B, false.B, false.B, false.B)) // equivalent to "b11 00 00 00".U + * FillInterleaved(2, Seq(false.B, false.B, false.B, true.B)) // equivalent to "b11 00 00 00".U * FillInterleaved(2, Seq(true.B, false.B, false.B, true.B)) // equivalent to "b11 00 00 11".U * }}} */ -- cgit v1.2.3