From 6e9740efd138523dca3de5a871104f91d884c476 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Wed, 22 Sep 2021 02:56:13 +0800 Subject: implement trace API. (#2077) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- .../scala/chiselTests/experimental/TraceSpec.scala | 309 +++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 src/test/scala/chiselTests/experimental/TraceSpec.scala (limited to 'src') diff --git a/src/test/scala/chiselTests/experimental/TraceSpec.scala b/src/test/scala/chiselTests/experimental/TraceSpec.scala new file mode 100644 index 00000000..59548921 --- /dev/null +++ b/src/test/scala/chiselTests/experimental/TraceSpec.scala @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chiselTests + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.experimental.Trace._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage, DesignAnnotation} +import chisel3.util.experimental.InlineInstance +import firrtl.AnnotationSeq +import firrtl.annotations.TargetToken.{Instance, OfModule, Ref} +import firrtl.annotations.{CompleteTarget, InstanceTarget, ReferenceTarget} +import org.scalatest.matchers.should.Matchers + +class TraceSpec extends ChiselFlatSpec with Matchers { + + def refTarget(topName: String, ref: String, path: Seq[(Instance, OfModule)] = Seq()) = + ReferenceTarget(topName, topName, path, ref, Seq()) + + def instTarget(topName: String, instance: String, ofModule: String, path: Seq[(Instance, OfModule)] = Seq()) = + InstanceTarget(topName, topName, path, instance, ofModule) + + def compile(testName: String, gen: () => Module): (os.Path, AnnotationSeq) = { + val testDir = os.Path(createTestDirectory(testName).getAbsolutePath) + val annos = (new ChiselStage).execute( + Array("--target-dir", s"$testDir"), + Seq( + ChiselGeneratorAnnotation(gen) + ) + ) + (testDir, annos) + } + + "TraceFromAnnotations" should "be able to get nested name." 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 + + traceName(r) + traceName(i) + traceName(o) + } + + class Module1 extends Module { + val i = IO(Input(new Bundle1)) + val m0 = Module(new Module0) + m0.i := i + m0.o := DontCare + } + + object Enum0 extends ChiselEnum { + val s0, s1, s2 = Value + } + + val (testDir, annos) = compile("TraceFromAnnotaions", () => new Module1) + val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module1] + // out of Builder. + + val oneTarget = finalTarget(annos)(dut.m0.r.a.a).head + val ioTarget = finalTarget(annos)(dut.m0.i.b(1)(2)).head + + val topName = "Module1" + oneTarget should be(refTarget(topName, "r_a_a", Seq(Instance("m0") -> OfModule("Module0")))) + + ioTarget should be(refTarget(topName, "i_b_1_2", Seq(Instance("m0") -> OfModule("Module0")))) + + // Below codes doesn't needs to be a FIRRTL Transform. + def generateVerilatorConfigFile(data: Seq[Data], annos: AnnotationSeq): String = + """`verilator_config + |lint_off -rule unused + |lint_off -rule declfilename + |""".stripMargin + + data + .flatMap(finalTarget(annos)) + .toSet + .map { target: CompleteTarget => + s"""public_flat_rd -module "${target.tokens.collectFirst { case OfModule(m) => m }.get}" -var "${target.tokens.collectFirst { case Ref(r) => r }.get}"""" + } + .mkString("\n") + "\n" + + def verilatorTemplate(data: Seq[Data], annos: AnnotationSeq): String = { + val vpiNames = data.flatMap(finalTarget(annos)).map { ct => + s"""TOP.${ct.circuit}.${ct.path.map { case (Instance(i), _) => i }.mkString(".")}.${ct.tokens.collectFirst { case Ref(r) => r }.get}""" + } + s""" + |#include "V${topName}.h" + |#include "verilated_vpi.h" + |#include + |#include + | + |int vpiGetInt(const char name[]) { + | vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8 *)name, NULL); + | if (!vh1) + | vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found"); + | s_vpi_value v; + | v.format = vpiIntVal; + | vpi_get_value(vh1, &v); + | return v.value.integer; + |} + | + |int main(int argc, char **argv) { + | const std::unique_ptr contextp{new VerilatedContext}; + | contextp->commandArgs(argc, argv); + | const std::unique_ptr top{new V$topName{contextp.get(), "TOP"}}; + | top->reset = 0; + | top->clock = 0; + | int a_b = 1; + | top->i_a_b = a_b; + | bool started = false; + | int ticks = 20; + | while (ticks--) { + | contextp->timeInc(1); + | top->clock = !top->clock; + | if (!top->clock) { + | if (contextp->time() > 1 && contextp->time() < 10) { + | top->reset = 1; + | } else { + | top->reset = 0; + | started = true; + | } + | a_b = a_b ? 0 : 1; + | top->i_a_b = a_b; + | } + | top->eval(); + | VerilatedVpi::callValueCbs(); + | if (started && !top->clock) { + | const int i = top->i_a_b; + | const int o = vpiGetInt("${vpiNames.head}"); + | if (i == o) + | vl_fatal(__FILE__, __LINE__, "sim_main", "${vpiNames.head} should be the old value of Module1.i_a_b"); + | printf("${vpiNames.head}=%d Module1.m0.o_a_b=%d\\n", i, o); + | } + | } + | top->final(); + | return 0; + |} + |""".stripMargin + } + + val config = os.temp(dir = testDir, contents = generateVerilatorConfigFile(Seq(dut.m0.o.a.b), annos)) + val verilog = testDir / s"$topName.v" + val cpp = os.temp(dir = testDir, suffix = ".cpp", contents = verilatorTemplate(Seq(dut.m0.o.a.b), annos)) + val exe = testDir / "obj_dir" / s"V$topName" + os.proc("verilator", "-Wall", "--cc", "--exe", "--build", "--vpi", s"$cpp", s"$verilog", s"$config").call(stdout = os.Inherit, stderr = os.Inherit, cwd = testDir) + assert(os.proc(s"$exe").call(stdout = os.Inherit, stderr = os.Inherit).exitCode == 0, "verilator should exit peacefully") + } + + "TraceFromCollideBundle" should "work" in { + class CollideModule extends Module { + val a = IO(Input(Vec(2, new Bundle { + val b = Flipped(Bool()) + val c = Vec(2, new Bundle { + val d = UInt(2.W) + val e = Flipped(UInt(3.W)) + }) + val c_1_e = UInt(4.W) + }))) + val a_0_c = IO(Output(UInt(5.W))) + val a__0 = IO(Output(UInt(5.W))) + a_0_c := DontCare + a__0 := DontCare + + traceName(a) + traceName(a_0_c) + traceName(a__0) + } + + val (_, annos) = compile("TraceFromCollideBundle", () => new CollideModule) + val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[CollideModule] + + val topName = "CollideModule" + + val a0 = finalTarget(annos)(dut.a(0)) + val a__0 = finalTarget(annos)(dut.a__0).head + val a__0_ref = refTarget(topName, "a__0") + a0.foreach(_ shouldNot be(a__0_ref)) + a__0 should be(a__0_ref) + + val a0_c = finalTarget(annos)(dut.a(0).c) + val a_0_c = finalTarget(annos)(dut.a_0_c).head + val a_0_c_ref = refTarget(topName, "a_0_c") + a0_c.foreach(_ shouldNot be(a_0_c_ref)) + a_0_c should be(a_0_c_ref) + + val a0_c1_e = finalTarget(annos)(dut.a(0).c(1).e).head + val a0_c_1_e = finalTarget(annos)(dut.a(0).c_1_e).head + a0_c1_e should be(refTarget(topName, "a_0_c__1_e")) + a0_c_1_e should be(refTarget(topName, "a_0_c_1_e")) + } + + "Inline should work" should "work" in { + class Module0 extends Module { + val i = IO(Input(Bool())) + val o = IO(Output(Bool())) + traceName(i) + o := !i + } + + class Module1 extends Module { + val i = IO(Input(Bool())) + val o = IO(Output(Bool())) + val m0 = Module(new Module0 with InlineInstance) + m0.i := i + o := m0.o + } + + val (_, annos) = compile("Inline", () => new Module1) + val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module1] + + val m0_i = finalTarget(annos)(dut.m0.i).head + m0_i should be(refTarget("Module1", "m0_i")) + } + + "Constant Propagation" should "be turned off by traceName" in { + class Module0 extends Module { + val i = WireDefault(1.U) + val i0 = i + 1.U + val o = IO(Output(UInt(2.W))) + traceName(i0) + o := i0 + } + + val (_, annos) = compile("ConstantProp", () => new Module0) + val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module0] + + val i0 = finalTarget(annos)(dut.i0).head + i0 should be(refTarget("Module0", "i0")) + } + + "Nested Module" should "work" in { + class Io extends Bundle { + val i = Input(Bool()) + val o = Output(Bool()) + } + + class Not extends Module { + val io = IO(new Io) + io.o := !io.i + } + + class M1 extends Module { + val io = IO(new Io) + val not = Module(new Not) + not.io <> io + } + + class M2 extends Module { + val io = IO(new Io) + val m1 = Module(new M1 with InlineInstance) + val not = Module(new Not) + + m1.io.i := io.i + not.io.i := io.i + + io.o := m1.io.o && not.io.o + } + + class M3 extends Module { + val io = IO(new Io) + val m2 = Module(new M2) + io <> m2.io + traceName(m2.not) + traceName(m2.m1.not) + } + + val (_, annos) = compile("NestedModule", () => new M3) + val m3 = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[M3] + + val m2_m1_not = finalTarget(annos)(m3.m2.m1.not).head + val m2_not = finalTarget(annos)(m3.m2.not).head + + m2_m1_not should be(instTarget("M3", "m1_not", "Not", Seq(Instance("m2") -> OfModule("M2")))) + m2_not should be(instTarget("M3", "not", "Not", Seq(Instance("m2") -> OfModule("M2")))) + } + + "All traced signal" should "generate" in { + class M extends Module { + val a = Wire(Bool()) + val b = Wire(Vec(2, Bool())) + a := DontCare + b := DontCare + Seq(a, b).foreach(traceName) + } + val (_, annos) = compile("NestedModule", () => new M) + val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[M] + val allTargets = finalTargetMap(annos) + allTargets(dut.a.toAbsoluteTarget) should be (Seq(refTarget("M", "a"))) + allTargets(dut.b.toAbsoluteTarget) should be (Seq( + refTarget("M", "b_0"), + refTarget("M", "b_1"), + )) + allTargets(dut.b(0).toAbsoluteTarget) should be (Seq(refTarget("M", "b_0"))) + allTargets(dut.b(1).toAbsoluteTarget) should be (Seq(refTarget("M", "b_1"))) + } +} -- cgit v1.2.3 From d1d38bd096fce8b92468720fbedc835ecda40e6b Mon Sep 17 00:00:00 2001 From: Kevin Laeufer Date: Thu, 23 Sep 2021 11:12:26 -0700 Subject: make all verification statements publically available (#2089) --- src/main/scala/chisel3/aop/Select.scala | 2 +- .../experimental/verification/package.scala | 27 ++++ src/main/scala/chisel3/testers/BasicTester.scala | 7 +- src/test/scala/chiselTests/PrintableSpec.scala | 8 +- src/test/scala/chiselTests/VerificationSpec.scala | 153 ++++++++++++++++++++ src/test/scala/chiselTests/aop/SelectSpec.scala | 7 +- .../verification/VerificationSpec.scala | 154 --------------------- 7 files changed, 189 insertions(+), 169 deletions(-) create mode 100644 src/main/scala/chisel3/experimental/verification/package.scala create mode 100644 src/test/scala/chiselTests/VerificationSpec.scala delete mode 100644 src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala (limited to 'src') diff --git a/src/main/scala/chisel3/aop/Select.scala b/src/main/scala/chisel3/aop/Select.scala index 2384c4d3..9c7320ce 100644 --- a/src/main/scala/chisel3/aop/Select.scala +++ b/src/main/scala/chisel3/aop/Select.scala @@ -269,7 +269,7 @@ object Select { val stops = mutable.ArrayBuffer[Stop]() searchWhens(module, (cmd: Command, preds: Seq[Predicate]) => { cmd match { - case chisel3.internal.firrtl.Stop(_, clock, ret) => stops += Stop(preds, ret, getId(clock).asInstanceOf[Clock]) + case chisel3.internal.firrtl.Stop(_, _, clock, ret) => stops += Stop(preds, ret, getId(clock).asInstanceOf[Clock]) case other => } }) diff --git a/src/main/scala/chisel3/experimental/verification/package.scala b/src/main/scala/chisel3/experimental/verification/package.scala new file mode 100644 index 00000000..f95b30bc --- /dev/null +++ b/src/main/scala/chisel3/experimental/verification/package.scala @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3.experimental + +import chisel3.{Bool, CompileOptions} +import chisel3.internal.sourceinfo.SourceInfo + +package object verification { + + object assert { + @deprecated("Please use chisel3.assert instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.4") + def apply(predicate: Bool, msg: String = "") + (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.assert.Assert = chisel3.assert(predicate, msg) + } + + object assume { + @deprecated("Please use chisel3.assume instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.4") + def apply(predicate: Bool, msg: String = "") + (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.assume.Assume = chisel3.assume(predicate, msg) + } + + object cover { + @deprecated("Please use chisel3.cover instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.4") + def apply(predicate: Bool, msg: String = "") + (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.cover.Cover = chisel3.cover(predicate, msg) + } +} diff --git a/src/main/scala/chisel3/testers/BasicTester.scala b/src/main/scala/chisel3/testers/BasicTester.scala index d17407ea..99002660 100644 --- a/src/main/scala/chisel3/testers/BasicTester.scala +++ b/src/main/scala/chisel3/testers/BasicTester.scala @@ -21,12 +21,7 @@ class BasicTester extends Module() { * reset). If your definition of reset is not the encapsulating Module's * reset, you will need to gate this externally. */ - def stop()(implicit sourceInfo: SourceInfo) { - // TODO: rewrite this using library-style SourceInfo passing. - when (!reset.asBool) { - pushCommand(Stop(sourceInfo, clock.ref, 0)) - } - } + def stop()(implicit sourceInfo: SourceInfo): Unit = chisel3.stop() /** The finish method provides a hook that subclasses of BasicTester can use to * alter a circuit after their constructor has been called. diff --git a/src/test/scala/chiselTests/PrintableSpec.scala b/src/test/scala/chiselTests/PrintableSpec.scala index 25b54966..95103352 100644 --- a/src/test/scala/chiselTests/PrintableSpec.scala +++ b/src/test/scala/chiselTests/PrintableSpec.scala @@ -3,7 +3,7 @@ package chiselTests import chisel3._ -import chisel3.experimental.{BaseSim, ChiselAnnotation} +import chisel3.experimental.ChiselAnnotation import chisel3.stage.ChiselStage import chisel3.testers.BasicTester import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation} @@ -23,7 +23,7 @@ object PrintfAnnotation { /** Create annotation for a given [[printf]]. * @param c component to be annotated */ - def annotate(c: BaseSim): Unit = { + def annotate(c: VerificationStatement): Unit = { chisel3.experimental.annotate(new ChiselAnnotation { def toFirrtl: PrintfAnnotation = PrintfAnnotation(c.toTarget) }) @@ -246,7 +246,7 @@ class PrintableSpec extends AnyFlatSpec with Matchers { // check for expected annotations exactly(3, annoLines) should include ("chiselTests.PrintfAnnotation") exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>farewell") - exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>SIM") + exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>printf") exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>howdy") // read in FIRRTL file @@ -256,7 +256,7 @@ class PrintableSpec extends AnyFlatSpec with Matchers { // check that verification components have expected names exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "hello AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : howdy""") - exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "goodbye AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : SIM""") + exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "goodbye AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : printf""") exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "adieu AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : farewell""") } } diff --git a/src/test/scala/chiselTests/VerificationSpec.scala b/src/test/scala/chiselTests/VerificationSpec.scala new file mode 100644 index 00000000..2d7144df --- /dev/null +++ b/src/test/scala/chiselTests/VerificationSpec.scala @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chiselTests + +import chisel3._ +import chisel3.experimental.{ChiselAnnotation, verification => formal} +import chisel3.stage.ChiselStage +import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation} +import org.scalatest.matchers.should.Matchers + +import java.io.File + +class SimpleTest extends Module { + val io = IO(new Bundle{ + val in = Input(UInt(8.W)) + val out = Output(UInt(8.W)) + }) + io.out := io.in + cover(io.in === 3.U) + when (io.in === 3.U) { + assume(io.in =/= 2.U) + assert(io.out === io.in) + } +} + +/** Dummy verification annotation. + * @param target target of component to be annotated + */ +case class VerifAnnotation(target: ReferenceTarget) extends SingleTargetAnnotation[ReferenceTarget] { + def duplicate(n: ReferenceTarget): VerifAnnotation = this.copy(target = n) +} + +object VerifAnnotation { + /** Create annotation for a given verification component. + * @param c component to be annotated + */ + def annotate(c: VerificationStatement): Unit = { + chisel3.experimental.annotate(new ChiselAnnotation { + def toFirrtl: VerifAnnotation = VerifAnnotation(c.toTarget) + }) + } +} + +class VerificationSpec extends ChiselPropSpec with Matchers { + + def assertContains(s: Seq[String], x: String): Unit = { + val containsLine = s.map(_.contains(x)).reduce(_ || _) + assert(containsLine, s"\n $x\nwas not found in`\n ${s.mkString("\n ")}``") + } + + property("basic equality check should work") { + val fir = ChiselStage.emitChirrtl(new SimpleTest) + val lines = fir.split("\n").map(_.trim) + + // reset guard around the verification statement + assertContains(lines, "when _T_2 : @[VerificationSpec.scala") + assertContains(lines, "cover(clock, _T, UInt<1>(\"h1\"), \"\")") + + assertContains(lines, "when _T_6 : @[VerificationSpec.scala") + assertContains(lines, "assume(clock, _T_4, UInt<1>(\"h1\"), \"\")") + + assertContains(lines, "when _T_10 : @[VerificationSpec.scala") + assertContains(lines, "assert(clock, _T_8, UInt<1>(\"h1\"), \"\")") + } + + property("annotation of verification constructs should work") { + /** Circuit that contains and annotates verification nodes. */ + class AnnotationTest extends Module { + val io = IO(new Bundle{ + val in = Input(UInt(8.W)) + val out = Output(UInt(8.W)) + }) + io.out := io.in + val cov = cover(io.in === 3.U) + val assm = chisel3.assume(io.in =/= 2.U) + val asst = chisel3.assert(io.out === io.in) + VerifAnnotation.annotate(cov) + VerifAnnotation.annotate(assm) + VerifAnnotation.annotate(asst) + } + + // compile circuit + val testDir = new File("test_run_dir", "VerificationAnnotationTests") + (new ChiselStage).emitSystemVerilog( + gen = new AnnotationTest, + args = Array("-td", testDir.getPath) + ) + + // read in annotation file + val annoFile = new File(testDir, "AnnotationTest.anno.json") + annoFile should exist + val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList + + // check for expected verification annotations + exactly(3, annoLines) should include ("chiselTests.VerifAnnotation") + exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>asst") + exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>assm") + exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>cov") + + // read in FIRRTL file + val firFile = new File(testDir, "AnnotationTest.fir") + firFile should exist + 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") + } + + property("annotation of verification constructs with suggested name should work") { + /** Circuit that annotates a renamed verification nodes. */ + class AnnotationRenameTest extends Module { + val io = IO(new Bundle{ + val in = Input(UInt(8.W)) + val out = Output(UInt(8.W)) + }) + io.out := io.in + + val goodbye = chisel3.assert(io.in === 1.U) + goodbye.suggestName("hello") + VerifAnnotation.annotate(goodbye) + + VerifAnnotation.annotate(chisel3.assume(io.in =/= 2.U).suggestName("howdy")) + } + + // compile circuit + val testDir = new File("test_run_dir", "VerificationAnnotationRenameTests") + (new ChiselStage).emitSystemVerilog( + gen = new AnnotationRenameTest, + args = Array("-td", testDir.getPath) + ) + + // read in annotation file + val annoFile = new File(testDir, "AnnotationRenameTest.anno.json") + annoFile should exist + val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList + + // check for expected verification annotations + exactly(2, annoLines) should include ("chiselTests.VerifAnnotation") + exactly(1, annoLines) should include ("~AnnotationRenameTest|AnnotationRenameTest>hello") + exactly(1, annoLines) should include ("~AnnotationRenameTest|AnnotationRenameTest>howdy") + + // read in FIRRTL file + val firFile = new File(testDir, "AnnotationRenameTest.fir") + firFile should exist + 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") + } +} diff --git a/src/test/scala/chiselTests/aop/SelectSpec.scala b/src/test/scala/chiselTests/aop/SelectSpec.scala index e09e78c8..2b47c6b8 100644 --- a/src/test/scala/chiselTests/aop/SelectSpec.scala +++ b/src/test/scala/chiselTests/aop/SelectSpec.scala @@ -133,11 +133,10 @@ class SelectSpec extends ChiselFlatSpec { { dut: SelectTester => Seq(Select.Stop( Seq( - When(Select.ops("eq")(dut).dropRight(1).last.asInstanceOf[Bool]), - When(dut.nreset), - WhenNot(dut.overflow) + When(Select.ops("eq")(dut)(1).asInstanceOf[Bool]), + When(dut.overflow) ), - 1, + 0, dut.clock )) } diff --git a/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala b/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala deleted file mode 100644 index 1e080739..00000000 --- a/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala +++ /dev/null @@ -1,154 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chiselTests.experimental.verification - -import chisel3._ -import chisel3.experimental.{ChiselAnnotation, verification => formal} -import chisel3.stage.ChiselStage -import chiselTests.ChiselPropSpec -import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation} - -import java.io.File -import org.scalatest.matchers.should.Matchers - -class SimpleTest extends Module { - val io = IO(new Bundle{ - val in = Input(UInt(8.W)) - val out = Output(UInt(8.W)) - }) - io.out := io.in - formal.cover(io.in === 3.U) - when (io.in === 3.U) { - formal.assume(io.in =/= 2.U) - formal.assert(io.out === io.in) - } -} - -/** Dummy verification annotation. - * @param target target of component to be annotated - */ -case class VerifAnnotation(target: ReferenceTarget) extends SingleTargetAnnotation[ReferenceTarget] { - def duplicate(n: ReferenceTarget): VerifAnnotation = this.copy(target = n) -} - -object VerifAnnotation { - /** Create annotation for a given verification component. - * @param c component to be annotated - */ - def annotate(c: experimental.BaseSim): Unit = { - chisel3.experimental.annotate(new ChiselAnnotation { - def toFirrtl: VerifAnnotation = VerifAnnotation(c.toTarget) - }) - } -} - -class VerificationSpec extends ChiselPropSpec with Matchers { - - def assertContains(s: Seq[String], x: String): Unit = { - val containsLine = s.map(_.contains(x)).reduce(_ || _) - assert(containsLine, s"\n $x\nwas not found in`\n ${s.mkString("\n ")}``") - } - - property("basic equality check should work") { - val fir = ChiselStage.emitChirrtl(new SimpleTest) - val lines = fir.split("\n").map(_.trim) - - // reset guard around the verification statement - assertContains(lines, "when _T_2 : @[VerificationSpec.scala") - assertContains(lines, "cover(clock, _T, UInt<1>(\"h1\"), \"\")") - - assertContains(lines, "when _T_6 : @[VerificationSpec.scala") - assertContains(lines, "assume(clock, _T_4, UInt<1>(\"h1\"), \"\")") - - assertContains(lines, "when _T_9 : @[VerificationSpec.scala") - assertContains(lines, "assert(clock, _T_7, UInt<1>(\"h1\"), \"\")") - } - - property("annotation of verification constructs should work") { - /** Circuit that contains and annotates verification nodes. */ - class AnnotationTest extends Module { - val io = IO(new Bundle{ - val in = Input(UInt(8.W)) - val out = Output(UInt(8.W)) - }) - io.out := io.in - val cov = formal.cover(io.in === 3.U) - val assm = formal.assume(io.in =/= 2.U) - val asst = formal.assert(io.out === io.in) - VerifAnnotation.annotate(cov) - VerifAnnotation.annotate(assm) - VerifAnnotation.annotate(asst) - } - - // compile circuit - val testDir = new File("test_run_dir", "VerificationAnnotationTests") - (new ChiselStage).emitSystemVerilog( - gen = new AnnotationTest, - args = Array("-td", testDir.getPath) - ) - - // read in annotation file - val annoFile = new File(testDir, "AnnotationTest.anno.json") - annoFile should exist - val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList - - // check for expected verification annotations - exactly(3, annoLines) should include ("chiselTests.experimental.verification.VerifAnnotation") - exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>asst") - exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>assm") - exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>cov") - - // read in FIRRTL file - val firFile = new File(testDir, "AnnotationTest.fir") - firFile should exist - 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_6, UInt<1>(\"h1\"), \"\") : asst") - } - - property("annotation of verification constructs with suggested name should work") { - /** Circuit that annotates a renamed verification nodes. */ - class AnnotationRenameTest extends Module { - val io = IO(new Bundle{ - val in = Input(UInt(8.W)) - val out = Output(UInt(8.W)) - }) - io.out := io.in - - val goodbye = formal.assert(io.in === 1.U) - goodbye.suggestName("hello") - VerifAnnotation.annotate(goodbye) - - VerifAnnotation.annotate(formal.assume(io.in =/= 2.U).suggestName("howdy")) - } - - // compile circuit - val testDir = new File("test_run_dir", "VerificationAnnotationRenameTests") - (new ChiselStage).emitSystemVerilog( - gen = new AnnotationRenameTest, - args = Array("-td", testDir.getPath) - ) - - // read in annotation file - val annoFile = new File(testDir, "AnnotationRenameTest.anno.json") - annoFile should exist - val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList - - // check for expected verification annotations - exactly(2, annoLines) should include ("chiselTests.experimental.verification.VerifAnnotation") - exactly(1, annoLines) should include ("~AnnotationRenameTest|AnnotationRenameTest>hello") - exactly(1, annoLines) should include ("~AnnotationRenameTest|AnnotationRenameTest>howdy") - - // read in FIRRTL file - val firFile = new File(testDir, "AnnotationRenameTest.fir") - firFile should exist - 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_3, UInt<1>(\"h1\"), \"\") : howdy") - } -} -- cgit v1.2.3 From 92f1ace73c85de859082eaa917eaacfce026fdf8 Mon Sep 17 00:00:00 2001 From: Kevin Laeufer Date: Thu, 23 Sep 2021 13:44:03 -0700 Subject: verification: fix off by one error in deprecation message (#2135) --- src/main/scala/chisel3/experimental/verification/package.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/experimental/verification/package.scala b/src/main/scala/chisel3/experimental/verification/package.scala index f95b30bc..a026542d 100644 --- a/src/main/scala/chisel3/experimental/verification/package.scala +++ b/src/main/scala/chisel3/experimental/verification/package.scala @@ -8,19 +8,19 @@ import chisel3.internal.sourceinfo.SourceInfo package object verification { object assert { - @deprecated("Please use chisel3.assert instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.4") + @deprecated("Please use chisel3.assert instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5") def apply(predicate: Bool, msg: String = "") (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.assert.Assert = chisel3.assert(predicate, msg) } object assume { - @deprecated("Please use chisel3.assume instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.4") + @deprecated("Please use chisel3.assume instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5") def apply(predicate: Bool, msg: String = "") (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.assume.Assume = chisel3.assume(predicate, msg) } object cover { - @deprecated("Please use chisel3.cover instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.4") + @deprecated("Please use chisel3.cover instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5") def apply(predicate: Bool, msg: String = "") (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.cover.Cover = chisel3.cover(predicate, msg) } -- cgit v1.2.3 From ce15ad50a5c175db06c3bba5e3bf46b6c5466c47 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Tue, 5 Oct 2021 10:27:18 -0700 Subject: Remove all Bundle cloneTypes and chiselRuntimeDeprecate its use (#2052) * Remove all manual cloneTypes and make it chisel runtime deprecated to add one * runtime deprecate cloneType with runtime reflection * [Backport this commit] Bundle: add check that override def cloneType still works (will be made an error later) * Plugin: make it an error to override cloneType and add a test for that * Docs: can't compile the cloneType anymore * BundleSpec: comment out failing test I cannot get to fail or ignore Co-authored-by: Jack Koenig --- src/main/scala/chisel3/util/BitPat.scala | 1 - src/main/scala/chisel3/util/Decoupled.scala | 6 ------ src/main/scala/chisel3/util/Enum.scala | 1 - src/main/scala/chisel3/util/Valid.scala | 2 -- src/test/scala/chiselTests/AutoClonetypeSpec.scala | 1 - src/test/scala/chiselTests/BundleSpec.scala | 17 ++++++++++++----- .../chiselTests/CompatibilityInteroperabilitySpec.scala | 5 ----- src/test/scala/chiselTests/CompatibilitySpec.scala | 2 -- src/test/scala/chiselTests/CompileOptionsTest.scala | 2 -- src/test/scala/chiselTests/ComplexAssign.scala | 5 +---- src/test/scala/chiselTests/PrintableSpec.scala | 1 - src/test/scala/chiselTests/RecordSpec.scala | 1 - 12 files changed, 13 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 0dcb2466..d607be4f 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -4,7 +4,6 @@ package chisel3.util import scala.language.experimental.macros import chisel3._ -import chisel3.internal.chiselRuntimeDeprecated import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 8909ffe3..0e05d114 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -82,9 +82,6 @@ object ReadyValidIO { * @param gen the type of data to be wrapped in DecoupledIO */ class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen) -{ - override def cloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type] -} /** This factory adds a decoupled handshaking protocol to a data bundle. */ object Decoupled @@ -123,9 +120,6 @@ object Decoupled * @param gen the type of data to be wrapped in IrrevocableIO */ class IrrevocableIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen) -{ - override def cloneType: this.type = new IrrevocableIO(gen).asInstanceOf[this.type] -} /** Factory adds an irrevocable handshaking protocol to a data bundle. */ object Irrevocable diff --git a/src/main/scala/chisel3/util/Enum.scala b/src/main/scala/chisel3/util/Enum.scala index bf150464..4501a2de 100644 --- a/src/main/scala/chisel3/util/Enum.scala +++ b/src/main/scala/chisel3/util/Enum.scala @@ -6,7 +6,6 @@ package chisel3.util import chisel3._ -import chisel3.internal.chiselRuntimeDeprecated /** Defines a set of unique UInt constants * diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala index 6c6d685e..838d43ca 100644 --- a/src/main/scala/chisel3/util/Valid.scala +++ b/src/main/scala/chisel3/util/Valid.scala @@ -29,8 +29,6 @@ class Valid[+T <: Data](gen: T) extends Bundle { * @return a Chisel [[Bool]] true if `valid` is asserted */ def fire(dummy: Int = 0): Bool = valid - - override def cloneType: this.type = Valid(gen).asInstanceOf[this.type] } /** Factory for generating "valid" interfaces. A "valid" interface is a data-communicating interface between a producer diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala index fcbc4785..3f33fda8 100644 --- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala +++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala @@ -327,7 +327,6 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { it should "support Bundles that implement their own cloneType" in { class MyBundle(i: Int) extends Bundle { val foo = UInt(i.W) - override def cloneType = new MyBundle(i).asInstanceOf[this.type] } elaborate { new MultiIOModule { val in = IO(Input(new MyBundle(8))) diff --git a/src/test/scala/chiselTests/BundleSpec.scala b/src/test/scala/chiselTests/BundleSpec.scala index 1d392f5c..51dedfb1 100644 --- a/src/test/scala/chiselTests/BundleSpec.scala +++ b/src/test/scala/chiselTests/BundleSpec.scala @@ -10,25 +10,20 @@ trait BundleSpecUtils { class BundleFooBar extends Bundle { val foo = UInt(16.W) val bar = UInt(16.W) - override def cloneType: this.type = (new BundleFooBar).asInstanceOf[this.type] } class BundleBarFoo extends Bundle { val bar = UInt(16.W) val foo = UInt(16.W) - override def cloneType: this.type = (new BundleBarFoo).asInstanceOf[this.type] } class BundleFoo extends Bundle { val foo = UInt(16.W) - override def cloneType: this.type = (new BundleFoo).asInstanceOf[this.type] } class BundleBar extends Bundle { val bar = UInt(16.W) - override def cloneType: this.type = (new BundleBar).asInstanceOf[this.type] } class BadSeqBundle extends Bundle { val bar = Seq(UInt(16.W), UInt(8.W), UInt(4.W)) - override def cloneType: this.type = (new BadSeqBundle).asInstanceOf[this.type] } class MyModule(output: Bundle, input: Bundle) extends Module { @@ -162,4 +157,16 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils { } } } + + // This tests the interaction of override def cloneType and the plugin. + // We are commenting it for now because although this code fails to compile + // as expected when just copied here, the test version is not seeing the failure. + // """ + // class BundleBaz(w: Int) extends Bundle { + // val baz = UInt(w.W) + // // This is a compiler error when using the plugin, which we test below. + // override def cloneType = (new BundleBaz(w)).asInstanceOf[this.type] + // } + // """ shouldNot compile + } diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala index 1795cc1f..4b03dfa5 100644 --- a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala +++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala @@ -12,8 +12,6 @@ object CompatibilityComponents { class ChiselBundle extends Bundle { val a = UInt(width = 32) val b = UInt(width = 32).flip - - override def cloneType: this.type = (new ChiselBundle).asInstanceOf[this.type] } class ChiselRecord extends Record { val elements = ListMap("a" -> UInt(width = 32), "b" -> UInt(width = 32).flip) @@ -48,8 +46,6 @@ object Chisel3Components { class Chisel3Bundle extends Bundle { val a = Output(UInt(32.W)) val b = Input(UInt(32.W)) - - override def cloneType: this.type = (new Chisel3Bundle).asInstanceOf[this.type] } class Chisel3Record extends Record { @@ -341,7 +337,6 @@ class CompatibiltyInteroperabilitySpec extends ChiselFlatSpec { val foo = maybeFlip(new Bundle { val bar = UInt(INPUT, width = 8) }) - override def cloneType = (new MyBundle(extraFlip)).asInstanceOf[this.type] } } import chisel3._ diff --git a/src/test/scala/chiselTests/CompatibilitySpec.scala b/src/test/scala/chiselTests/CompatibilitySpec.scala index 2d4ad517..bf8cd3fc 100644 --- a/src/test/scala/chiselTests/CompatibilitySpec.scala +++ b/src/test/scala/chiselTests/CompatibilitySpec.scala @@ -195,11 +195,9 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck class SmallBundle extends Bundle { val f1 = UInt(width = 4) val f2 = UInt(width = 5) - override def cloneType: this.type = (new SmallBundle).asInstanceOf[this.type] } class BigBundle extends SmallBundle { val f3 = UInt(width = 6) - override def cloneType: this.type = (new BigBundle).asInstanceOf[this.type] } "A Module with missing bundle fields when compiled with the Chisel compatibility package" should "not throw an exception" in { diff --git a/src/test/scala/chiselTests/CompileOptionsTest.scala b/src/test/scala/chiselTests/CompileOptionsTest.scala index 9c88c1e0..1ecf97f0 100644 --- a/src/test/scala/chiselTests/CompileOptionsTest.scala +++ b/src/test/scala/chiselTests/CompileOptionsTest.scala @@ -14,11 +14,9 @@ class CompileOptionsSpec extends ChiselFlatSpec with Utils { class SmallBundle extends Bundle { val f1 = UInt(4.W) val f2 = UInt(5.W) - override def cloneType: this.type = (new SmallBundle).asInstanceOf[this.type] } class BigBundle extends SmallBundle { val f3 = UInt(6.W) - override def cloneType: this.type = (new BigBundle).asInstanceOf[this.type] } "A Module with missing bundle fields when compiled with implicit Strict.CompileOption " should "throw an exception" in { diff --git a/src/test/scala/chiselTests/ComplexAssign.scala b/src/test/scala/chiselTests/ComplexAssign.scala index 36fb59c2..222b6373 100644 --- a/src/test/scala/chiselTests/ComplexAssign.scala +++ b/src/test/scala/chiselTests/ComplexAssign.scala @@ -7,10 +7,7 @@ import chisel3.testers.BasicTester import chisel3.util._ import org.scalacheck.Shrink -class Complex[T <: Data](val re: T, val im: T) extends Bundle { - override def cloneType: this.type = - new Complex(re.cloneType, im.cloneType).asInstanceOf[this.type] -} +class Complex[T <: Data](val re: T, val im: T) extends Bundle class ComplexAssign(w: Int) extends Module { val io = IO(new Bundle { diff --git a/src/test/scala/chiselTests/PrintableSpec.scala b/src/test/scala/chiselTests/PrintableSpec.scala index 95103352..c7e819ec 100644 --- a/src/test/scala/chiselTests/PrintableSpec.scala +++ b/src/test/scala/chiselTests/PrintableSpec.scala @@ -139,7 +139,6 @@ class PrintableSpec extends AnyFlatSpec with Matchers { } class MyBundle extends Bundle { val foo = UInt(32.W) - override def cloneType: this.type = (new MyBundle).asInstanceOf[this.type] } class MyModule extends BasicTester { override def desiredName: String = "MyModule" diff --git a/src/test/scala/chiselTests/RecordSpec.scala b/src/test/scala/chiselTests/RecordSpec.scala index c21d455c..f0edca8b 100644 --- a/src/test/scala/chiselTests/RecordSpec.scala +++ b/src/test/scala/chiselTests/RecordSpec.scala @@ -12,7 +12,6 @@ trait RecordSpecUtils { class MyBundle extends Bundle { val foo = UInt(32.W) val bar = UInt(32.W) - override def cloneType: this.type = (new MyBundle).asInstanceOf[this.type] } // Useful for constructing types from CustomBundle // This is a def because each call to this needs to return a new instance -- cgit v1.2.3 From 110705eeace4f9165dc6377e55c86a599f37a465 Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Tue, 5 Oct 2021 12:33:23 -0700 Subject: Deprecate auto-application of empty argument lists to parameterless functions (#2124) * Migrate nullary funcs to parameterless versions * Make deprecation message and dummy arguments clear and consistent Co-authored-by: Megan Wachs --- src/main/scala/chisel3/compatibility.scala | 5 ++- src/main/scala/chisel3/util/Decoupled.scala | 9 +++-- src/test/scala/chiselTests/SIntOps.scala | 2 +- src/test/scala/chiselTests/StrongEnum.scala | 4 +-- src/test/scala/chiselTests/VecLiteralSpec.scala | 48 ++++++++++++------------- 5 files changed, 37 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index dde2321d..ffbb7e27 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -33,7 +33,10 @@ package object Chisel { implicit class AddDirectionToData[T<:Data](target: T) { def asInput: T = Input(target) def asOutput: T = Output(target) - def flip(): T = Flipped(target) + def flip: T = Flipped(target) + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def flip(dummy: Int*): T = flip } implicit class AddDirMethodToData[T<:Data](target: T) { diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 0e05d114..060a684c 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -37,7 +37,10 @@ object ReadyValidIO { /** Indicates if IO is both ready and valid */ - def fire(): Bool = target.ready && target.valid + def fire: Bool = target.ready && target.valid + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def fire(dummy: Int = 0): Bool = fire /** Push dat onto the output bits of this interface to let the consumer know it has happened. * @param dat the values to assign to bits. @@ -222,8 +225,8 @@ class Queue[T <: Data](val gen: T, val ptr_match = enq_ptr.value === deq_ptr.value val empty = ptr_match && !maybe_full val full = ptr_match && maybe_full - val do_enq = WireDefault(io.enq.fire()) - val do_deq = WireDefault(io.deq.fire()) + val do_enq = WireDefault(io.enq.fire) + val do_deq = WireDefault(io.deq.fire) val flush = io.flush.getOrElse(false.B) // when flush is high, empty the queue diff --git a/src/test/scala/chiselTests/SIntOps.scala b/src/test/scala/chiselTests/SIntOps.scala index f2e238e9..222d0ba7 100644 --- a/src/test/scala/chiselTests/SIntOps.scala +++ b/src/test/scala/chiselTests/SIntOps.scala @@ -44,7 +44,7 @@ class SIntOps extends Module { io.noteqout := (a =/= b) io.lesseqout := a <= b io.greateqout := a >= b - // io.negout := -a(15, 0).toSInt + io.negout := -a(15, 0).asSInt io.negout := (0.S -% a) } diff --git a/src/test/scala/chiselTests/StrongEnum.scala b/src/test/scala/chiselTests/StrongEnum.scala index d7dea571..404c3f66 100644 --- a/src/test/scala/chiselTests/StrongEnum.scala +++ b/src/test/scala/chiselTests/StrongEnum.scala @@ -257,8 +257,8 @@ class IsLitTester extends BasicTester { for (e <- EnumExample.all) { val wire = WireDefault(e) - assert(e.isLit()) - assert(!wire.isLit()) + assert(e.isLit) + assert(!wire.isLit) } stop() } diff --git a/src/test/scala/chiselTests/VecLiteralSpec.scala b/src/test/scala/chiselTests/VecLiteralSpec.scala index d91cd2f4..74d8c005 100644 --- a/src/test/scala/chiselTests/VecLiteralSpec.scala +++ b/src/test/scala/chiselTests/VecLiteralSpec.scala @@ -142,17 +142,17 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils { "lowest of vec literal contains least significant bits and " in { val y = Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 1 -> 0xCD.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W)) - y.litValue() should be(BigInt("FFEFCDAB", 16)) + y.litValue should be(BigInt("FFEFCDAB", 16)) } "the order lits are specified does not matter" in { val y = Vec(4, UInt(8.W)).Lit(3 -> 0xFF.U(8.W), 2 -> 0xEF.U(8.W), 1 -> 0xCD.U(8.W), 0 -> 0xAB.U(8.W)) - y.litValue() should be(BigInt("FFEFCDAB", 16)) + y.litValue should be(BigInt("FFEFCDAB", 16)) } "regardless of the literals widths, packing should be done based on the width of the Vec's gen" in { val z = Vec(4, UInt(8.W)).Lit(0 -> 0x2.U, 1 -> 0x2.U, 2 -> 0x2.U, 3 -> 0x3.U) - z.litValue() should be(BigInt("03020202", 16)) + z.litValue should be(BigInt("03020202", 16)) } "packing sparse vec lits should not pack, litOption returns None" in { @@ -221,7 +221,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils { chisel3.assert(outsideVecLit(2) === 0xBB.U) chisel3.assert(outsideVecLit(3) === 0xAA.U) - chisel3.assert(outsideVecLit.litValue().U === outsideVecLit.asUInt()) + chisel3.assert(outsideVecLit.litValue.U === outsideVecLit.asUInt()) val insideVecLit = Vec(4, UInt(16.W)).Lit(0 -> 0xDD.U, 1 -> 0xCC.U, 2 -> 0xBB.U, 3 -> 0xAA.U) chisel3.assert(insideVecLit(0) === 0xDD.U) @@ -277,15 +277,15 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils { 1 -> Vec(3, UInt(4.W)).Lit(0 -> 4.U, 1 -> 5.U, 2 -> 6.U) ) - outerVec.litValue() should be (BigInt("654321", 16)) - outerVec(0).litValue() should be (BigInt("321", 16)) - outerVec(1).litValue() should be (BigInt("654", 16)) - outerVec(0)(0).litValue() should be (BigInt(1)) - outerVec(0)(1).litValue() should be (BigInt(2)) - outerVec(0)(2).litValue() should be (BigInt(3)) - outerVec(1)(0).litValue() should be (BigInt(4)) - outerVec(1)(1).litValue() should be (BigInt(5)) - outerVec(1)(2).litValue() should be (BigInt(6)) + outerVec.litValue should be (BigInt("654321", 16)) + outerVec(0).litValue should be (BigInt("321", 16)) + outerVec(1).litValue should be (BigInt("654", 16)) + outerVec(0)(0).litValue should be (BigInt(1)) + outerVec(0)(1).litValue should be (BigInt(2)) + outerVec(0)(2).litValue should be (BigInt(3)) + outerVec(1)(0).litValue should be (BigInt(4)) + outerVec(1)(1).litValue should be (BigInt(5)) + outerVec(1)(2).litValue should be (BigInt(6)) } "contained vecs should work" in { @@ -473,19 +473,19 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils { 0 -> (new SubBundle).Lit(_.foo -> 0xab.U, _.bar -> 0xc.U), 1 -> (new SubBundle).Lit(_.foo -> 0xde.U, _.bar -> 0xf.U) ) - vec.litValue().toString(16) should be("defabc") + vec.litValue.toString(16) should be("defabc") } "vec literals can have bundle children assembled incrementally" in { val bundle1 = (new SubBundle).Lit(_.foo -> 0xab.U, _.bar -> 0xc.U) val bundle2 = (new SubBundle).Lit(_.foo -> 0xde.U, _.bar -> 0xf.U) - bundle1.litValue().toString(16) should be("abc") - bundle2.litValue().toString(16) should be("def") + bundle1.litValue.toString(16) should be("abc") + bundle2.litValue.toString(16) should be("def") val vec = Vec(2, new SubBundle).Lit(0 -> bundle1, 1 -> bundle2) - vec.litValue().toString(16) should be("defabc") + vec.litValue.toString(16) should be("defabc") } "bundles can contain vec lits" in { @@ -495,7 +495,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils { val foo = Vec(3, UInt(4.W)) val bar = Vec(2, UInt(4.W)) }).Lit(_.foo -> vec1, _.bar -> vec2) - bundle.litValue().toString(16) should be("cbaed") + bundle.litValue.toString(16) should be("cbaed") } "bundles can contain vec lits in-line" in { @@ -506,21 +506,21 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils { _.foo -> Vec(3, UInt(4.W)).Lit(0 -> 0xa.U, 1 -> 0xb.U, 2 -> 0xc.U), _.bar -> Vec(2, UInt(4.W)).Lit(0 -> 0xd.U, 1 -> 0xe.U) ) - bundle.litValue().toString(16) should be("cbaed") + bundle.litValue.toString(16) should be("cbaed") } "Vec.Lit is a trivial Vec literal factory" in { val vec = Vec.Lit(0xa.U, 0xb.U) - vec(0).litValue() should be(0xa) - vec(1).litValue() should be(0xb) + vec(0).litValue should be(0xa) + vec(1).litValue should be(0xb) } "Vec.Lit bases it's element width on the widest literal supplied" in { val vec = Vec.Lit(0xa.U, 0xbbbb.U) - vec(0).litValue() should be(0xa) - vec(1).litValue() should be(0xbbbb) + vec(0).litValue should be(0xa) + vec(1).litValue should be(0xbbbb) vec.length should be(2) vec.getWidth should be(16 * 2) - vec.litValue() should be(BigInt("bbbb000a", 16)) + vec.litValue should be(BigInt("bbbb000a", 16)) } } -- cgit v1.2.3 From c2985aa6ef95a45d6ce9663a17f835eaba0cb9c5 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Tue, 5 Oct 2021 13:20:28 -0700 Subject: Fix naming of unwrapped val io in Chisel.Modules (#2150) The removal of virtual method io accidentally made the naming of io in compatibility mode Bundles sensitive to the prefix at the time of the first access of the field. It also made .suggestName able to override the name. This commit fixes that issue by forcing the name of the io Data to be "io" no matter what.--- src/test/scala/chiselTests/CompatibilitySpec.scala | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/CompatibilitySpec.scala b/src/test/scala/chiselTests/CompatibilitySpec.scala index bf8cd3fc..ccf287a6 100644 --- a/src/test/scala/chiselTests/CompatibilitySpec.scala +++ b/src/test/scala/chiselTests/CompatibilitySpec.scala @@ -564,4 +564,32 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck verilog should include ("assign io_out_0 = io_in_0;") } + it should "ignore .suggestName on field io" in { + class MyModule extends Module { + val io = new Bundle { + val foo = UInt(width = 8).asInput + val bar = UInt(width = 8).asOutput + } + io.suggestName("potato") + io.bar := io.foo + } + val verilog = ChiselStage.emitVerilog(new MyModule) + verilog should include ("input [7:0] io_foo") + verilog should include ("output [7:0] io_bar") + } + + it should "properly name field io" in { + class MyModule extends Module { + val io = new Bundle { + val foo = UInt(width = 8).asInput + val bar = UInt(width = 8).asOutput + } + val wire = Wire(init = io.foo) + io.bar := wire + } + val verilog = ChiselStage.emitVerilog(new MyModule) + verilog should include ("input [7:0] io_foo") + verilog should include ("output [7:0] io_bar") + } + } -- cgit v1.2.3 From bdba21b032e592b21d117a8d68f166ba3834c205 Mon Sep 17 00:00:00 2001 From: Kamyar Mohajerani Date: Tue, 5 Oct 2021 18:12:57 -0400 Subject: Circular-shift (rotate) operations for UInt (#1140) * change static shift behavior to mod width when width is known * add dynamic shift * basic tests that actually do something * MatchedRotateLeftAndRight based on the idea from @chick * BasicRotate rotate "b001" and compare with known values * Fix check for KnownWidth(0|1) as suggested by @aswaterman * Add dontTouch to UIntOps.io (other tests were also optimized out) Co-authored-by: Chick Markley Co-authored-by: Andrew Waterman --- src/test/scala/chiselTests/UIntOps.scala | 84 ++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala index 62d00de2..bc6454b8 100644 --- a/src/test/scala/chiselTests/UIntOps.scala +++ b/src/test/scala/chiselTests/UIntOps.scala @@ -6,6 +6,7 @@ import chisel3._ import org.scalatest._ import chisel3.stage.ChiselStage import chisel3.testers.BasicTester +import chisel3.util._ import org.scalacheck.Shrink import org.scalatest.matchers.should.Matchers @@ -22,6 +23,8 @@ class UIntOps extends Module { val modout = Output(UInt(32.W)) val lshiftout = Output(UInt(32.W)) val rshiftout = Output(UInt(32.W)) + val lrotateout = Output(UInt(32.W)) + val rrotateout = Output(UInt(32.W)) val lessout = Output(Bool()) val greatout = Output(Bool()) val eqout = Output(Bool()) @@ -30,6 +33,8 @@ class UIntOps extends Module { val greateqout = Output(Bool()) }) + dontTouch(io) + val a = io.a val b = io.b @@ -42,6 +47,8 @@ class UIntOps extends Module { io.modout := a % b io.lshiftout := (a << b(3, 0))(31, 0) io.rshiftout := a >> b + io.lrotateout := a.rotateLeft(5) + io.rrotateout := a.rotateRight(5) io.lessout := a < b io.greatout := a > b io.eqout := a === b @@ -67,6 +74,14 @@ class UIntOpsTester(a: Long, b: Long) extends BasicTester { assert(dut.io.modout === (a % (b max 1)).U(32.W)) assert(dut.io.lshiftout === (a << (b % 16)).U(32.W)) assert(dut.io.rshiftout === (a >> b).U(32.W)) + assert( + dut.io.lrotateout === s"h${Integer.rotateLeft(a.toInt, 5).toHexString}" + .U(32.W) + ) + assert( + dut.io.rrotateout === s"h${Integer.rotateRight(a.toInt, 5).toHexString}" + .U(32.W) + ) assert(dut.io.lessout === (a < b).B) assert(dut.io.greatout === (a > b).B) assert(dut.io.eqout === (a == b).B) @@ -98,6 +113,65 @@ class NegativeShift(t: => Bits) extends Module { Reg(t) >> -1 } +class BasicRotate extends BasicTester { + val shiftAmount = random.LFSR(4) + val ctr = RegInit(0.U(4.W)) + + + val rotL = 1.U(3.W).rotateLeft(shiftAmount) + val rotR = 1.U(3.W).rotateRight(shiftAmount) + + printf("Shift amount: %d rotateLeft:%b rotateRight:%b\n", shiftAmount, rotL, rotR) + + switch(shiftAmount % 3.U) { + is(0.U, 3.U) { + assert(rotL === "b001".U) + assert(rotR === "b001".U) + } + is(1.U) { + assert(rotL === "b010".U) + assert(rotR === "b100".U) + } + is(2.U) { + assert(rotL === "b100".U) + assert(rotR === "b010".U) + } + } + + ctr := ctr + 1.U + + when (ctr === 15.U){ + stop() + } +} + +/** rotating a w-bit word left by n should be equivalent to rotating it by w - n + * to the left + */ +class MatchedRotateLeftAndRight(w: Int = 13) extends BasicTester { + val initValue = BigInt(w, scala.util.Random) + println(s"Initial value: ${initValue.toString(2)}") + + val maxWidthBits = log2Ceil(w + 1) + val shiftAmount1 = RegInit(0.U(w.W)) + val shiftAmount2 = RegInit(w.U(w.W)) + shiftAmount1 := shiftAmount1 + 1.U + shiftAmount2 := shiftAmount2 - 1.U + + val value = RegInit(initValue.U(w.W)) + + val out1 = value.rotateLeft(shiftAmount1) + val out2 = value.rotateRight(shiftAmount2) + + printf("rotateLeft by %d: %b\n", shiftAmount1, out1) + + assert(out1 === out2) + when(shiftAmount1 === w.U) { + assert(out1 === initValue.U) + stop() + } +} + class UIntLitExtractTester extends BasicTester { assert("b101010".U(2) === false.B) assert("b101010".U(3) === true.B) @@ -140,6 +214,16 @@ class UIntOpsSpec extends ChiselPropSpec with Matchers with Utils { } } + property("rotateLeft and rotateRight should work for dynamic shift values") { + assertTesterPasses(new BasicRotate) + } + + property( + "rotateLeft and rotateRight should be consistent for dynamic shift values" + ) { + assertTesterPasses(new MatchedRotateLeftAndRight) + } + property("Bit extraction on literals should work for all non-negative indices") { assertTesterPasses(new UIntLitExtractTester) } -- cgit v1.2.3 From baaa2adcbfcf4fb508d8e5e71345afd1d7e5a352 Mon Sep 17 00:00:00 2001 From: Chick Markley Date: Thu, 7 Oct 2021 14:31:16 -0700 Subject: Fixed bug with unary minus on FixedPoint and Interval (#2154) In `Bits.scala`, `FixedPoint` and `Interval` did not defeine the `do_unary_-` methods (the `do_`) was missing The recent PR #2124 combined with the above fact made DspTools break. This fix is necessary to get that repo to build.--- src/test/scala/chiselTests/FixedPointSpec.scala | 3 +++ src/test/scala/chiselTests/IntervalSpec.scala | 7 +++++++ 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/FixedPointSpec.scala b/src/test/scala/chiselTests/FixedPointSpec.scala index a1acdb17..2530bb13 100644 --- a/src/test/scala/chiselTests/FixedPointSpec.scala +++ b/src/test/scala/chiselTests/FixedPointSpec.scala @@ -60,6 +60,9 @@ class FixedPointFromBitsTester extends BasicTester { val negativefp = (-3.5).F(4.BP) val positivefp = 3.5.F(4.BP) + assert(- positivefp === negativefp) + assert(positivefp === -negativefp) + assert(uint2fp === uint_result) assert(sint2fp === sint_result) assert(fp2fp === fp_result) diff --git a/src/test/scala/chiselTests/IntervalSpec.scala b/src/test/scala/chiselTests/IntervalSpec.scala index abc619e5..a33cedc1 100644 --- a/src/test/scala/chiselTests/IntervalSpec.scala +++ b/src/test/scala/chiselTests/IntervalSpec.scala @@ -406,6 +406,13 @@ class IntervalChainedSubTester extends BasicTester { assert(intervalResult1 === 5.I) assert(intervalResult2 === 5.I) + val negativeInterval = (-3.5).I(4.BP) + val positiveInterval = 3.5.I(4.BP) + + assert(negativeInterval =/= positiveInterval) + assert(-negativeInterval === positiveInterval) + assert(negativeInterval === -positiveInterval) + stop() } -- cgit v1.2.3 From 7930544e9c8047f27285420204d25f78c753ea57 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 8 Oct 2021 09:07:04 -0700 Subject: Add nullary .fire to Valid and deprecate dummy version (#2156) Also replace all uses of .fire() with .fire--- src/main/scala/chisel3/util/Arbiter.scala | 4 ++-- src/main/scala/chisel3/util/Valid.scala | 3 +++ src/main/scala/chisel3/util/random/PRNG.scala | 2 +- src/test/scala/chiselTests/QueueFlushSpec.scala | 20 ++++++++--------- src/test/scala/chiselTests/QueueSpec.scala | 30 ++++++++++++------------- 5 files changed, 31 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala index 059bdd14..135700fa 100644 --- a/src/main/scala/chisel3/util/Arbiter.scala +++ b/src/main/scala/chisel3/util/Arbiter.scala @@ -47,7 +47,7 @@ abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLo val locked = lockCount.value =/= 0.U val wantsLock = needsLock.map(_(io.out.bits)).getOrElse(true.B) - when (io.out.fire() && wantsLock) { + when (io.out.fire && wantsLock) { lockIdx := io.chosen lockCount.inc() } @@ -63,7 +63,7 @@ abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLo class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends LockingArbiterLike[T](gen, n, count, needsLock) { - lazy val lastGrant = RegEnable(io.chosen, io.out.fire()) + lazy val lastGrant = RegEnable(io.chosen, io.out.fire) lazy val grantMask = (0 until n).map(_.asUInt > lastGrant) lazy val validMask = io.in zip grantMask map { case (in, g) => in.valid && g } diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala index 838d43ca..4d348014 100644 --- a/src/main/scala/chisel3/util/Valid.scala +++ b/src/main/scala/chisel3/util/Valid.scala @@ -28,6 +28,9 @@ class Valid[+T <: Data](gen: T) extends Bundle { /** True when `valid` is asserted * @return a Chisel [[Bool]] true if `valid` is asserted */ + def fire: Bool = valid + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") def fire(dummy: Int = 0): Bool = valid } diff --git a/src/main/scala/chisel3/util/random/PRNG.scala b/src/main/scala/chisel3/util/random/PRNG.scala index d94b78e8..9b42acf1 100644 --- a/src/main/scala/chisel3/util/random/PRNG.scala +++ b/src/main/scala/chisel3/util/random/PRNG.scala @@ -62,7 +62,7 @@ abstract class PRNG(val width: Int, val seed: Option[BigInt], step: Int = 1, upd state := nextState(state) } - when (io.seed.fire()) { + when (io.seed.fire) { state := (if (updateSeed) { nextState(io.seed.bits) } else { io.seed.bits }) } diff --git a/src/test/scala/chiselTests/QueueFlushSpec.scala b/src/test/scala/chiselTests/QueueFlushSpec.scala index 11a411a8..9e0c6bb4 100644 --- a/src/test/scala/chiselTests/QueueFlushSpec.scala +++ b/src/test/scala/chiselTests/QueueFlushSpec.scala @@ -40,11 +40,11 @@ abstract class FlushQueueTesterBase(elements: Seq[Int], queueDepth: Int, bitWidt q.io.deq.ready := LFSR(16)(tap) q.io.enq.bits := elems(inCnt.value) - when(q.io.enq.fire()) { + when(q.io.enq.fire) { inCnt.inc() currQCnt := currQCnt + 1.U //counts how many items have been enqueued } - when(q.io.deq.fire()) { + when(q.io.deq.fire) { assert(flushRegister === false.B) //check queue isn't flushed (can't dequeue an empty queue) } when(flushRegister) { //Internal signal maybe_full is a register so some signals update on the next cycle @@ -70,18 +70,18 @@ class QueueGetsFlushedTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, flush := LFSR(16)((tap + 3) % 16) //testing a flush when flush is called randomly val halfCnt = (queueDepth + 1)/2 - when(q.io.deq.fire()) { + when(q.io.deq.fire) { //ensure that what comes out is what comes in assert(currQCnt <= queueDepth.U) assert(elems(outCnt) === q.io.deq.bits) outCnt := outCnt + 1.U when (currQCnt > 0.U) { - currQCnt := Mux(q.io.enq.fire(), currQCnt, (currQCnt - 1.U)) + currQCnt := Mux(q.io.enq.fire, currQCnt, (currQCnt - 1.U)) } } when(flush) { assert(currQCnt === 0.U || q.io.deq.valid) - outCnt := outCnt + Mux(q.io.enq.fire(), (currQCnt + 1.U), currQCnt) + outCnt := outCnt + Mux(q.io.enq.fire, (currQCnt + 1.U), currQCnt) currQCnt := 0.U //resets the number of items currently inside queue } } @@ -102,7 +102,7 @@ class EmptyFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWidth: I flush := (cycleCounter.value === 0.U && inCnt.value === 0.U) //flushed only before anything is enqueued q.io.enq.valid := (inCnt.value < elements.length.U) && !flush - when(q.io.deq.fire()) { + when(q.io.deq.fire) { assert(elems(outCnt) === q.io.deq.bits) outCnt := outCnt + 1.U } @@ -124,7 +124,7 @@ class EnqueueEmptyFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitW flush := (cycleCounter.value === 0.U && inCnt.value === 0.U) //flushed only before anything is enqueued cycleCounter.inc() //counts every cycle - when(q.io.deq.fire()) { + when(q.io.deq.fire) { //flush and enqueue were both active on the first cycle, //so that element is flushed immediately which makes outCnt off by one assert(elems(outCounter.value + 1.U) === q.io.deq.bits) //ensure that what comes out is what comes in @@ -145,7 +145,7 @@ class FullQueueFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWidt //testing a flush when queue is full flush := (currQCnt === queueDepth.U) - when(q.io.deq.fire()) { + when(q.io.deq.fire) { //ensure that what comes out is what comes in assert(currQCnt <= queueDepth.U) assert(elems(outCnt) === q.io.deq.bits) @@ -177,7 +177,7 @@ class DequeueFullQueueEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWi q.io.enq.valid := !flushRegister q.io.deq.ready := flush - when(q.io.deq.fire()) { + when(q.io.deq.fire) { //ensure that what comes out is what comes in assert(currQCnt <= queueDepth.U) assert(elems(outCnt) === q.io.deq.bits) @@ -191,7 +191,7 @@ class DequeueFullQueueEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWi } when(flushRegister) { //check that queue gets flushed when queue is full - assert(q.io.deq.fire() === false.B) + assert(q.io.deq.fire === false.B) } } diff --git a/src/test/scala/chiselTests/QueueSpec.scala b/src/test/scala/chiselTests/QueueSpec.scala index 51b899cb..9eb6c20c 100644 --- a/src/test/scala/chiselTests/QueueSpec.scala +++ b/src/test/scala/chiselTests/QueueSpec.scala @@ -21,10 +21,10 @@ class ThingsPassThroughTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int q.io.deq.ready := LFSR(16)(tap) q.io.flush.foreach { _ := false.B } //Flush behavior is tested in QueueFlushSpec q.io.enq.bits := elems(inCnt.value) - when(q.io.enq.fire()) { + when(q.io.enq.fire) { inCnt.inc() } - when(q.io.deq.fire()) { + when(q.io.deq.fire) { //ensure that what comes out is what comes in assert(elems(outCnt.value) === q.io.deq.bits) outCnt.inc() @@ -51,10 +51,10 @@ class QueueReasonableReadyValid(elements: Seq[Int], queueDepth: Int, bitWidth: I assert(q.io.deq.valid || q.io.count === 0.U) q.io.enq.bits := elems(inCnt.value) - when(q.io.enq.fire()) { + when(q.io.enq.fire) { inCnt.inc() } - when(q.io.deq.fire()) { + when(q.io.deq.fire) { outCnt.inc() } when(outCnt.value === elements.length.U) { @@ -74,11 +74,11 @@ class CountIsCorrectTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, t q.io.deq.ready := LFSR(16)(tap) q.io.enq.bits := elems(inCnt.value) - when(q.io.enq.fire()) { + when(q.io.enq.fire) { inCnt.inc() assert(q.io.count === (inCnt.value - outCnt.value)) } - when(q.io.deq.fire()) { + when(q.io.deq.fire) { outCnt.inc() assert(q.io.count === (inCnt.value - outCnt.value)) } @@ -103,10 +103,10 @@ class QueueSinglePipeTester(elements: Seq[Int], bitWidth: Int, tap: Int, useSync assert(q.io.enq.ready || (q.io.count === 1.U && !q.io.deq.ready)) q.io.enq.bits := elems(inCnt.value) - when(q.io.enq.fire()) { + when(q.io.enq.fire) { inCnt.inc() } - when(q.io.deq.fire()) { + when(q.io.deq.fire) { outCnt.inc() } @@ -129,10 +129,10 @@ class QueuePipeTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: I assert(q.io.enq.ready || (q.io.count === queueDepth.U && !q.io.deq.ready)) q.io.enq.bits := elems(inCnt.value) - when(q.io.enq.fire()) { + when(q.io.enq.fire) { inCnt.inc() } - when(q.io.deq.fire()) { + when(q.io.deq.fire) { outCnt.inc() } @@ -155,13 +155,13 @@ class QueueFlowTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: I q.io.deq.ready := LFSR(16)(tap) //Queue should be empty or valid - assert(q.io.deq.valid || (q.io.count === 0.U && !q.io.enq.fire())) + assert(q.io.deq.valid || (q.io.count === 0.U && !q.io.enq.fire)) q.io.enq.bits := elems(inCnt.value) - when(q.io.enq.fire()) { + when(q.io.enq.fire) { inCnt.inc() } - when(q.io.deq.fire()) { + when(q.io.deq.fire) { outCnt.inc() } when(outCnt.value === elements.length.U) { @@ -183,10 +183,10 @@ class QueueFactoryTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap deq.ready := LFSR(16)(tap) enq.bits := elems(inCnt.value) - when(enq.fire()) { + when(enq.fire) { inCnt.inc() } - when(deq.fire()) { + when(deq.fire) { //ensure that what comes out is what comes in assert(elems(outCnt.value) === deq.bits) outCnt.inc() -- cgit v1.2.3 From ffa0831c736c7d5296964bc65536ac256220dcaa Mon Sep 17 00:00:00 2001 From: Nic McDonald Date: Tue, 12 Oct 2021 15:25:55 -0600 Subject: Fix GaloisLFSR comments (#2178) --- src/main/scala/chisel3/util/random/GaloisLFSR.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/random/GaloisLFSR.scala b/src/main/scala/chisel3/util/random/GaloisLFSR.scala index 0d407c87..68346e82 100644 --- a/src/main/scala/chisel3/util/random/GaloisLFSR.scala +++ b/src/main/scala/chisel3/util/random/GaloisLFSR.scala @@ -13,7 +13,7 @@ import chisel3._ * * $seedExplanation * - * In the example below, a 4-bit LFSR Fibonacci LFSR is constructed. The tap points are defined as four and three + * In the example below, a 4-bit LFSR Galois LFSR is constructed. The tap points are defined as four and three * (using LFSR convention of indexing from one). This results in the hardware configuration shown in the diagram. * * {{{ @@ -85,7 +85,7 @@ class MaxPeriodGaloisLFSR(width: Int, seed: Option[BigInt] = Some(1), reduction: */ object GaloisLFSR { - /** Return a pseudorandom [[UInt]] generated from a [[FibonacciLFSR]]. + /** Return a pseudorandom [[UInt]] generated from a [[GaloisLFSR]]. * $paramWidth * $paramTaps * $paramIncrement -- cgit v1.2.3 From 8ed9940ed943d0b7f4248d26c598a95c62340f26 Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Wed, 13 Oct 2021 12:01:52 -0700 Subject: Support @public on unimplemented vals (#2182) --- .../chiselTests/experimental/hierarchy/DefinitionSpec.scala | 11 +++++++++++ .../scala/chiselTests/experimental/hierarchy/Examples.scala | 9 +++++++++ 2 files changed, 20 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala index 19261c36..4eb77c8a 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala @@ -258,6 +258,17 @@ class DefinitionSpec extends ChiselFunSpec with Utils { val (_, annos) = getFirrtlAndAnnos(new Top) annos should contain(MarkAnnotation("~Top|HasPublicConstructorArgs>x".rt, "10")) } + it("3.10: should work on unimplemented vals in abstract classes/traits") { + class Top() extends Module { + val i = Definition(new ConcreteHasBlah()) + def f(d: Definition[HasBlah]): Unit = { + mark(d, d.blah.toString) + } + f(i) + } + val (_, annos) = getFirrtlAndAnnos(new Top) + annos should contain(MarkAnnotation("~Top|ConcreteHasBlah".mt, "10")) + } } describe("4: toDefinition") { it("4.0: should work on modules") { diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala index 23b8c9c0..94c0e551 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala @@ -183,4 +183,13 @@ object Examples { @public val out = IO(Output(UInt(3.W))) out := RegNext(in) } + @instantiable + abstract class HasBlah() extends Module { + @public val blah: Int + } + + @instantiable + class ConcreteHasBlah() extends HasBlah { + val blah = 10 + } } -- cgit v1.2.3 From 2534931cbc8d5c730f766c9f16d40936ae710c22 Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Mon, 25 Oct 2021 14:20:22 -0700 Subject: Add type parameter support for @instantiable (#2206) --- src/test/scala/chiselTests/experimental/hierarchy/Examples.scala | 4 ++++ .../scala/chiselTests/experimental/hierarchy/InstanceSpec.scala | 9 +++++++++ 2 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala index 94c0e551..7c9396cf 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala @@ -192,4 +192,8 @@ object Examples { class ConcreteHasBlah() extends HasBlah { val blah = 10 } + @instantiable + class HasTypeParams[D <: Data](d: D) extends Module { + @public val blah = Wire(d) + } } diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala index 3866bf87..6c227866 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala @@ -144,6 +144,15 @@ class InstanceSpec extends ChiselFunSpec with Utils { val (_, annos) = getFirrtlAndAnnos(new Top) annos should contain (MarkAnnotation("~Top|AddOneWithAnnotation>innerWire".rt, "innerWire")) } + it("1.11: should work on things with type parameters"){ + class Top extends Module { + val definition = Definition(new HasTypeParams[UInt](UInt(3.W))) + val i0 = Instance(definition) + mark(i0.blah, "blah") + } + val (_, annos) = getFirrtlAndAnnos(new Top) + annos should contain (MarkAnnotation("~Top|Top/i0:HasTypeParams>blah".rt, "blah")) + } } describe("2: Annotations on designs not in the same chisel compilation") { it("2.0: should work on an innerWire, marked in a different compilation") { -- cgit v1.2.3 From d9722cd96159cd8957cd335d79dbb495260e590d Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Mon, 25 Oct 2021 15:12:53 -0700 Subject: Add Hierarchy trait (#2204) --- .../chiselTests/experimental/hierarchy/Annotations.scala | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala b/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala index 43111fdd..eba412f1 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala @@ -5,24 +5,20 @@ package chiselTests.experimental.hierarchy import _root_.firrtl.annotations._ import chisel3.experimental.{annotate, BaseModule} import chisel3.Data -import chisel3.experimental.hierarchy.{Instance, Definition} +import chisel3.experimental.hierarchy.{Instance, Definition, Hierarchy} object Annotations { case class MarkAnnotation(target: IsMember, tag: String) extends SingleTargetAnnotation[IsMember] { def duplicate(n: IsMember): Annotation = this.copy(target = n) } - case class MarkChiselInstanceAnnotation[B <: BaseModule](d: Instance[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation { - def toFirrtl = MarkAnnotation(d.toTarget, tag) - } - case class MarkChiselDefinitionAnnotation[B <: BaseModule](d: Definition[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation { + case class MarkChiselHierarchyAnnotation[B <: BaseModule](d: Hierarchy[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation { def toFirrtl = MarkAnnotation(d.toTarget, tag) } case class MarkChiselAnnotation(d: Data, tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation { def toFirrtl = if(isAbsolute) MarkAnnotation(d.toAbsoluteTarget, tag) else MarkAnnotation(d.toTarget, tag) } def mark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, false)) - def mark[B <: BaseModule](d: Instance[B], tag: String): Unit = annotate(MarkChiselInstanceAnnotation(d, tag, false)) - def mark[B <: BaseModule](d: Definition[B], tag: String): Unit = annotate(MarkChiselDefinitionAnnotation(d, tag, false)) + def mark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true)) def amark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, true)) - def amark[B <: BaseModule](d: Instance[B], tag: String): Unit = annotate(MarkChiselInstanceAnnotation(d, tag, true)) + def amark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true)) } -- cgit v1.2.3 From 2a68cc0636580db1a5fa98e87727bb3ec870e0bc Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Wed, 27 Oct 2021 15:51:21 -0700 Subject: Add java reflection to hierarchy (#2209) * Add Hierarchy trait * Add Hierarchy trait * Add Hierarchy scaladoc * Add license * Add isA and tests * Add back isA * Make calculate via lazy val * Apply suggestions from code review Co-authored-by: Megan Wachs * Add shouldNot compile * Update src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala Co-authored-by: Jack Koenig * Made protected vals private Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- .../experimental/hierarchy/InstanceSpec.scala | 41 ++++++++++++++++++++++ 1 file changed, 41 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 6c227866..0795e76c 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala @@ -714,5 +714,46 @@ class InstanceSpec extends ChiselFunSpec with Utils { } } } + describe("9: isA[..]") { + it("9.0: it should work on simple classes") { + class Top extends Module { + val d = Definition(new AddOne) + require(d.isA[AddOne]) + } + getFirrtlAndAnnos(new Top) + } + it("9.1: it should not work on inner classes") { + class InnerClass extends Module + class Top extends Module { + val d = Definition(new InnerClass) + "require(d.isA[Module])" should compile // ensures that the test below is checking something useful + "require(d.isA[InnerClass])" shouldNot compile + } + getFirrtlAndAnnos(new Top) + } + it("9.2: it should work on super classes") { + class InnerClass extends Module + class Top extends Module { + val d = Definition(new InnerClass) + require(d.isA[Module]) + } + getFirrtlAndAnnos(new Top) + } + it("9.2: it should work after casts") { + class Top extends Module { + val d0: Definition[Module] = Definition(new AddOne) + require(d0.isA[AddOne]) + val d1: Definition[Module] = Definition((new AddOne).asInstanceOf[Module]) + require(d1.isA[AddOne]) + val i0: Instance[Module] = Instance(d0) + require(i0.isA[AddOne]) + val i1: Instance[Module] = Instance(d1) + require(i1.isA[AddOne]) + val i2: Instance[Module] = Instance(Definition(new AddOne)) + require(i2.isA[AddOne]) + } + getFirrtlAndAnnos(new Top) + } + } } -- cgit v1.2.3 From ef8a9c2148f01e058d2986c9d64f0c35f640790c Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Wed, 27 Oct 2021 16:52:56 -0700 Subject: Add Select APIs for Hierarchy package (#2210) * Add Hierarchy trait * Add Hierarchy trait * Add Hierarchy scaladoc * Add license * Add isA and tests * Add back isA * Add new Select APIs for hierarchy package * Update scaladoc * Write outlines for tests * Add tests and fixes to new Select functions * Make calculate via lazy val * Apply suggestions from code review Co-authored-by: Megan Wachs * Apply suggestions from code review Co-authored-by: Megan Wachs * Clean up scaladoc * Add shouldNot compile * Apply suggestions from code review Co-authored-by: Megan Wachs * Bugfix all funcs should analyze root too * Add mdoc, bugfix toDefinition * Make func private, add scaladoc * Update src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala Co-authored-by: Jack Koenig * Made protected vals private * Apply suggestions from code review Co-authored-by: Jack Koenig * Address code review comments * Added additional null check Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig --- src/main/scala/chisel3/aop/Select.scala | 178 ++++++++++++++++++--- .../chisel3/aop/injecting/InjectingAspect.scala | 2 +- .../experimental/hierarchy/Examples.scala | 12 ++ .../experimental/hierarchy/InstanceSpec.scala | 96 +++++++++++ 4 files changed, 264 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/aop/Select.scala b/src/main/scala/chisel3/aop/Select.scala index 9c7320ce..8bdf4344 100644 --- a/src/main/scala/chisel3/aop/Select.scala +++ b/src/main/scala/chisel3/aop/Select.scala @@ -6,10 +6,12 @@ import chisel3._ import chisel3.internal.{HasId} import chisel3.experimental.BaseModule import chisel3.experimental.FixedPoint -import chisel3.internal.firrtl._ +import chisel3.internal.firrtl.{Definition => DefinitionIR, _} +import chisel3.experimental.hierarchy._ import chisel3.internal.PseudoModule import chisel3.internal.BaseModule.ModuleClone import firrtl.annotations.ReferenceTarget +import scala.reflect.runtime.universe.TypeTag import scala.collection.mutable import chisel3.internal.naming.chiselName @@ -22,7 +24,6 @@ object Select { /** Return just leaf components of expanded node * * @param d Component to find leafs if aggregate typed. Intermediate fields/indicies are not included - * @return */ def getLeafs(d: Data): Seq[Data] = d match { case r: Record => r.getElements.flatMap(getLeafs) @@ -33,7 +34,6 @@ object Select { /** Return all expanded components, including intermediate aggregate nodes * * @param d Component to find leafs if aggregate typed. Intermediate fields/indicies ARE included - * @return */ def getIntermediateAndLeafs(d: Data): Seq[Data] = d match { case r: Record => r +: r.getElements.flatMap(getIntermediateAndLeafs) @@ -41,15 +41,156 @@ object Select { case other => Seq(other) } + /** Selects all instances/modules directly instantiated within given definition + * + * @param parent + */ + def instancesIn(parent: Hierarchy[BaseModule]): Seq[Instance[BaseModule]] = { + check(parent) + implicit val mg = new chisel3.internal.MacroGenerated{} + parent.proto._component.get match { + case d: DefModule => d.commands.collect { + case d: DefInstance => + d.id match { + case p: chisel3.internal.BaseModule.IsClone[_] => + parent._lookup { x => new Instance(Right(p)).asInstanceOf[Instance[BaseModule]] } + case other: BaseModule => + parent._lookup { x => other } + } + } + case other => Nil + } + } + + /** Selects all Instances of instances/modules directly instantiated within given module, of provided type + * + * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class. + * @param parent hierarchy which instantiates the returned Definitions + */ + def instancesOf[T <: BaseModule : TypeTag](parent: Hierarchy[BaseModule]): Seq[Instance[T]] = { + check(parent) + implicit val mg = new chisel3.internal.MacroGenerated{} + parent.proto._component.get match { + case d: DefModule => d.commands.flatMap { + case d: DefInstance => + d.id match { + case p: chisel3.internal.BaseModule.IsClone[_] => + val i = parent._lookup { x => new Instance(Right(p)).asInstanceOf[Instance[BaseModule]] } + if(i.isA[T]) Some(i.asInstanceOf[Instance[T]]) else None + case other: BaseModule => + val i = parent._lookup { x => other } + if(i.isA[T]) Some(i.asInstanceOf[Instance[T]]) else None + } + case other => None + } + case other => Nil + } + } + + /** Selects all Instances directly and indirectly instantiated within given root hierarchy, of provided type + * + * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class. + * @param root top of the hierarchy to search for instances/modules of given type + */ + def allInstancesOf[T <: BaseModule : TypeTag](root: Hierarchy[BaseModule]): Seq[Instance[T]] = { + val soFar = if(root.isA[T]) Seq(root.toInstance.asInstanceOf[Instance[T]]) else Nil + val allLocalInstances = instancesIn(root) + soFar ++ (allLocalInstances.flatMap(allInstancesOf[T])) + } + + /** Selects the Definitions of all instances/modules directly instantiated within given module + * + * @param parent + */ + def definitionsIn(parent: Hierarchy[BaseModule]): Seq[Definition[BaseModule]] = { + type DefType = Definition[BaseModule] + implicit val mg = new chisel3.internal.MacroGenerated{} + check(parent) + val defs = parent.proto._component.get match { + case d: DefModule => d.commands.collect { + case i: DefInstance => + i.id match { + case p: chisel3.internal.BaseModule.IsClone[_] => + parent._lookup { x => new Definition(Left(p.getProto)).asInstanceOf[Definition[BaseModule]] } + case other: BaseModule => + parent._lookup { x => other.toDefinition } + } + } + case other => Nil + } + val (_, defList) = defs.foldLeft((Set.empty[DefType], List.empty[DefType])) { case ((set, list), definition: Definition[BaseModule]) => + if(set.contains(definition)) (set, list) else (set + definition, definition +: list) + } + defList.reverse + } + + + /** Selects all Definitions of instances/modules directly instantiated within given module, of provided type + * + * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class. + * @param parent hierarchy which instantiates the returned Definitions + */ + def definitionsOf[T <: BaseModule : TypeTag](parent: Hierarchy[BaseModule]): Seq[Definition[T]] = { + check(parent) + implicit val mg = new chisel3.internal.MacroGenerated{} + type DefType = Definition[T] + val defs = parent.proto._component.get match { + case d: DefModule => d.commands.flatMap { + case d: DefInstance => + d.id match { + case p: chisel3.internal.BaseModule.IsClone[_] => + val d = parent._lookup { x => new Definition(Right(p)).asInstanceOf[Definition[BaseModule]] } + if(d.isA[T]) Some(d.asInstanceOf[Definition[T]]) else None + case other: BaseModule => + val d = parent._lookup { x => other.toDefinition } + if(d.isA[T]) Some(d.asInstanceOf[Definition[T]]) else None + } + case other => None + } + } + val (_, defList) = defs.foldLeft((Set.empty[DefType], List.empty[DefType])) { case ((set, list), definition: Definition[T]) => + if(set.contains(definition)) (set, list) else (set + definition, definition +: list) + } + defList.reverse + } + + /** Selects all Definition's directly and indirectly instantiated within given root hierarchy, of provided type + * + * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class, i.e. + * a class defined within another class. + * @param root top of the hierarchy to search for definitions of given type + */ + def allDefinitionsOf[T <: BaseModule : TypeTag](root: Hierarchy[BaseModule]): Seq[Definition[T]] = { + type DefType = Definition[T] + val allDefSet = mutable.HashSet[Definition[BaseModule]]() + val defSet = mutable.HashSet[DefType]() + val defList = mutable.ArrayBuffer[DefType]() + def rec(hier: Definition[BaseModule]): Unit = { + if(hier.isA[T] && !defSet.contains(hier.asInstanceOf[DefType])) { + defSet += hier.asInstanceOf[DefType] + defList += hier.asInstanceOf[DefType] + } + allDefSet += hier + val allDefs = definitionsIn(hier) + allDefs.collect { + case d if !allDefSet.contains(d) => rec(d) + } + } + rec(root.toDefinition) + defList.toList + } + /** Collects all components selected by collector within module and all children modules it instantiates * directly or indirectly * Accepts a collector function, rather than a collector partial function (see [[collectDeep]]) + * + * @note This API will not work with the new experimental hierarchy package. Instead, use allInstancesOf or allDefinitionsOf. + * * @param module Module to collect components, as well as all children module it directly and indirectly instantiates * @param collector Collector function to pick, given a module, which components to collect * @param tag Required for generics to work, should ignore this * @tparam T Type of the component that will be collected - * @return */ def getDeep[T](module: BaseModule)(collector: BaseModule => Seq[T]): Seq[T] = { check(module) @@ -63,11 +204,13 @@ object Select { /** Collects all components selected by collector within module and all children modules it instantiates * directly or indirectly * Accepts a collector partial function, rather than a collector function (see [[getDeep]]) + * + * @note This API will not work with the new experimental hierarchy package. Instead, use allInstancesOf or allDefinitionsOf. + * * @param module Module to collect components, as well as all children module it directly and indirectly instantiates * @param collector Collector partial function to pick, given a module, which components to collect * @param tag Required for generics to work, should ignore this * @tparam T Type of the component that will be collected - * @return */ def collectDeep[T](module: BaseModule)(collector: PartialFunction[BaseModule, T]): Iterable[T] = { check(module) @@ -78,9 +221,11 @@ object Select { myItems ++ deepChildrenItems } - /** Selects all instances directly instantiated within given module + /** Selects all modules directly instantiated within given module + * + * @note This API will not work with the new experimental hierarchy package. Instead, use instancesIn or definitionsIn. + * * @param module - * @return */ def instances(module: BaseModule): Seq[BaseModule] = { check(module) @@ -88,7 +233,7 @@ object Select { case d: DefModule => d.commands.flatMap { case i: DefInstance => i.id match { case m: ModuleClone[_] if !m._madeFromDefinition => None - case _: PseudoModule => throw new Exception("Aspect APIs are currently incompatible with Definition/Instance") + case _: PseudoModule => throw new Exception("instances, collectDeep, and getDeep are currently incompatible with Definition/Instance!") case other => Some(other) } case _ => None @@ -99,7 +244,6 @@ object Select { /** Selects all registers directly instantiated within given module * @param module - * @return */ def registers(module: BaseModule): Seq[Data] = { check(module) @@ -111,7 +255,6 @@ object Select { /** Selects all ios directly contained within given module * @param module - * @return */ def ios(module: BaseModule): Seq[Data] = { check(module) @@ -120,7 +263,6 @@ object Select { /** Selects all SyncReadMems directly contained within given module * @param module - * @return */ def syncReadMems(module: BaseModule): Seq[SyncReadMem[_]] = { check(module) @@ -131,7 +273,6 @@ object Select { /** Selects all Mems directly contained within given module * @param module - * @return */ def mems(module: BaseModule): Seq[Mem[_]] = { check(module) @@ -142,7 +283,6 @@ object Select { /** Selects all arithmetic or logical operators directly instantiated within given module * @param module - * @return */ def ops(module: BaseModule): Seq[(String, Data)] = { check(module) @@ -155,7 +295,6 @@ object Select { * The kind of operators are contained in [[chisel3.internal.firrtl.PrimOp]] * @param opKind the kind of operator, e.g. "mux", "add", or "bits" * @param module - * @return */ def ops(opKind: String)(module: BaseModule): Seq[Data] = { check(module) @@ -166,7 +305,6 @@ object Select { /** Selects all wires in a module * @param module - * @return */ def wires(module: BaseModule): Seq[Data] = { check(module) @@ -177,7 +315,6 @@ object Select { /** Selects all memory ports, including their direction and memory * @param module - * @return */ def memPorts(module: BaseModule): Seq[(Data, MemPortDirection, MemBase[_])] = { check(module) @@ -189,7 +326,6 @@ object Select { /** Selects all memory ports of a given direction, including their memory * @param dir The direction of memory ports to select * @param module - * @return */ def memPorts(dir: MemPortDirection)(module: BaseModule): Seq[(Data, MemBase[_])] = { check(module) @@ -200,7 +336,6 @@ object Select { /** Selects all components who have been set to be invalid, even if they are later connected to * @param module - * @return */ def invalids(module: BaseModule): Seq[Data] = { check(module) @@ -211,7 +346,6 @@ object Select { /** Selects all components who are attached to a given signal, within a module * @param module - * @return */ def attachedTo(module: BaseModule)(signal: Data): Set[Data] = { check(module) @@ -226,7 +360,6 @@ object Select { * E.g. if signal = io.foo.bar, connectionsTo will return all connections to io, io.foo, and io.bar * @param module * @param signal - * @return */ def connectionsTo(module: BaseModule)(signal: Data): Seq[PredicatedConnect] = { check(module) @@ -237,7 +370,7 @@ object Select { var seenDef = isPort searchWhens(module, (cmd: Command, preds) => { cmd match { - case cmd: Definition if cmd.id.isInstanceOf[Data] => + case cmd: DefinitionIR if cmd.id.isInstanceOf[Data] => val x = getIntermediateAndLeafs(cmd.id.asInstanceOf[Data]) if(x.contains(signal)) prePredicates = preds case Connect(_, loc@Node(d: Data), exp) => @@ -263,7 +396,6 @@ object Select { /** Selects all stop statements, and includes the predicates surrounding the stop statement * * @param module - * @return */ def stops(module: BaseModule): Seq[Stop] = { val stops = mutable.ArrayBuffer[Stop]() @@ -279,7 +411,6 @@ object Select { /** Selects all printf statements, and includes the predicates surrounding the printf statement * * @param module - * @return */ def printfs(module: BaseModule): Seq[Printf] = { val printfs = mutable.ArrayBuffer[Printf]() @@ -297,6 +428,7 @@ object Select { require(module.isClosed, "Can't use Selector on modules that have not finished construction!") require(module._component.isDefined, "Can't use Selector on modules that don't have components!") } + private def check(hierarchy: Hierarchy[BaseModule]): Unit = check(hierarchy.proto) // Given a loc, return all subcomponents of id that could be assigned to in connect private def getEffected(a: Arg): Seq[Data] = a match { diff --git a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala index 1a476f61..dc7e6487 100644 --- a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala +++ b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala @@ -43,7 +43,7 @@ abstract class InjectorAspect[T <: RawModule, M <: RawModule]( injection: M => Unit ) extends Aspect[T] { final def toAnnotation(top: T): AnnotationSeq = { - val moduleNames = Select.collectDeep(top) { case i => i.name }.toSeq + val moduleNames = Select.allDefinitionsOf[chisel3.experimental.BaseModule](top.toDefinition).map{i => i.toTarget.module }.toSeq toAnnotation(selectRoots(top), top.name, moduleNames) } diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala index 7c9396cf..d8ae7322 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala @@ -57,6 +57,18 @@ object Examples { i1.in := i0.out out := i1.out } + + @instantiable + class AddFour extends Module { + @public val in = IO(Input(UInt(32.W))) + @public val out = IO(Output(UInt(32.W))) + @public val definition = Definition(new AddTwoMixedModules) + @public val i0 = Instance(definition) + @public val i1 = Instance(definition) + i0.in := in + i1.in := i0.out + out := i1.out + } @instantiable class AggregatePortModule extends Module { @public val io = IO(new Bundle { diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala index 0795e76c..83084468 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala @@ -755,5 +755,101 @@ class InstanceSpec extends ChiselFunSpec with Utils { getFirrtlAndAnnos(new Top) } } + describe("10: Select APIs") { + it("10.0: instancesOf") { + val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules => + val targets = aop.Select.instancesOf[AddOne](m.toDefinition).map { i: Instance[AddOne] => i.toTarget } + targets should be (Seq( + "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it, + "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_2".it, + )) + }) + getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect)) + } + it("10.1: instancesIn") { + val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules => + val insts = aop.Select.instancesIn(m.toDefinition) + val abs = insts.map { i: Instance[BaseModule] => i.toAbsoluteTarget } + val rel = insts.map { i: Instance[BaseModule] => i.toTarget } + abs should be (Seq( + "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it, + "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_2".it, + )) + rel should be (Seq( + "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it, + "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_2".it, + )) + }) + getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect)) + } + it("10.2: allInstancesOf") { + val aspect = aop.inspecting.InspectingAspect({ m: AddFour => + val insts = aop.Select.allInstancesOf[AddOne](m.toDefinition) + val abs = insts.map { i: Instance[AddOne] => i.in.toAbsoluteTarget } + val rel = insts.map { i: Instance[AddOne] => i.in.toTarget } + rel should be (Seq( + "~AddFour|AddFour/i0:AddTwoMixedModules/i0:AddOne>in".rt, + "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_2>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_2>in".rt, + )) + abs should be (Seq( + "~AddFour|AddFour/i0:AddTwoMixedModules/i0:AddOne>in".rt, + "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_2>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_2>in".rt, + )) + }) + getFirrtlAndAnnos(new AddFour, Seq(aspect)) + } + it("10.3: definitionsOf") { + val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules => + val targets = aop.Select.definitionsOf[AddOne](m.toDefinition).map { i: Definition[AddOne] => i.in.toTarget } + targets should be (Seq( + "~AddTwoMixedModules|AddOne>in".rt, + "~AddTwoMixedModules|AddOne_2>in".rt, + )) + }) + getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect)) + } + it("10.4: definitionsIn") { + val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules => + val targets = aop.Select.definitionsIn(m.toDefinition).map { i: Definition[BaseModule] => i.toTarget } + targets should be (Seq( + "~AddTwoMixedModules|AddOne".mt, + "~AddTwoMixedModules|AddOne_2".mt, + )) + }) + getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect)) + } + it("10.5: allDefinitionsOf") { + val aspect = aop.inspecting.InspectingAspect({ m: AddFour => + val targets = aop.Select.allDefinitionsOf[AddOne](m.toDefinition).map { i: Definition[AddOne] => i.in.toTarget } + targets should be (Seq( + "~AddFour|AddOne>in".rt, + "~AddFour|AddOne_2>in".rt, + )) + }) + getFirrtlAndAnnos(new AddFour, Seq(aspect)) + } + it("10.6: Select.collectDeep should fail when combined with hierarchy package") { + val aspect = aop.inspecting.InspectingAspect({ m: AddFour => + aop.Select.collectDeep(m) { case m: AddOne => m.toTarget } + }) + intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) } + } + it("10.7: Select.getDeep should fail when combined with hierarchy package") { + val aspect = aop.inspecting.InspectingAspect({ m: AddFour => + aop.Select.getDeep(m) { m: BaseModule => Nil } + }) + intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) } + } + it("10.8: Select.instances should fail when combined with hierarchy package") { + val aspect = aop.inspecting.InspectingAspect({ m: AddFour => + aop.Select.instances(m) + }) + intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) } + } + } } -- cgit v1.2.3 From 0c43dadf60c1485be348115c20690990f0fea940 Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Thu, 28 Oct 2021 18:18:34 -0700 Subject: Exposing more APIs from D/I internals (#2220) Exposing more internals of D/I, which are required for supporting D/I with more powerful Chisel libraries: - Exposing IsClone[_] - Exposing InstantiableClone[_] - Gated builders for Instance/Definition - Unsealing Lookupable, with protected accessors for proto and cloned--- src/main/scala/chisel3/aop/Select.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/aop/Select.scala b/src/main/scala/chisel3/aop/Select.scala index 8bdf4344..8f5a2577 100644 --- a/src/main/scala/chisel3/aop/Select.scala +++ b/src/main/scala/chisel3/aop/Select.scala @@ -53,7 +53,7 @@ object Select { case d: DefInstance => d.id match { case p: chisel3.internal.BaseModule.IsClone[_] => - parent._lookup { x => new Instance(Right(p)).asInstanceOf[Instance[BaseModule]] } + parent._lookup { x => new Instance(Clone(p)).asInstanceOf[Instance[BaseModule]] } case other: BaseModule => parent._lookup { x => other } } @@ -75,7 +75,7 @@ object Select { case d: DefInstance => d.id match { case p: chisel3.internal.BaseModule.IsClone[_] => - val i = parent._lookup { x => new Instance(Right(p)).asInstanceOf[Instance[BaseModule]] } + val i = parent._lookup { x => new Instance(Clone(p)).asInstanceOf[Instance[BaseModule]] } if(i.isA[T]) Some(i.asInstanceOf[Instance[T]]) else None case other: BaseModule => val i = parent._lookup { x => other } @@ -111,7 +111,7 @@ object Select { case i: DefInstance => i.id match { case p: chisel3.internal.BaseModule.IsClone[_] => - parent._lookup { x => new Definition(Left(p.getProto)).asInstanceOf[Definition[BaseModule]] } + parent._lookup { x => new Definition(Proto(p.getProto)).asInstanceOf[Definition[BaseModule]] } case other: BaseModule => parent._lookup { x => other.toDefinition } } @@ -139,7 +139,7 @@ object Select { case d: DefInstance => d.id match { case p: chisel3.internal.BaseModule.IsClone[_] => - val d = parent._lookup { x => new Definition(Right(p)).asInstanceOf[Definition[BaseModule]] } + val d = parent._lookup { x => new Definition(Clone(p)).asInstanceOf[Definition[BaseModule]] } if(d.isA[T]) Some(d.asInstanceOf[Definition[T]]) else None case other: BaseModule => val d = parent._lookup { x => other.toDefinition } -- cgit v1.2.3 From a79f57565e7157d137628d1aaeae750f98e3d88b Mon Sep 17 00:00:00 2001 From: Abongwa Bonalais Date: Wed, 3 Nov 2021 05:56:37 +0100 Subject: Add field grouping ScalaDoc for other subclasses of Bundle (#2214) * Add field grouping scaladocs for DecoupledIo * Added groupdesc to DecoupledIO * Added groupings for IrrevocableIO * Add groupings for ValidIO * Add field grouping scaladoc for PRNGIO * Add field grouping scaladoc for QueueIO * Added groupings for PipeIO * Update src/main/scala/chisel3/util/Decoupled.scala Commited Sugestion Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Decoupled.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Decoupled.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Decoupled.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Decoupled.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Valid.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Valid.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Valid.scala Co-authored-by: Megan Wachs Co-authored-by: Megan Wachs --- src/main/scala/chisel3/util/Decoupled.scala | 30 +++++++++++++++++++++++---- src/main/scala/chisel3/util/Valid.scala | 18 ++++++++++++---- src/main/scala/chisel3/util/random/PRNG.scala | 13 +++++++++--- 3 files changed, 50 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 060a684c..2a098f4d 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -16,6 +16,7 @@ import chisel3.internal.naming._ // can't use chisel3_ version because of compi * while the consumer uses the flipped interface (inputs bits). * The actual semantics of ready/valid are enforced via the use of concrete subclasses. * @param gen the type of data to be wrapped in Ready/Valid + * @groupdesc Signals The actual hardware fields of the Bundle */ abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle { @@ -26,8 +27,19 @@ abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle case _ => gen } +/** Indicates that the consumer is ready to accept the data this cycle + * @group Signals + */ val ready = Input(Bool()) + +/** Indicates that the producer has put valid data in 'bits' + * @group Signals + */ val valid = Output(Bool()) + +/** The data to be transferred when ready and valid are asserted at the same cycle + * @group Signals + */ val bits = Output(genType) } @@ -121,6 +133,7 @@ object Decoupled * Additionally, once 'valid' is raised it will never be lowered until after * 'ready' has also been raised. * @param gen the type of data to be wrapped in IrrevocableIO + * @groupdesc Signals The actual hardware fields of the Bundle */ class IrrevocableIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen) @@ -161,6 +174,7 @@ object DeqIO { * @param gen The type of data to queue * @param entries The max number of entries in the queue. * @param hasFlush A boolean for whether the generated Queue is flushable + * @groupdesc Signals The hardware fields of the Bundle */ class QueueIO[T <: Data](private val gen: T, val entries: Int, val hasFlush: Boolean = false) extends Bundle { // See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs. @@ -169,13 +183,21 @@ class QueueIO[T <: Data](private val gen: T, val entries: Int, val hasFlush: Boo * but internally, the queue implementation itself sits on the other side * of the interface so uses the flipped instance. */ - /** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped. */ + /** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped. + * @group Signals + */ val enq = Flipped(EnqIO(gen)) - /** I/O to dequeue data (client is consumer and Queue object is producer), is [[Chisel.DecoupledIO]]*/ + /** I/O to dequeue data (client is consumer and Queue object is producer), is [[Chisel.DecoupledIO]] + * @group Signals + */ val deq = Flipped(DeqIO(gen)) - /** The current amount of data in the queue */ + /** The current amount of data in the queue + * @group Signals + */ val count = Output(UInt(log2Ceil(entries + 1).W)) - /** When asserted, reset the enqueue and dequeue pointers, effectively flushing the queue (Optional IO for a flushable Queue)*/ + /** When asserted, reset the enqueue and dequeue pointers, effectively flushing the queue (Optional IO for a flushable Queue) + * @group Signals + */ val flush = if (hasFlush) Some(Input(Bool())) else None } diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala index 4d348014..5d80502a 100644 --- a/src/main/scala/chisel3/util/Valid.scala +++ b/src/main/scala/chisel3/util/Valid.scala @@ -17,12 +17,17 @@ import chisel3._ * @tparam T the type of the data * @param gen some data * @see [[Valid$ Valid factory]] for concrete examples + * @groupdesc Signals The actual hardware fields of the Bundle */ class Valid[+T <: Data](gen: T) extends Bundle { - /** A bit that will be asserted when `bits` is valid */ + /** A bit that will be asserted when `bits` is valid + * @group Signals + */ val valid = Output(Bool()) - /** Some data */ + /** The data to be transferred, qualified by `valid` + * @group Signals + */ val bits = Output(gen) /** True when `valid` is asserted @@ -173,13 +178,18 @@ class Pipe[T <: Data](val gen: T, val latency: Int = 1)(implicit compileOptions: /** Interface for [[Pipe]]s composed of a [[Valid]] input and [[Valid]] output * @define notAQueue + * @groupdesc Signals Hardware fields of the Bundle */ class PipeIO extends Bundle { - /** [[Valid]] input */ + /** [[Valid]] input + * @group Signals + */ val enq = Input(Valid(gen)) - /** [[Valid]] output. Data will appear here `latency` cycles after being valid at `enq`. */ + /** [[Valid]] output. Data will appear here `latency` cycles after being valid at `enq`. + * @group Signals + */ val deq = Output(Valid(gen)) } diff --git a/src/main/scala/chisel3/util/random/PRNG.scala b/src/main/scala/chisel3/util/random/PRNG.scala index 9b42acf1..3a44385a 100644 --- a/src/main/scala/chisel3/util/random/PRNG.scala +++ b/src/main/scala/chisel3/util/random/PRNG.scala @@ -7,16 +7,23 @@ import chisel3.util.Valid /** Pseudo Random Number Generators (PRNG) interface * @param n the width of the LFSR + * @groupdesc Signals The actual hardware fields of the Bundle */ class PRNGIO(val n: Int) extends Bundle { - /** A [[chisel3.util.Valid Valid]] interface that can be used to set the seed (internal PRNG state) */ + /** A [[chisel3.util.Valid Valid]] interface that can be used to set the seed (internal PRNG state) + * @group Signals + */ val seed: Valid[Vec[Bool]] = Input(Valid(Vec(n, Bool()))) - /** When asserted, the PRNG will increment by one */ + /** When asserted, the PRNG will increment by one + * @group Signals + */ val increment: Bool = Input(Bool()) - /** The current state of the PRNG */ + /** The current state of the PRNG + * @group Signals + */ val out: Vec[Bool] = Output(Vec(n, Bool())) } -- cgit v1.2.3 From 614551236186d35ff42ea9c90130a3b80646ba69 Mon Sep 17 00:00:00 2001 From: Abongwa Bonalais Date: Wed, 3 Nov 2021 06:46:49 +0100 Subject: Add field grouping ScalaDoc for ArbiterIO (#2208) * Update Arbiter.scala * Update src/main/scala/chisel3/util/Arbiter.scala changed group name Co-authored-by: Megan Wachs * minor changes on grouping ArbiterIO * removed unmatched closing brace * Remove groupdesc from Arbiter.scala * Added groupdesc to Aggregate.scala * Update Arbiter.scala * Update core/src/main/scala/chisel3/Aggregate.scala Co-authored-by: Megan Wachs * Update Arbiter.scala * Update src/main/scala/chisel3/util/Arbiter.scala Added suugestions. Co-authored-by: Megan Wachs * added suggestions from review * added suggestions from review * Resolved conflicts * update Arbiter.scala * Update core/src/main/scala/chisel3/Aggregate.scala deleted groudesc for ArbiterIO Co-authored-by: Megan Wachs * Update Scaladoc syntax * removed some lines * Better documentation * Removed @param and @gen * Update core/src/main/scala/chisel3/Aggregate.scala Co-authored-by: Megan Wachs * Update src/main/scala/chisel3/util/Arbiter.scala Co-authored-by: Megan Wachs * Added groupdesc to ArbiterIO * Update src/main/scala/chisel3/util/Arbiter.scala Co-authored-by: Megan Wachs * Update core/src/main/scala/chisel3/Aggregate.scala Co-authored-by: Megan Wachs * Update Arbiter.scala * Update src/main/scala/chisel3/util/Arbiter.scala Co-authored-by: Megan Wachs * Update Arbiter.scala Co-authored-by: Megan Wachs --- src/main/scala/chisel3/util/Arbiter.scala | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala index 135700fa..b68acae1 100644 --- a/src/main/scala/chisel3/util/Arbiter.scala +++ b/src/main/scala/chisel3/util/Arbiter.scala @@ -10,6 +10,7 @@ import chisel3.internal.naming.chiselName // can't use chisel3_ version because /** IO bundle definition for an Arbiter, which takes some number of ready-valid inputs and outputs * (selects) at most one. + * @groupdesc Signals The actual hardware fields of the Bundle * * @param gen data type * @param n number of inputs @@ -17,8 +18,20 @@ import chisel3.internal.naming.chiselName // can't use chisel3_ version because class ArbiterIO[T <: Data](private val gen: T, val n: Int) extends Bundle { // See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs. +/** Input data, one per potential sender + * + * @group Signals + */ val in = Flipped(Vec(n, Decoupled(gen))) +/** Output data after arbitration + * + * @group Signals + */ val out = Decoupled(gen) +/** One-Hot vector indicating which output was chosen + * + * @group Signals + */ val chosen = Output(UInt(log2Ceil(n).W)) } -- cgit v1.2.3 From d4aa92cef6b067ef6c1c37fc7fde467f0c815767 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Sun, 14 Nov 2021 04:29:00 +0800 Subject: add toBools to compatibility layer. --- src/main/scala/chisel3/compatibility.scala | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index ffbb7e27..d1e7b4f1 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -637,6 +637,7 @@ package object Chisel { final def toUInt(implicit compileOptions: CompileOptions): UInt = a.do_asUInt(DeprecatedSourceInfo, compileOptions) + final def toBools(implicit compileOptions: CompileOptions): Seq[Bool] = a.do_asBools(DeprecatedSourceInfo, compileOptions) } } -- cgit v1.2.3 From 00b6a9a9ef398320fc6ffe451b0a757f69aae7bd Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Sun, 14 Nov 2021 04:30:13 +0800 Subject: add tests. --- src/test/scala/chiselTests/CompatibilitySpec.scala | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/CompatibilitySpec.scala b/src/test/scala/chiselTests/CompatibilitySpec.scala index ccf287a6..7ac67b7c 100644 --- a/src/test/scala/chiselTests/CompatibilitySpec.scala +++ b/src/test/scala/chiselTests/CompatibilitySpec.scala @@ -536,6 +536,9 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck info("toUInt works") s.toUInt shouldBe a [UInt] + + info("toBools works") + s.toBools shouldBe a [Seq[Bool]] } ChiselStage.elaborate(new Foo) -- cgit v1.2.3 From 8f796df5693b560a086b95a24c5bd090064a639e Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Thu, 18 Nov 2021 02:31:32 +0800 Subject: refactor Queue.hasFlush: Boolean to Queue.flush: Option[Bool]. (#2245) * refactor Queue.hasFlush: Boolean to Queue.flush: Option[Bool]. Using factory Queue(..., hasFlush = true) won't take effects, since in the Queue.apply API, Queue Module is not exposed, thus even user defines hasFlush = true, there is no place for them to give the flush signal. This commit fix this, refactor Queue.hasFlush: Boolean to Queue.flush: Option[Bool], makes user be able to pass the flush signal into Queue Module. * use zip to connect. * refactor docs. Co-authored-by: Megan Wachs --- src/main/scala/chisel3/util/Decoupled.scala | 65 +++++++++++++++++++---------- 1 file changed, 44 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala index 2a098f4d..4b8b3eeb 100644 --- a/src/main/scala/chisel3/util/Decoupled.scala +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -249,7 +249,7 @@ class Queue[T <: Data](val gen: T, val full = ptr_match && maybe_full val do_enq = WireDefault(io.enq.fire) val do_deq = WireDefault(io.deq.fire) - val flush = io.flush.getOrElse(false.B) + val flush = io.flush.getOrElse(false.B) // when flush is high, empty the queue // Semantically, any enqueues happen before the flush. @@ -307,20 +307,26 @@ class Queue[T <: Data](val gen: T, } } -/** Factory for a generic hardware queue. - * - * @param enq input (enqueue) interface to the queue, also determines width of queue elements - * @param entries depth (number of elements) of the queue - * - * @return output (dequeue) interface from the queue - * - * @example {{{ - * consumer.io.in <> Queue(producer.io.out, 16) - * }}} - */ +/** Factory for a generic hardware queue. */ object Queue { - /** Create a queue and supply a DecoupledIO containing the product. */ + /** Create a [[Queue]] and supply a [[DecoupledIO]] containing the product. + * + * @param enq input (enqueue) interface to the queue, also determines type of queue elements. + * @param entries depth (number of elements) of the queue + * @param pipe True if a single entry queue can run at full throughput (like a pipeline). The `ready` signals are + * combinationally coupled. + * @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately). + * The `valid` signals are coupled. + * @param useSyncReadMem True uses SyncReadMem instead of Mem as an internal memory element. + * @param flush Optional [[Bool]] signal, if defined, the [[Queue.hasFlush]] will be true, and connect correspond + * signal to [[Queue]] instance. + * @return output (dequeue) interface from the queue. + * + * @example {{{ + * consumer.io.in <> Queue(producer.io.out, 16) + * }}} + */ @chiselName def apply[T <: Data]( enq: ReadyValidIO[T], @@ -328,7 +334,7 @@ object Queue pipe: Boolean = false, flow: Boolean = false, useSyncReadMem: Boolean = false, - hasFlush: Boolean = false): DecoupledIO[T] = { + flush: Option[Bool] = None): DecoupledIO[T] = { if (entries == 0) { val deq = Wire(new DecoupledIO(chiselTypeOf(enq.bits))) deq.valid := enq.valid @@ -336,7 +342,8 @@ object Queue enq.ready := deq.ready deq } else { - val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem, hasFlush)) + val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem, flush.isDefined)) + q.io.flush.zip(flush).foreach(f => f._1 := f._2) q.io.enq.valid := enq.valid // not using <> so that override is allowed q.io.enq.bits := enq.bits enq.ready := q.io.enq.ready @@ -344,10 +351,25 @@ object Queue } } - /** Create a queue and supply a IrrevocableIO containing the product. - * Casting from Decoupled is safe here because we know the Queue has - * Irrevocable semantics; we didn't want to change the return type of - * apply() for backwards compatibility reasons. + /** Create a queue and supply a [[IrrevocableIO]] containing the product. + * Casting from [[DecoupledIO]] is safe here because we know the [[Queue]] has + * Irrevocable semantics. + * we didn't want to change the return type of apply() for backwards compatibility reasons. + * + * @param enq [[DecoupledIO]] signal to enqueue. + * @param entries The max number of entries in the queue + * @param pipe True if a single entry queue can run at full throughput (like a pipeline). The ''ready'' signals are + * combinationally coupled. + * @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately). + * The ''valid'' signals are coupled. + * @param useSyncReadMem True uses SyncReadMem instead of Mem as an internal memory element. + * @param flush Optional [[Bool]] signal, if defined, the [[Queue.hasFlush]] will be true, and connect correspond + * signal to [[Queue]] instance. + * @return a [[DecoupledIO]] signal which should connect to the dequeue signal. + * + * @example {{{ + * consumer.io.in <> Queue(producer.io.out, 16) + * }}} */ @chiselName def irrevocable[T <: Data]( @@ -355,8 +377,9 @@ object Queue entries: Int = 2, pipe: Boolean = false, flow: Boolean = false, - useSyncReadMem: Boolean = false): IrrevocableIO[T] = { - val deq = apply(enq, entries, pipe, flow, useSyncReadMem) + useSyncReadMem: Boolean = false, + flush: Option[Bool] = None): IrrevocableIO[T] = { + val deq = apply(enq, entries, pipe, flow, useSyncReadMem, flush) require(entries > 0, "Zero-entry queues don't guarantee Irrevocability") val irr = Wire(new IrrevocableIO(chiselTypeOf(deq.bits))) irr.bits := deq.bits -- cgit v1.2.3 From 2b0bc0ecbc9c53882e2104ecd1e1387039be27f3 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Tue, 23 Nov 2021 04:17:14 +0800 Subject: add documentations to decoder. (#2254) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- .../chisel3/util/experimental/decode/EspressoMinimizer.scala | 12 +++++++++++- .../chisel3/util/experimental/decode/QMCMinimizer.scala | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (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 1d725875..6adf544c 100644 --- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala @@ -7,11 +7,21 @@ import logger.LazyLogging case object EspressoNotFoundException extends Exception +/** A [[Minimizer]] implementation to use espresso to minimize the [[TruthTable]]. + * + * espresso uses heuristic algorithm providing a sub-optimized) result. + * For implementation details, please refer to: + * [[https://www.springerprofessional.de/en/logic-minimization-algorithms-for-vlsi-synthesis/13780088]] + * + * a espresso executable should be downloaded from [[https://github.com/chipsalliance/espresso]] + * + * If user want to user the this [[Minimizer]], a espresso executable should be added to system PATH environment. + */ object EspressoMinimizer extends Minimizer with LazyLogging { def minimize(table: TruthTable): TruthTable = TruthTable.merge(TruthTable.split(table).map{case (table, indexes) => (espresso(table), indexes)}) - def espresso(table: TruthTable): TruthTable = { + private def espresso(table: TruthTable): TruthTable = { def writeTable(table: TruthTable): String = { def invert(string: String) = string .replace('0', 't') diff --git a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala index c1533f44..8bd8a03e 100644 --- a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala @@ -8,6 +8,15 @@ import scala.annotation.tailrec import scala.math.Ordered.orderingToOrdered import scala.language.implicitConversions +/** A [[Minimizer]] implementation to use Quine-Mccluskey algorithm to minimize the [[TruthTable]]. + * + * This algorithm can always find the best solution, but is a NP-Complete algorithm, + * which means, for large-scale [[TruthTable]] minimization task, it will be really slow, + * and might run out of memory of JVM stack. + * + * In this situation, users should consider switch to [[EspressoMinimizer]], + * which uses heuristic algorithm providing a sub-optimized result. + */ object QMCMinimizer extends Minimizer { private implicit def toImplicant(x: BitPat): Implicant = new Implicant(x) -- cgit v1.2.3 From f26f8554879f638b4c4743becbc6da13da174e63 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Wed, 24 Nov 2021 03:11:25 +0800 Subject: fix for chipsalliance/firrtl#2421 (#2256) --- src/test/scala/chiselTests/IntervalSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/IntervalSpec.scala b/src/test/scala/chiselTests/IntervalSpec.scala index a33cedc1..c223260d 100644 --- a/src/test/scala/chiselTests/IntervalSpec.scala +++ b/src/test/scala/chiselTests/IntervalSpec.scala @@ -15,7 +15,7 @@ import firrtl.passes.CheckTypes.InvalidConnect import firrtl.passes.CheckWidths.{DisjointSqueeze, InvalidRange} import firrtl.passes.{PassExceptions, WrapWithRemainder} import firrtl.stage.{CompilerAnnotation, FirrtlCircuitAnnotation} -import firrtl.{FIRRTLException, HighFirrtlCompiler, LowFirrtlCompiler, MiddleFirrtlCompiler, MinimumVerilogCompiler, NoneCompiler, SystemVerilogCompiler, VerilogCompiler} +import firrtl.{HighFirrtlCompiler, LowFirrtlCompiler, MiddleFirrtlCompiler, MinimumVerilogCompiler, NoneCompiler, SystemVerilogCompiler, VerilogCompiler} import org.scalatest.freespec.AnyFreeSpec import org.scalatest.matchers.should.Matchers -- cgit v1.2.3 From 563f6157a861d0f524a84d15fc8c2647c8cfb6ba Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Mon, 29 Nov 2021 11:39:00 -0800 Subject: Deprecate chisel3.BackendCompilationUtilities (#2257) Also remove as many deprecated APIs as possible by inlining implementations of old deprecated/removed code from firrtl--- src/main/scala/chisel3/Driver.scala | 145 +++++++++++++++++------------ src/main/scala/chisel3/compatibility.scala | 3 +- src/main/scala/chisel3/stage/package.scala | 29 ------ src/test/scala/chiselTests/Harness.scala | 5 +- 4 files changed, 86 insertions(+), 96 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala index fb564446..aa379629 100644 --- a/src/main/scala/chisel3/Driver.scala +++ b/src/main/scala/chisel3/Driver.scala @@ -2,85 +2,106 @@ package chisel3 -import chisel3.internal.ErrorLog import internal.firrtl._ import firrtl._ -import firrtl.options.{Dependency, Phase, PhaseManager, StageError} -import firrtl.options.phases.DeletedWrapper -import firrtl.options.Viewer.view -import firrtl.annotations.JsonProtocol import firrtl.util.{BackendCompilationUtilities => FirrtlBackendCompilationUtilities} -import chisel3.stage.{ChiselExecutionResultView, ChiselGeneratorAnnotation, ChiselStage} -import chisel3.stage.phases.DriverCompatibility import java.io._ +import _root_.logger.LazyLogging +@deprecated("Use object firrtl.util.BackendCompilationUtilities instead", "Chisel 3.5") +trait BackendCompilationUtilities extends LazyLogging { -/** - * The Driver provides methods to invoke the chisel3 compiler and the firrtl compiler. - * By default firrtl is automatically run after chisel. an [[ExecutionOptionsManager]] - * is needed to manage options. It can parser command line arguments or coordinate - * multiple chisel toolchain tools options. - * - * @example - * {{{ - * val optionsManager = new ExecutionOptionsManager("chisel3") - * with HasFirrtlOptions - * with HasChiselExecutionOptions { - * commonOptions = CommonOption(targetDirName = "my_target_dir") - * chiselOptions = ChiselExecutionOptions(runFirrtlCompiler = false) - * } - * chisel3.Driver.execute(optionsManager, () => new Dut) - * }}} - * or via command line arguments - * @example {{{ - * args = "--no-run-firrtl --target-dir my-target-dir".split(" +") - * chisel3.execute(args, () => new DUT) - * }}} - */ + import scala.sys.process.{ProcessBuilder, ProcessLogger, _} + + // Inlined from old trait firrtl.util.BackendCompilationUtilities + lazy val TestDirectory = FirrtlBackendCompilationUtilities.TestDirectory + def timeStamp: String = FirrtlBackendCompilationUtilities.timeStamp + def loggingProcessLogger: ProcessLogger = FirrtlBackendCompilationUtilities.loggingProcessLogger + def copyResourceToFile(name: String, file: File): Unit = FirrtlBackendCompilationUtilities.copyResourceToFile(name, file) + def createTestDirectory(testName: String): File = FirrtlBackendCompilationUtilities.createTestDirectory(testName) + def makeHarness(template: String => String, post: String)(f: File): File = + FirrtlBackendCompilationUtilities.makeHarness(template, post)(f) + def firrtlToVerilog(prefix: String, dir: File): ProcessBuilder = + FirrtlBackendCompilationUtilities.firrtlToVerilog(prefix, dir) + def verilogToCpp( + dutFile: String, + dir: File, + vSources: Seq[File], + cppHarness: File, + suppressVcd: Boolean = false, + resourceFileName: String = firrtl.transforms.BlackBoxSourceHelper.defaultFileListName + ): ProcessBuilder = { + FirrtlBackendCompilationUtilities.verilogToCpp(dutFile, dir, vSources, cppHarness, suppressVcd, resourceFileName) + } + def cppToExe(prefix: String, dir: File): ProcessBuilder = FirrtlBackendCompilationUtilities.cppToExe(prefix, dir) + def executeExpectingFailure( + prefix: String, + dir: File, + assertionMsg: String = "" + ): Boolean = { + FirrtlBackendCompilationUtilities.executeExpectingFailure(prefix, dir, assertionMsg) + } + def executeExpectingSuccess(prefix: String, dir: File): Boolean = + FirrtlBackendCompilationUtilities.executeExpectingSuccess(prefix, dir) -trait BackendCompilationUtilities extends FirrtlBackendCompilationUtilities { /** Compile Chirrtl to Verilog by invoking Firrtl inside the same JVM * * @param prefix basename of the file * @param dir directory where file lives * @return true if compiler completed successfully */ + @deprecated("Use ChiselStage instead", "Chisel 3.5") def compileFirrtlToVerilog(prefix: String, dir: File): Boolean = { - val optionsManager = new ExecutionOptionsManager("chisel3") with HasChiselExecutionOptions with HasFirrtlOptions { - commonOptions = CommonOptions(topName = prefix, targetDirName = dir.getAbsolutePath) - firrtlOptions = FirrtlExecutionOptions(compilerName = "verilog") + + // ====== Implemented by inlining logic from ExecutionsOptionManager.toAnnotations ===== + import firrtl.stage.InfoModeAnnotation + import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation + import _root_.logger.LogLevelAnnotation + val annos: AnnotationSeq = List( + InfoModeAnnotation("append"), + TopNameAnnotation(prefix), + TargetDirAnnotation(dir.getAbsolutePath), + LogLevelAnnotation(_root_.logger.LogLevel.None) + ) + + // ******************* Implemented by inlining firrtl.Driver.execute *************************** + import firrtl.stage.phases.DriverCompatibility + import firrtl.stage.FirrtlStage + import firrtl.options.{Dependency, Phase, PhaseManager} + import firrtl.options.phases.DeletedWrapper + + val phases: Seq[Phase] = { + import DriverCompatibility._ + new PhaseManager( + List( + Dependency[AddImplicitFirrtlFile], + Dependency[AddImplicitAnnotationFile], + Dependency[AddImplicitOutputFile], + Dependency[AddImplicitEmitter], + Dependency[FirrtlStage] + ) + ).transformOrder + .map(DeletedWrapper(_)) } - firrtl.Driver.execute(optionsManager) match { - case _: FirrtlExecutionSuccess => true - case _: FirrtlExecutionFailure => false + val annosx = + try { + phases.foldLeft(annos)((a, p) => p.transform(a)) + } catch { + case _: firrtl.options.OptionsException => return false + } + // ********************************************************************************************* + + val options = annosx + + // ********** Implemented by inlining firrtl.stage.FirrtlExecutionResultView.view ************** + import firrtl.stage.FirrtlCircuitAnnotation + + options.collectFirst { case a: FirrtlCircuitAnnotation => a.circuit } match { + case None => false + case Some(_) => true } + // ********************************************************************************************* } } -/** - * This family provides return values from the chisel3 and possibly firrtl compile steps - */ -@deprecated("This will be removed in Chisel 3.5", "Chisel3 3.4") -trait ChiselExecutionResult - -/** - * - * @param circuitOption Optional circuit, has information like circuit name - * @param emitted The emitted Chirrrl text - * @param firrtlResultOption Optional Firrtl result, @see freechipsproject/firrtl for details - */ -@deprecated("This will be removed in Chisel 3.5", "Chisel 3.4") -case class ChiselExecutionSuccess( - circuitOption: Option[Circuit], - emitted: String, - firrtlResultOption: Option[FirrtlExecutionResult] - ) extends ChiselExecutionResult - -/** - * Getting one of these indicates failure of some sort. - * - * @param message A clue might be provided here. - */ -@deprecated("This will be removed in Chisel 3.5", "Chisel 3.4") -case class ChiselExecutionFailure(message: String) extends ChiselExecutionResult diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index d1e7b4f1..ccb4ec1f 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -365,7 +365,8 @@ package object Chisel { implicit class fromBooleanToLiteral(x: Boolean) extends chisel3.fromBooleanToLiteral(x) implicit class fromIntToWidth(x: Int) extends chisel3.fromIntToWidth(x) - type BackendCompilationUtilities = firrtl.util.BackendCompilationUtilities + @deprecated("Use object firrtl.util.BackendCompilationUtilities instead", "Chisel 3.5") + type BackendCompilationUtilities = chisel3.BackendCompilationUtilities val ImplicitConversions = chisel3.util.ImplicitConversions // Deprecated as of Chisel3 diff --git a/src/main/scala/chisel3/stage/package.scala b/src/main/scala/chisel3/stage/package.scala index 4d6738d6..c307d3ae 100644 --- a/src/main/scala/chisel3/stage/package.scala +++ b/src/main/scala/chisel3/stage/package.scala @@ -24,33 +24,4 @@ package object stage { } } - - private[chisel3] implicit object ChiselExecutionResultView extends OptionsView[ChiselExecutionResult] { - - def view(options: AnnotationSeq): ChiselExecutionResult = { - var chiselCircuit: Option[ChiselCircuit] = None - var chirrtlCircuit: Option[String] = None - - options.foreach { - case a @ ChiselCircuitAnnotation(b) => - chiselCircuit = Some(b) - chirrtlCircuit = { - val anno = CircuitSerializationAnnotation(a.circuit, "", FirrtlFileFormat) - Some(anno.getBytes.map(_.toChar).mkString) - } - case _ => - } - - val fResult = firrtl.stage.phases.DriverCompatibility.firrtlResultView(options) - - (chiselCircuit, chirrtlCircuit) match { - case (None, _) => ChiselExecutionFailure("Failed to elaborate Chisel circuit") - case (Some(_), None) => ChiselExecutionFailure("Failed to convert Chisel circuit to FIRRTL") - case (Some(a), Some(b)) => ChiselExecutionSuccess( Some(a), b, Some(fResult)) - } - - } - - } - } diff --git a/src/test/scala/chiselTests/Harness.scala b/src/test/scala/chiselTests/Harness.scala index 23379498..51576566 100644 --- a/src/test/scala/chiselTests/Harness.scala +++ b/src/test/scala/chiselTests/Harness.scala @@ -4,10 +4,7 @@ package chiselTests import java.io.File -import firrtl.util.BackendCompilationUtilities - -class HarnessSpec extends ChiselPropSpec - with BackendCompilationUtilities { +class HarnessSpec extends ChiselPropSpec { def makeTrivialVerilog: (File => File) = makeHarness((prefix: String) => s""" module ${prefix}; -- cgit v1.2.3 From 40192433e96ffe91928fa140d32f99562f95e7cf Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Mon, 29 Nov 2021 16:02:04 -0800 Subject: Remove ChiselExecutionOptions and HasChiselExecutionOptions (#2267) These were not actually deprecated but any APIs using them were long since deprecated and more recently removed. They also depend on long deprecated APIs in FIRRTL that will soon be removed.--- .../scala/chisel3/ChiselExecutionOptions.scala | 49 ---------------------- .../chisel3/stage/phases/DriverCompatibility.scala | 16 +++---- 2 files changed, 5 insertions(+), 60 deletions(-) delete mode 100644 src/main/scala/chisel3/ChiselExecutionOptions.scala (limited to 'src') diff --git a/src/main/scala/chisel3/ChiselExecutionOptions.scala b/src/main/scala/chisel3/ChiselExecutionOptions.scala deleted file mode 100644 index 9f635b19..00000000 --- a/src/main/scala/chisel3/ChiselExecutionOptions.scala +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3 - -import chisel3.stage.{NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation} - -import firrtl.{AnnotationSeq, ExecutionOptionsManager, ComposableOptions} - -//TODO: provide support for running firrtl as separate process, could alternatively be controlled by external driver -//TODO: provide option for not saving chirrtl file, instead calling firrtl with in memory chirrtl -/** - * Options that are specific to chisel. - * - * @param runFirrtlCompiler when true just run chisel, when false run chisel then compile its output with firrtl - * @note this extends FirrtlExecutionOptions which extends CommonOptions providing easy access to down chain options - */ -case class ChiselExecutionOptions( - runFirrtlCompiler: Boolean = true, - printFullStackTrace: Boolean = false - // var runFirrtlAsProcess: Boolean = false - ) extends ComposableOptions { - - def toAnnotations: AnnotationSeq = - (if (!runFirrtlCompiler) { Seq(NoRunFirrtlCompilerAnnotation) } else { Seq() }) ++ - (if (printFullStackTrace) { Some(PrintFullStackTraceAnnotation) } else { None }) - -} - -trait HasChiselExecutionOptions { - self: ExecutionOptionsManager => - - var chiselOptions = ChiselExecutionOptions() - - parser.note("chisel3 options") - - parser.opt[Unit]("no-run-firrtl") - .abbr("chnrf") - .foreach { _ => - chiselOptions = chiselOptions.copy(runFirrtlCompiler = false) - } - .text("Stop after chisel emits chirrtl file") - - parser.opt[Unit]("full-stacktrace") - .foreach { _ => - chiselOptions = chiselOptions.copy(printFullStackTrace = true) - } - .text("Do not trim stack trace") -} - diff --git a/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala b/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala index 9305c5c9..847b7179 100644 --- a/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala +++ b/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala @@ -2,19 +2,13 @@ package chisel3.stage.phases -import firrtl.{AnnotationSeq, ExecutionOptionsManager, HasFirrtlOptions} -import firrtl.annotations.NoTargetAnnotation -import firrtl.options.{Dependency, OptionsException, OutputAnnotationFileAnnotation, Phase, Unserializable} -import firrtl.stage.{FirrtlCircuitAnnotation, RunFirrtlTransformAnnotation} -import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation +import firrtl.annotations.Annotation +import firrtl.options.Phase -import chisel3.HasChiselExecutionOptions -import chisel3.stage.{ChiselStage, NoRunFirrtlCompilerAnnotation, ChiselOutputFileAnnotation} - -/** This provides components of a compatibility wrapper around Chisel's deprecated [[chisel3.Driver]]. +/** This formerly provided components of a compatibility wrapper around Chisel's removed `chisel3.Driver`. * - * Primarily, this object includes [[firrtl.options.Phase Phase]]s that generate [[firrtl.annotations.Annotation]]s - * derived from the deprecated [[firrtl.stage.phases.DriverCompatibility.TopNameAnnotation]]. + * This object formerly included [[firrtl.options.Phase Phase]]s that generate [[firrtl.annotations.Annotation]]s + * derived from the deprecated `firrtl.stage.phases.DriverCompatibility.TopNameAnnotation`. */ @deprecated("This object contains no public members. This will be removed in Chisel 3.6.", "Chisel 3.5") object DriverCompatibility -- cgit v1.2.3 From ef1a14e29e8d634cd8e52490b2a3fc368218c41c Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Tue, 30 Nov 2021 17:05:14 -0800 Subject: Remove unused imports for API removed from firrtl (#2269) This fixes CI which fails with current firrtl 1.5-SNAPSHOT.--- src/test/scala/chiselTests/BlackBoxImpl.scala | 1 - src/test/scala/chiselTests/InlineSpec.scala | 1 - src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala | 1 - src/test/scala/chiselTests/TransitNameSpec.scala | 1 - 4 files changed, 4 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/BlackBoxImpl.scala b/src/test/scala/chiselTests/BlackBoxImpl.scala index a9a6fa29..2fa3d8a6 100644 --- a/src/test/scala/chiselTests/BlackBoxImpl.scala +++ b/src/test/scala/chiselTests/BlackBoxImpl.scala @@ -7,7 +7,6 @@ import java.io.File import chisel3._ import chisel3.util.{HasBlackBoxInline, HasBlackBoxResource, HasBlackBoxPath} import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} -import firrtl.FirrtlExecutionSuccess import firrtl.transforms.BlackBoxNotFoundException import org.scalacheck.Test.Failed import org.scalatest.Succeeded diff --git a/src/test/scala/chiselTests/InlineSpec.scala b/src/test/scala/chiselTests/InlineSpec.scala index 397eac2e..59a1e984 100644 --- a/src/test/scala/chiselTests/InlineSpec.scala +++ b/src/test/scala/chiselTests/InlineSpec.scala @@ -5,7 +5,6 @@ package chiselTests import chisel3._ import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} import chisel3.util.experimental.{InlineInstance, FlattenInstance} -import firrtl.FirrtlExecutionSuccess import firrtl.passes.InlineAnnotation import firrtl.stage.{FirrtlCircuitAnnotation, FirrtlStage} import firrtl.transforms.FlattenAnnotation diff --git a/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala b/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala index 8a998496..74e587bc 100644 --- a/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala +++ b/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala @@ -8,7 +8,6 @@ import chisel3._ import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} import chisel3.util.experimental.{loadMemoryFromFile,loadMemoryFromFileInline} import chisel3.util.log2Ceil -import firrtl.FirrtlExecutionSuccess import firrtl.annotations.MemoryLoadFileType import org.scalatest.freespec.AnyFreeSpec import org.scalatest.matchers.should.Matchers diff --git a/src/test/scala/chiselTests/TransitNameSpec.scala b/src/test/scala/chiselTests/TransitNameSpec.scala index b21818d6..656c6731 100644 --- a/src/test/scala/chiselTests/TransitNameSpec.scala +++ b/src/test/scala/chiselTests/TransitNameSpec.scala @@ -6,7 +6,6 @@ import chisel3._ import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} import chisel3.util.TransitName -import firrtl.FirrtlExecutionSuccess import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -- cgit v1.2.3 From a476329ef7b051aa480903cacd7d62ee46980c84 Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Tue, 30 Nov 2021 17:45:59 -0800 Subject: Bugfix - definition name index skipping with D/I (#2249) * Bugfix - definition name index skipping with D/I * Add tests to DefinitionSpec * Add failing test * Fix failing test * Update core/src/main/scala/chisel3/internal/Builder.scala Co-authored-by: Jack Koenig * whitespace * revert package private val Co-authored-by: Jack Koenig Co-authored-by: Jack Koenig --- .../experimental/hierarchy/DefinitionSpec.scala | 44 ++++++++++++++++++++-- .../experimental/hierarchy/Examples.scala | 28 ++++++++++++++ .../experimental/hierarchy/InstanceSpec.scala | 28 +++++++------- 3 files changed, 83 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala index 4eb77c8a..f33f7869 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala @@ -40,6 +40,44 @@ class DefinitionSpec extends ChiselFunSpec with Utils { val (chirrtl, _) = getFirrtlAndAnnos(new Top) chirrtl.serialize should include ("inst i0 of HasUninferredReset") } + it("0.3: module names of repeated definition should be sequential") { + class Top extends Module { + val k = Module(new AddTwoParameterized(4, (x: Int) => Seq.tabulate(x){j => + val addOneDef = Definition(new AddOneParameterized(x+j)) + val addOne = Instance(addOneDef) + addOne + })) + } + val (chirrtl, _) = getFirrtlAndAnnos(new Top) + chirrtl.serialize should include ("module AddOneParameterized :") + chirrtl.serialize should include ("module AddOneParameterized_1 :") + chirrtl.serialize should include ("module AddOneParameterized_2 :") + chirrtl.serialize should include ("module AddOneParameterized_3 :") + } + it("0.4: multiple instantiations should have sequential names") { + class Top extends Module { + val addOneDef = Definition(new AddOneParameterized(4)) + val addOne = Instance(addOneDef) + val otherAddOne = Module(new AddOneParameterized(4)) + } + val (chirrtl, _) = getFirrtlAndAnnos(new Top) + chirrtl.serialize should include ("module AddOneParameterized :") + chirrtl.serialize should include ("module AddOneParameterized_1 :") + } + it("0.5: nested definitions should have sequential names") { + class Top extends Module { + val k = Module(new AddTwoWithNested(4, (x: Int) => Seq.tabulate(x){j => + val addOneDef = Definition(new AddOneWithNested(x+j)) + val addOne = Instance(addOneDef) + addOne + })) + } + val (chirrtl, _) = getFirrtlAndAnnos(new Top) + chirrtl.serialize should include ("module AddOneWithNested :") + chirrtl.serialize should include ("module AddOneWithNested_1 :") + chirrtl.serialize should include ("module AddOneWithNested_2 :") + chirrtl.serialize should include ("module AddOneWithNested_3 :") + } } describe("1: Annotations on definitions in same chisel compilation") { it("1.0: should work on a single definition, annotating the definition") { @@ -97,7 +135,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils { mark(definition.i1, "i0.i1") } val (_, annos) = getFirrtlAndAnnos(new Top) - annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_2".it, "i0.i1")) + annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_1".it, "i0.i1")) } // Can you define an instantiable container? I think not. // Instead, we can test the instantiable container in a definition @@ -322,7 +360,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils { amark(i.i1.in, "blah") } val (_, annos) = getFirrtlAndAnnos(new Top) - annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_2>in".rt, "blah")) + annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_1>in".rt, "blah")) } it("5.3: toAbsoluteTarget on a submodule's data, in an aggregate, within a definition") { class Top() extends Module { @@ -330,7 +368,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils { amark(i.i1.x.head, "blah") } val (_, annos) = getFirrtlAndAnnos(new Top) - annos should contain(MarkAnnotation("~Top|InstantiatesHasVec/i1:HasVec_2>x[0]".rt, "blah")) + annos should contain(MarkAnnotation("~Top|InstantiatesHasVec/i1:HasVec_1>x[0]".rt, "blah")) } } describe("6: @instantiable traits should work as expected") { diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala index d8ae7322..c0f504ff 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala @@ -35,6 +35,19 @@ object Examples { innerWire := in + 1.U out := innerWire } + @instantiable + class AddOneParameterized(width: Int) extends Module { + @public val in = IO(Input(UInt(width.W))) + @public val out = IO(Output(UInt(width.W))) + out := in + 1.U + } + class AddOneWithNested(width: Int) extends Module { + @public val in = IO(Input(UInt(width.W))) + @public val out = IO(Output(UInt(width.W))) + val addOneDef = Seq.fill(3)(Definition(new AddOne)) + out := in + 1.U + } + @instantiable class AddTwo extends Module { @public val in = IO(Input(UInt(32.W))) @@ -57,6 +70,21 @@ object Examples { i1.in := i0.out out := i1.out } + @instantiable + class AddTwoParameterized(width: Int, makeParameterizedOnes: Int => Seq[Instance[AddOneParameterized]]) extends Module { + val in = IO(Input(UInt(width.W))) + val out = IO(Output(UInt(width.W))) + val addOnes = makeParameterizedOnes(width) + addOnes.head.in := in + out := addOnes.last.out + addOnes.zip(addOnes.tail).foreach{ case (head, tail) => tail.in := head.out} + } + @instantiable + class AddTwoWithNested(width: Int, makeParameterizedOnes: Int => Seq[Instance[AddOneWithNested]]) extends Module { + val in = IO(Input(UInt(width.W))) + val out = IO(Output(UInt(width.W))) + val addOnes = makeParameterizedOnes(width) + } @instantiable class AddFour extends Module { diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala index 83084468..929e3875 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala @@ -89,7 +89,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { mark(i0.i1, "i0.i1") } val (_, annos) = getFirrtlAndAnnos(new Top) - annos should contain (MarkAnnotation("~Top|Top/i0:AddTwoMixedModules/i1:AddOne_2".it, "i0.i1")) + annos should contain (MarkAnnotation("~Top|Top/i0:AddTwoMixedModules/i1:AddOne_1".it, "i0.i1")) } it("1.5: should work on an instantiable container, annotating a wire") { class Top extends Module { @@ -362,7 +362,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { amark(i.i1.in, "blah") } val (_, annos) = getFirrtlAndAnnos(new Top) - annos should contain(MarkAnnotation("~Top|Top/i:AddTwoMixedModules/i1:AddOne_2>in".rt, "blah")) + annos should contain(MarkAnnotation("~Top|Top/i:AddTwoMixedModules/i1:AddOne_1>in".rt, "blah")) } it("5.3: toAbsoluteTarget on a submodule's data, in an aggregate, within an instance") { class Top() extends Module { @@ -370,7 +370,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { amark(i.i1.x.head, "blah") } val (_, annos) = getFirrtlAndAnnos(new Top) - annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_2>x[0]".rt, "blah")) + annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_1>x[0]".rt, "blah")) } it("5.4: toAbsoluteTarget on a submodule's data, in an aggregate, within an instance, ILit") { class MyBundle extends Bundle { val x = UInt(3.W) } @@ -388,7 +388,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { amark(i.i1.x.head.x, "blah") } val (_, annos) = getFirrtlAndAnnos(new Top) - annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_2>x[0].x".rt, "blah")) + annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_1>x[0].x".rt, "blah")) } it("5.5: toAbsoluteTarget on a subinstance") { class Top() extends Module { @@ -761,7 +761,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { val targets = aop.Select.instancesOf[AddOne](m.toDefinition).map { i: Instance[AddOne] => i.toTarget } targets should be (Seq( "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it, - "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_2".it, + "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it, )) }) getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect)) @@ -773,11 +773,11 @@ class InstanceSpec extends ChiselFunSpec with Utils { val rel = insts.map { i: Instance[BaseModule] => i.toTarget } abs should be (Seq( "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it, - "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_2".it, + "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it, )) rel should be (Seq( "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it, - "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_2".it, + "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it, )) }) getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect)) @@ -789,15 +789,15 @@ class InstanceSpec extends ChiselFunSpec with Utils { val rel = insts.map { i: Instance[AddOne] => i.in.toTarget } rel should be (Seq( "~AddFour|AddFour/i0:AddTwoMixedModules/i0:AddOne>in".rt, - "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_2>in".rt, + "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_1>in".rt, "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt, - "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_2>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_1>in".rt, )) abs should be (Seq( "~AddFour|AddFour/i0:AddTwoMixedModules/i0:AddOne>in".rt, - "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_2>in".rt, + "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_1>in".rt, "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt, - "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_2>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_1>in".rt, )) }) getFirrtlAndAnnos(new AddFour, Seq(aspect)) @@ -807,7 +807,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { val targets = aop.Select.definitionsOf[AddOne](m.toDefinition).map { i: Definition[AddOne] => i.in.toTarget } targets should be (Seq( "~AddTwoMixedModules|AddOne>in".rt, - "~AddTwoMixedModules|AddOne_2>in".rt, + "~AddTwoMixedModules|AddOne_1>in".rt, )) }) getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect)) @@ -817,7 +817,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { val targets = aop.Select.definitionsIn(m.toDefinition).map { i: Definition[BaseModule] => i.toTarget } targets should be (Seq( "~AddTwoMixedModules|AddOne".mt, - "~AddTwoMixedModules|AddOne_2".mt, + "~AddTwoMixedModules|AddOne_1".mt, )) }) getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect)) @@ -827,7 +827,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { val targets = aop.Select.allDefinitionsOf[AddOne](m.toDefinition).map { i: Definition[AddOne] => i.in.toTarget } targets should be (Seq( "~AddFour|AddOne>in".rt, - "~AddFour|AddOne_2>in".rt, + "~AddFour|AddOne_1>in".rt, )) }) getFirrtlAndAnnos(new AddFour, Seq(aspect)) -- cgit v1.2.3 From 392ea3c9b5b04e374eeb1bf3b0d87ac9fbf45513 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 1 Dec 2021 14:49:34 -0800 Subject: Require the chisel3 compiler plugin (#2271) As the chisel3 compiler plugin is now required, we can delete unused code for reflective autoclonetype as well as the noPluginTests.--- src/test/scala/chisel3/testers/TestUtils.scala | 9 - src/test/scala/chiselTests/AutoClonetypeSpec.scala | 198 ++++++++++----------- .../scala/chiselTests/AutoNestedCloneSpec.scala | 65 ++++--- 3 files changed, 121 insertions(+), 151 deletions(-) (limited to 'src') diff --git a/src/test/scala/chisel3/testers/TestUtils.scala b/src/test/scala/chisel3/testers/TestUtils.scala index c72c779a..338f9cd4 100644 --- a/src/test/scala/chisel3/testers/TestUtils.scala +++ b/src/test/scala/chisel3/testers/TestUtils.scala @@ -12,13 +12,4 @@ object TestUtils { // Useful because TesterDriver.Backend is chisel3 package private def containsBackend(annos: AnnotationSeq): Boolean = annos.collectFirst { case b: Backend => b }.isDefined - - // Allows us to check that the compiler plugin cloneType is actually working - val usingPlugin: Boolean = (new Bundle { def check = _usingPlugin }).check - def elaborateNoReflectiveAutoCloneType(f: => RawModule): Circuit = { - ChiselStage.elaborate { - chisel3.internal.Builder.allowReflectiveAutoCloneType = !usingPlugin - f - } - } } diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala index 3f33fda8..ef58f1ed 100644 --- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala +++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala @@ -5,6 +5,7 @@ package chiselTests import chisel3._ import chisel3.testers.TestUtils import chisel3.util.QueueIO +import chisel3.stage.ChiselStage.elaborate class BundleWithIntArg(val i: Int) extends Bundle { val out = UInt(i.W) @@ -71,14 +72,11 @@ class InheritingBundle extends QueueIO(UInt(8.W), 8) { val error = Output(Bool()) } -// TODO all `.suggestNames` are due to https://github.com/chipsalliance/chisel3/issues/1802 class AutoClonetypeSpec extends ChiselFlatSpec with Utils { - val usingPlugin: Boolean = TestUtils.usingPlugin - val elaborate = TestUtils.elaborateNoReflectiveAutoCloneType _ "Bundles with Scala args" should "not need clonetype" in { elaborate { new Module { - val io = IO(new Bundle{}).suggestName("io") + val io = IO(new Bundle{}) val myWire = Wire(new BundleWithIntArg(8)) assert(myWire.i == 8) @@ -87,7 +85,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { "Bundles with Scala implicit args" should "not need clonetype" in { elaborate { new Module { - val io = IO(new Bundle{}).suggestName("io") + val io = IO(new Bundle{}) implicit val implicitInt: Int = 4 val myWire = Wire(new BundleWithImplicit()) @@ -98,7 +96,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { "Bundles with Scala explicit and impicit args" should "not need clonetype" in { elaborate { new Module { - val io = IO(new Bundle{}).suggestName("io") + val io = IO(new Bundle{}) implicit val implicitInt: Int = 4 val myWire = Wire(new BundleWithArgAndImplicit(8)) @@ -110,7 +108,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { "Subtyped Bundles" should "not need clonetype" in { elaborate { new Module { - val io = IO(new Bundle{}).suggestName("io") + val io = IO(new Bundle{}) val myWire = Wire(new SubBundle(8, 4)) @@ -118,7 +116,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { assert(myWire.i2 == 4) } } elaborate { new Module { - val io = IO(new Bundle{}).suggestName("io") + val io = IO(new Bundle{}) val myWire = Wire(new SubBundleVal(8, 4)) @@ -131,23 +129,12 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { new BundleWithIntArg(8).cloneType } - def checkSubBundleInvalid() = { + "Subtyped Bundles that don't clone well" should "be now be supported!" in { elaborate { new Module { - val io = IO(new Bundle{}).suggestName("io") + val io = IO(new Bundle{}) val myWire = Wire(new SubBundleInvalid(8, 4)) } } } - if (usingPlugin) { - "Subtyped Bundles that don't clone well" should "be now be supported!" in { - checkSubBundleInvalid() - } - } else { - "Subtyped Bundles that don't clone well" should "be caught" in { - a [ChiselException] should be thrownBy extractCause[ChiselException] { - checkSubBundleInvalid() - } - } - } "Inner bundles with Scala args" should "not need clonetype" in { elaborate { new ModuleWithInner } @@ -155,7 +142,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { "Bundles with arguments as fields" should "not need clonetype" in { elaborate { new Module { - val io = IO(Output(new BundleWithArgumentField(UInt(8.W), UInt(8.W)))).suggestName("io") + val io = IO(Output(new BundleWithArgumentField(UInt(8.W), UInt(8.W)))) io.x := 1.U io.y := 1.U } } @@ -163,28 +150,28 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { it should "also work when giving directions to the fields" in { elaborate { new Module { - val io = IO(new BundleWithArgumentField(Input(UInt(8.W)), Output(UInt(8.W)))).suggestName("io") + val io = IO(new BundleWithArgumentField(Input(UInt(8.W)), Output(UInt(8.W)))) io.y := io.x } } } "Bundles inside companion objects" should "not need clonetype" in { elaborate { new Module { - val io = IO(Output(new CompanionObjectWithBundle.Inner)).suggestName("io") + val io = IO(Output(new CompanionObjectWithBundle.Inner)) io.data := 1.U } } } "Parameterized bundles inside companion objects" should "not need clonetype" in { elaborate { new Module { - val io = IO(Output(new CompanionObjectWithBundle.ParameterizedInner(8))).suggestName("io") + val io = IO(Output(new CompanionObjectWithBundle.ParameterizedInner(8))) io.data := 1.U } } } "Nested directioned anonymous Bundles" should "not need clonetype" in { elaborate { new Module { - val io = IO(new NestedAnonymousBundle).suggestName("io") + val io = IO(new NestedAnonymousBundle) val a = WireDefault(io) io.a.a := 1.U } } @@ -197,7 +184,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { val a = Output(UInt(8.W)) } } - val io = IO((new InnerClassThing).createBundle).suggestName("io") + val io = IO((new InnerClassThing).createBundle) val a = WireDefault(io) } } } @@ -208,7 +195,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { val bundleFieldType = UInt(8.W) val io = IO(Output(new Bundle { val a = bundleFieldType - })).suggestName("io") + })) io.a := 0.U } } } @@ -221,7 +208,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { } elaborate { new Module { - val io = IO(Output(new BadBundle(UInt(8.W), 1))).suggestName("io") + val io = IO(Output(new BadBundle(UInt(8.W), 1))) io.a := 0.U } } } @@ -265,100 +252,97 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { behavior of "Compiler Plugin Autoclonetype" - // New tests from the plugin - if (usingPlugin) { - it should "NOT break code that extends chisel3.util Bundles if they use the plugin" in { - class MyModule extends MultiIOModule { - val io = IO(new InheritingBundle) - io.deq <> io.enq - io.count := 0.U - io.error := true.B - } - elaborate(new MyModule) + it should "NOT break code that extends chisel3.util Bundles if they use the plugin" in { + class MyModule extends MultiIOModule { + val io = IO(new InheritingBundle) + io.deq <> io.enq + io.count := 0.U + io.error := true.B } + elaborate(new MyModule) + } - it should "support Bundles with non-val parameters" in { - class MyBundle(i: Int) extends Bundle { - val foo = UInt(i.W) - } - elaborate { new MultiIOModule { - val in = IO(Input(new MyBundle(8))) - val out = IO(Output(new MyBundle(8))) - out := in - }} + it should "support Bundles with non-val parameters" in { + class MyBundle(i: Int) extends Bundle { + val foo = UInt(i.W) } + elaborate { new MultiIOModule { + val in = IO(Input(new MyBundle(8))) + val out = IO(Output(new MyBundle(8))) + out := in + }} + } - it should "support type-parameterized Bundles" in { - class MyBundle[T <: Data](gen: T) extends Bundle { - val foo = gen - } - elaborate { new MultiIOModule { - val in = IO(Input(new MyBundle(UInt(8.W)))) - val out = IO(Output(new MyBundle(UInt(8.W)))) - out := in - }} + it should "support type-parameterized Bundles" in { + class MyBundle[T <: Data](gen: T) extends Bundle { + val foo = gen } + elaborate { new MultiIOModule { + val in = IO(Input(new MyBundle(UInt(8.W)))) + val out = IO(Output(new MyBundle(UInt(8.W)))) + out := in + }} + } - it should "support Bundles with non-val implicit parameters" in { - class MyBundle(implicit i: Int) extends Bundle { - val foo = UInt(i.W) - } - elaborate { new MultiIOModule { - implicit val x = 8 - val in = IO(Input(new MyBundle)) - val out = IO(Output(new MyBundle)) - out := in - }} + it should "support Bundles with non-val implicit parameters" in { + class MyBundle(implicit i: Int) extends Bundle { + val foo = UInt(i.W) } + elaborate { new MultiIOModule { + implicit val x = 8 + val in = IO(Input(new MyBundle)) + val out = IO(Output(new MyBundle)) + out := in + }} + } - it should "support Bundles with multiple parameter lists" in { - class MyBundle(i: Int)(j: Int, jj: Int)(k: UInt) extends Bundle { - val foo = UInt((i + j + jj + k.getWidth).W) - } - elaborate { - new MultiIOModule { - val in = IO(Input(new MyBundle(8)(8, 8)(UInt(8.W)))) - val out = IO(Output(new MyBundle(8)(8, 8)(UInt(8.W)))) - out := in - } + it should "support Bundles with multiple parameter lists" in { + class MyBundle(i: Int)(j: Int, jj: Int)(k: UInt) extends Bundle { + val foo = UInt((i + j + jj + k.getWidth).W) + } + elaborate { + new MultiIOModule { + val in = IO(Input(new MyBundle(8)(8, 8)(UInt(8.W)))) + val out = IO(Output(new MyBundle(8)(8, 8)(UInt(8.W)))) + out := in } } + } - it should "support Bundles that implement their own cloneType" in { - class MyBundle(i: Int) extends Bundle { - val foo = UInt(i.W) - } - elaborate { new MultiIOModule { - val in = IO(Input(new MyBundle(8))) - val out = IO(Output(new MyBundle(8))) - out := in - }} + it should "support Bundles that implement their own cloneType" in { + class MyBundle(i: Int) extends Bundle { + val foo = UInt(i.W) } + elaborate { new MultiIOModule { + val in = IO(Input(new MyBundle(8))) + val out = IO(Output(new MyBundle(8))) + out := in + }} + } - it should "support Bundles that capture type parameters from their parent scope" in { - class MyModule[T <: Data](gen: T) extends MultiIOModule { - class MyBundle(n: Int) extends Bundle { - val foo = Vec(n, gen) - } - val in = IO(Input(new MyBundle(4))) - val out = IO(Output(new MyBundle(4))) - out := in + it should "support Bundles that capture type parameters from their parent scope" in { + class MyModule[T <: Data](gen: T) extends MultiIOModule { + class MyBundle(n: Int) extends Bundle { + val foo = Vec(n, gen) } - elaborate(new MyModule(UInt(8.W))) + val in = IO(Input(new MyBundle(4))) + val out = IO(Output(new MyBundle(4))) + out := in } + elaborate(new MyModule(UInt(8.W))) + } - it should "work for higher-kinded types" in { - class DataGen[T <: Data](gen: T) { - def newType: T = gen.cloneType - } - class MyBundle[A <: Data, B <: DataGen[A]](gen: B) extends Bundle { - val foo = gen.newType - } - class MyModule extends MultiIOModule { - val io = IO(Output(new MyBundle[UInt, DataGen[UInt]](new DataGen(UInt(3.W))))) - io.foo := 0.U - } - elaborate(new MyModule) + it should "work for higher-kinded types" in { + class DataGen[T <: Data](gen: T) { + def newType: T = gen.cloneType + } + class MyBundle[A <: Data, B <: DataGen[A]](gen: B) extends Bundle { + val foo = gen.newType + } + class MyModule extends MultiIOModule { + val io = IO(Output(new MyBundle[UInt, DataGen[UInt]](new DataGen(UInt(3.W))))) + io.foo := 0.U } + elaborate(new MyModule) } } diff --git a/src/test/scala/chiselTests/AutoNestedCloneSpec.scala b/src/test/scala/chiselTests/AutoNestedCloneSpec.scala index 401766e2..258d0823 100644 --- a/src/test/scala/chiselTests/AutoNestedCloneSpec.scala +++ b/src/test/scala/chiselTests/AutoNestedCloneSpec.scala @@ -3,6 +3,7 @@ package chiselTests import chisel3._ import chisel3.testers.TestUtils +import chisel3.stage.ChiselStage.elaborate import org.scalatest.matchers.should.Matchers class BundleWithAnonymousInner(val w: Int) extends Bundle { @@ -11,10 +12,7 @@ class BundleWithAnonymousInner(val w: Int) extends Bundle { } } -// TODO all `.suggestNames` are due to https://github.com/chipsalliance/chisel3/issues/1802 class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils { - val usingPlugin: Boolean = TestUtils.usingPlugin - val elaborate = TestUtils.elaborateNoReflectiveAutoCloneType _ behavior of "autoCloneType of inner Bundle in Chisel3" @@ -27,7 +25,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils { } def getIO: InnerIOType = new InnerIOType } - val io = IO(new Bundle {}).suggestName("io") + val io = IO(new Bundle {}) val myWire = Wire((new Middle(w)).getIO) } new Outer(2) @@ -37,7 +35,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils { it should "clone an anonymous inner bundle successfully" in { elaborate { class TestTop(val w: Int) extends Module { - val io = IO(new Bundle {}).suggestName("io") + val io = IO(new Bundle {}) val myWire = Wire(new Bundle{ val a = UInt(w.W) }) } new TestTop(2) @@ -50,13 +48,13 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils { val io = IO(new Bundle{ val in = Input(UInt(w.W)) val out = Output(UInt(w.W)) - }).suggestName("io") + }) } class Outer(val w: Int) extends Module { val io = IO(new Bundle{ val in = Input(UInt(w.W)) val out = Output(UInt(w.W)) - }).suggestName("io") + }) val i = Module(new Inner(w)) val iw = Wire(chiselTypeOf(i.io)) iw <> io @@ -69,7 +67,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils { it should "clone an anonymous, bound, inner bundle of another bundle successfully" in { elaborate { class TestModule(w: Int) extends Module { - val io = IO(new BundleWithAnonymousInner(w) ).suggestName("io") + val io = IO(new BundleWithAnonymousInner(w)) val w0 = WireDefault(io) val w1 = WireDefault(io.inner) } @@ -85,7 +83,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils { } val io = IO(new Bundle { val inner = Input(bun) - }).suggestName("io") + }) val w0 = WireDefault(io) val w1 = WireDefault(io.inner) } @@ -100,42 +98,39 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils { val inner = Input(new Bundle { val x = UInt(8.W) }) - }).suggestName("io") + }) } new TestModule() } } - if (usingPlugin) { - // This works with the plugin, but is a null pointer exception when using reflective autoclonetype - it should "support an anonymous doubly-nested inner bundle" in { - elaborate { - class Outer(val w: Int) extends Module { - class Middle(val w: Int) { - def getIO: Bundle = new Bundle { - val in = Input(UInt(w.W)) - } + it should "support an anonymous doubly-nested inner bundle" in { + elaborate { + class Outer(val w: Int) extends Module { + class Middle(val w: Int) { + def getIO: Bundle = new Bundle { + val in = Input(UInt(w.W)) } - val io = IO(new Bundle {}).suggestName("io") - val myWire = Wire((new Middle(w)).getIO) } - new Outer(2) + val io = IO(new Bundle {}) + val myWire = Wire((new Middle(w)).getIO) } + new Outer(2) } + } - it should "support anonymous Inner bundles that capture type parameters from outer Bundles" in { - elaborate(new MultiIOModule { - class MyBundle[T <: Data](n: Int, gen: T) extends Bundle { - val foo = new Bundle { - val x = Input(Vec(n, gen)) - } - val bar = Output(Option(new { def mkBundle = new Bundle { val x = Vec(n, gen) }}).get.mkBundle) + it should "support anonymous Inner bundles that capture type parameters from outer Bundles" in { + elaborate(new MultiIOModule { + class MyBundle[T <: Data](n: Int, gen: T) extends Bundle { + val foo = new Bundle { + val x = Input(Vec(n, gen)) } - val io = IO(new MyBundle(4, UInt(8.W))) - val myWire = WireInit(io.foo) - val myWire2 = WireInit(io.bar) - io.bar.x := io.foo.x - }) - } + val bar = Output(Option(new { def mkBundle = new Bundle { val x = Vec(n, gen) }}).get.mkBundle) + } + val io = IO(new MyBundle(4, UInt(8.W))) + val myWire = WireInit(io.foo) + val myWire2 = WireInit(io.bar) + io.bar.x := io.foo.x + }) } } -- cgit v1.2.3 From 9dfee489b15642745174d191181ebf6f570db3ca Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Wed, 1 Dec 2021 16:09:34 -0800 Subject: Refactor Data.toString (#2197) Provides a more intuitive implementation of toString for Data. Utilizes the fact that the compiler plugin provides names earlier than Chisel had in the past so we can accurately guess the name of signals even in the currently elaborating module. Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig --- src/test/scala/chiselTests/DataPrint.scala | 56 +++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/DataPrint.scala b/src/test/scala/chiselTests/DataPrint.scala index b5f96c4d..7fb790a8 100644 --- a/src/test/scala/chiselTests/DataPrint.scala +++ b/src/test/scala/chiselTests/DataPrint.scala @@ -20,6 +20,14 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers { val b = Bool() } + class PartialBundleTest extends Bundle { + val a = UInt(8.W) + val b = Bool() + val c = SInt(8.W) + val e = FixedPoint(5.W, 3.BP) + val f = EnumTest.Type() + } + "Data types" should "have a meaningful string representation" in { ChiselStage.elaborate { new RawModule { UInt().toString should be ("UInt") @@ -31,18 +39,20 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers { Vec(3, UInt(2.W)).toString should be ("UInt<2>[3]") EnumTest.Type().toString should be ("EnumTest") (new BundleTest).toString should be ("BundleTest") - } } + new Bundle { val a = UInt(8.W) }.toString should be ("AnonymousBundle") + new Bundle { val a = UInt(8.W) }.a.toString should be ("UInt<8>") + }} } class BoundDataModule extends Module { // not in the test to avoid anon naming suffixes - Wire(UInt()).toString should be("UInt(Wire in BoundDataModule)") - Reg(SInt()).toString should be("SInt(Reg in BoundDataModule)") + Wire(UInt()).toString should be("BoundDataModule.?: Wire[UInt]") + Reg(SInt()).toString should be("BoundDataModule.?: Reg[SInt]") val io = IO(Output(Bool())) // needs a name so elaboration doesn't fail - io.toString should be("Bool(IO in unelaborated BoundDataModule)") + io.toString should be("BoundDataModule.io: IO[Bool]") val m = Mem(4, UInt(2.W)) - m(2).toString should be("UInt<2>(MemPort in BoundDataModule)") - (2.U + 2.U).toString should be("UInt<2>(OpResult in BoundDataModule)") - Wire(Vec(3, UInt(2.W))).toString should be ("UInt<2>[3](Wire in BoundDataModule)") + m(2).toString should be("BoundDataModule.?: MemPort[UInt<2>]") + (2.U + 2.U).toString should be("BoundDataModule.?: OpResult[UInt<2>]") + Wire(Vec(3, UInt(2.W))).toString should be ("BoundDataModule.?: Wire[UInt<2>[3]]") class InnerModule extends Module { val io = IO(Output(new Bundle { @@ -50,8 +60,31 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers { })) } val inner = Module(new InnerModule) - inner.clock.toString should be ("Clock(IO clock in InnerModule)") - inner.io.a.toString should be ("UInt<4>(IO io_a in InnerModule)") + inner.clock.toString should be ("InnerModule.clock: IO[Clock]") + inner.io.a.toString should be ("InnerModule.io.a: IO[UInt<4>]") + + class FooTypeTest extends Bundle { + val foo = Vec(2, UInt(8.W)) + val fizz = UInt(8.W) + } + val tpe = new FooTypeTest + val fooio: FooTypeTest = IO(Input(tpe)) + fooio.foo(0).toString should be ("BoundDataModule.fooio.foo[0]: IO[UInt<8>]") + + class NestedBundle extends Bundle { + val nestedFoo = UInt(8.W) + val nestedFooVec = Vec(2, UInt(8.W)) + } + class NestedType extends Bundle { + val foo = new NestedBundle + } + + val nestedTpe = new NestedType + val nestedio = IO(Input(nestedTpe)) + (nestedio.foo.nestedFoo.toString should be + ("BoundDataModule.nestedio.foo.nestedFoo: IO[UInt<8>]")) + (nestedio.foo.nestedFooVec(0).toString should be + ("BoundDataModule.nestedio.foo.nestedFooVec[0]: IO[UInt<8>]")) } "Bound data types" should "have a meaningful string representation" in { @@ -67,13 +100,12 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers { true.B.toString should be ("Bool(true)") 2.25.F(6.W, 2.BP).toString should be ("FixedPoint<6><<2>>(2.25)") -2.25.F(6.W, 2.BP).toString should be ("FixedPoint<6><<2>>(-2.25)") + Vec(3, UInt(4.W)).toString should be ("UInt<4>[3]") EnumTest.sNone.toString should be ("EnumTest(0=sNone)") EnumTest.sTwo.toString should be ("EnumTest(2=sTwo)") EnumTest(1.U).toString should be ("EnumTest(1=sOne)") (new BundleTest).Lit(_.a -> 2.U, _.b -> false.B).toString should be ("BundleTest(a=UInt<8>(2), b=Bool(false))") - new Bundle { - val a = UInt(8.W) - }.toString should be ("AnonymousBundle") + (new PartialBundleTest).Lit().toString should be ("PartialBundleTest(a=UInt<8>(DontCare), b=Bool(DontCare), c=SInt<8>(DontCare), e=FixedPoint<5><<3>>(DontCare), f=EnumTest(DontCare))") DontCare.toString should be ("DontCare()") } } } -- cgit v1.2.3 From 08271081e4af2025fc6c6af97511fd110ef65e5c Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 8 Dec 2021 14:21:44 -0800 Subject: Implement DataViews for Seq and Tuple (#2277) * DataProducts for Seq and Tuple2-10 in DataProduct companion object * DataViews for Seq and Tuple 2-10 in DataView companion object * HWTuple2-10 Bundles in chisel3.experimental * Implicit conversions from Seq to Vec and Tuple to HWTuple in chisel3.experimental.conversions--- .../chisel3/experimental/conversions/package.scala | 128 ++++++++++++++++ .../scala/chiselTests/experimental/DataView.scala | 102 +------------ .../experimental/DataViewTargetSpec.scala | 3 +- .../scala/chiselTests/experimental/Tuple.scala | 163 +++++++++++++++++++++ .../experimental/hierarchy/InstanceSpec.scala | 2 +- 5 files changed, 299 insertions(+), 99 deletions(-) create mode 100644 src/main/scala/chisel3/experimental/conversions/package.scala create mode 100644 src/test/scala/chiselTests/experimental/Tuple.scala (limited to 'src') diff --git a/src/main/scala/chisel3/experimental/conversions/package.scala b/src/main/scala/chisel3/experimental/conversions/package.scala new file mode 100644 index 00000000..574f9f96 --- /dev/null +++ b/src/main/scala/chisel3/experimental/conversions/package.scala @@ -0,0 +1,128 @@ + +package chisel3.experimental + +import chisel3._ +import chisel3.experimental.dataview._ +import scala.language.implicitConversions + +/** Implicit conversions from some Scala standard library types and [[Data]] + * + * @note As this leans heavily on the experimental [[DataView]] feature, these APIs are experimental and subject to change + */ +package object conversions { + + /** Implicit conversion between `Seq` and `Vec` */ + implicit def seq2vec[A : DataProduct, B <: Data](xs: Seq[A])(implicit dv: DataView[A, B]): Vec[B] = + xs.viewAs[Vec[B]] + + /** Implicit conversion between [[Tuple2]] and [[HWTuple2]] */ + implicit def tuple2hwtuple[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data]( + tup: (T1, T2) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2] + ): HWTuple2[V1, V2] = { + tup.viewAs[HWTuple2[V1, V2]] + } + + /** Implicit conversion between [[Tuple3]] and [[HWTuple3]] */ + implicit def tuple3hwtuple[T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, V1 <: Data, V2 <: Data, V3 <: Data]( + tup: (T1, T2, T3) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3] + ): HWTuple3[V1, V2, V3] = { + tup.viewAs[HWTuple3[V1, V2, V3]] + } + + /** Implicit conversion between [[Tuple4]] and [[HWTuple4]] */ + implicit def tuple4hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data + ]( + tup: (T1, T2, T3, T4) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4] + ): HWTuple4[V1, V2, V3, V4] = { + tup.viewAs[HWTuple4[V1, V2, V3, V4]] + } + + /** Implicit conversion between [[Tuple5]] and [[HWTuple5]] */ + implicit def tuple5hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data + ]( + tup: (T1, T2, T3, T4, T5) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5] + ): HWTuple5[V1, V2, V3, V4, V5] = { + tup.viewAs[HWTuple5[V1, V2, V3, V4, V5]] + } + + /** Implicit conversion between [[Tuple6]] and [[HWTuple6]] */ + implicit def tuple6hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, T6 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data + ]( + tup: (T1, T2, T3, T4, T5, T6) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5], + v6: DataView[T6, V6] + ): HWTuple6[V1, V2, V3, V4, V5, V6] = { + tup.viewAs[HWTuple6[V1, V2, V3, V4, V5, V6]] + } + + /** Implicit conversion between [[Tuple7]] and [[HWTuple7]] */ + implicit def tuple7hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, T7 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data + ]( + tup: (T1, T2, T3, T4, T5, T6, T7) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5], + v6: DataView[T6, V6], v7: DataView[T7, V7] + ): HWTuple7[V1, V2, V3, V4, V5, V6, V7] = { + tup.viewAs[HWTuple7[V1, V2, V3, V4, V5, V6, V7]] + } + + /** Implicit conversion between [[Tuple8]] and [[HWTuple8]] */ + implicit def tuple8hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data + ]( + tup: (T1, T2, T3, T4, T5, T6, T7, T8) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5], + v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8] + ): HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8] = { + tup.viewAs[HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8]] + } + + /** Implicit conversion between [[Tuple9]] and [[HWTuple9]] */ + implicit def tuple9hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data + ]( + tup: (T1, T2, T3, T4, T5, T6, T7, T8, T9) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5], + v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], v9: DataView[T9, V9] + ): HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9] = { + tup.viewAs[HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9]] + } + + /** Implicit conversion between [[Tuple10]] and [[HWTuple10]] */ + implicit def tuple10hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct, T10 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data, V10 <: Data + ]( + tup: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5], + v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], v9: DataView[T9, V9], v10: DataView[T10, V10] + ): HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10] = { + tup.viewAs[HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10]] + } +} diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala index d1620e88..399b0cbc 100644 --- a/src/test/scala/chiselTests/experimental/DataView.scala +++ b/src/test/scala/chiselTests/experimental/DataView.scala @@ -5,7 +5,9 @@ package chiselTests.experimental import chiselTests.ChiselFlatSpec import chisel3._ import chisel3.experimental.dataview._ +import chisel3.experimental.conversions._ import chisel3.experimental.DataMirror.internal.chiselTypeClone +import chisel3.experimental.HWTuple2 import chisel3.stage.ChiselStage import chisel3.util.{Decoupled, DecoupledIO} @@ -50,69 +52,6 @@ object FlatDecoupledDataView { implicit val view2 = view.invert(_ => new FlatDecoupled) } -// This should become part of Chisel in a later PR -object Tuple2DataProduct { - implicit def tuple2DataProduct[A : DataProduct, B : DataProduct] = new DataProduct[(A, B)] { - def dataIterator(tup: (A, B), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val (a, b) = tup - dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2") - } - } -} - -// This should become part of Chisel in a later PR -object HWTuple { - import Tuple2DataProduct._ - - class HWTuple2[A <: Data, B <: Data](val _1: A, val _2: B) extends Bundle - - implicit def view[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data]( - implicit v1: DataView[T1, V1], v2: DataView[T2, V2] - ): DataView[(T1, T2), HWTuple2[V1, V2]] = - DataView.mapping( - { case (a, b) => new HWTuple2(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType)}, - { case ((a, b), hwt) => - Seq(a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2) - } - ) - - implicit def tuple2hwtuple[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data]( - tup: (T1, T2))(implicit v1: DataView[T1, V1], v2: DataView[T2, V2] - ): HWTuple2[V1, V2] = tup.viewAs[HWTuple2[V1, V2]] -} - -// This should become part of Chisel in a later PR -object SeqDataProduct { - // Should we special case Seq[Data]? - implicit def seqDataProduct[A : DataProduct]: DataProduct[Seq[A]] = new DataProduct[Seq[A]] { - def dataIterator(a: Seq[A], path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - a.iterator - .zipWithIndex - .flatMap { case (elt, idx) => - dpa.dataIterator(elt, s"$path[$idx]") - } - } - } -} - -object SeqToVec { - import SeqDataProduct._ - - // TODO this would need a better way to determine the prototype for the Vec - implicit def seqVec[A : DataProduct, B <: Data](implicit dv: DataView[A, B]): DataView[Seq[A], Vec[B]] = - DataView.mapping[Seq[A], Vec[B]]( - xs => Vec(xs.size, chiselTypeClone(xs.head.viewAs[B])), // xs.head is not correct in general - { case (s, v) => s.zip(v).map { case (a, b) => a.viewAs[B] -> b } } - ) - - implicit def seq2Vec[A : DataProduct, B <: Data](xs: Seq[A])(implicit dv: DataView[A, B]): Vec[B] = - xs.viewAs[Vec[B]] -} - class DataViewSpec extends ChiselFlatSpec { behavior of "DataView" @@ -327,15 +266,14 @@ class DataViewSpec extends ChiselFlatSpec { chirrtl should include ("z.fizz <= b.foo") } - // This example should be turned into a built-in feature - it should "enable implementing \"HardwareTuple\"" in { - import HWTuple._ - + it should "enable using Seq like Data" in { class MyModule extends Module { val a, b, c, d = IO(Input(UInt(8.W))) val sel = IO(Input(Bool())) val y, z = IO(Output(UInt(8.W))) - (y, z) := Mux(sel, (a, b), (c, d)) + // Unclear why the implicit conversion does not work in this case for Seq + // That being said, it's easy enough to cast via `.viewAs` with or without + Seq(y, z) := Mux(sel, Seq(a, b).viewAs, Seq(c, d).viewAs[Vec[UInt]]) } // Verilog instead of CHIRRTL because the optimizations make it much prettier val verilog = ChiselStage.emitVerilog(new MyModule) @@ -343,25 +281,8 @@ class DataViewSpec extends ChiselFlatSpec { verilog should include ("assign z = sel ? b : d;") } - it should "support nesting of tuples" in { - import Tuple2DataProduct._ - import HWTuple._ - - class MyModule extends Module { - val a, b, c, d = IO(Input(UInt(8.W))) - val w, x, y, z = IO(Output(UInt(8.W))) - ((w, x), (y, z)) := ((a, b), (c, d)) - } - val chirrtl = ChiselStage.emitChirrtl(new MyModule) - chirrtl should include ("w <= a") - chirrtl should include ("x <= b") - chirrtl should include ("y <= c") - chirrtl should include ("z <= d") - } - // This example should be turned into a built-in feature it should "enable viewing Seqs as Vecs" in { - import SeqToVec._ class MyModule extends Module { val a, b, c = IO(Input(UInt(8.W))) @@ -376,11 +297,6 @@ class DataViewSpec extends ChiselFlatSpec { } it should "support recursive composition of views" in { - import Tuple2DataProduct._ - import SeqDataProduct._ - import SeqToVec._ - import HWTuple._ - class MyModule extends Module { val a, b, c, d = IO(Input(UInt(8.W))) val w, x, y, z = IO(Output(UInt(8.W))) @@ -398,10 +314,6 @@ class DataViewSpec extends ChiselFlatSpec { } it should "error if you try to dynamically index a Vec view" in { - import SeqDataProduct._ - import SeqToVec._ - import Tuple2DataProduct._ - import HWTuple._ class MyModule extends Module { val inA, inB = IO(Input(UInt(8.W))) @@ -434,7 +346,6 @@ class DataViewSpec extends ChiselFlatSpec { } it should "error if the mapping is non-total in the target" in { - import Tuple2DataProduct._ implicit val dv = DataView[(UInt, UInt), UInt](_ => UInt(), _._1 -> _) class MyModule extends Module { val a, b = IO(Input(UInt(8.W))) @@ -533,7 +444,6 @@ class DataViewSpec extends ChiselFlatSpec { } it should "NOT error if the mapping is non-total in the target" in { - import Tuple2DataProduct._ implicit val dv = PartialDataView[(UInt, UInt), UInt](_ => UInt(), _._2 -> _) class MyModule extends Module { val a, b = IO(Input(UInt(8.W))) diff --git a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala index 92091631..a17b0f40 100644 --- a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala +++ b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala @@ -4,8 +4,8 @@ package chiselTests.experimental import chisel3._ import chisel3.experimental.dataview._ +import chisel3.experimental.conversions._ import chisel3.experimental.{ChiselAnnotation, annotate} -import chisel3.stage.ChiselStage import chiselTests.ChiselFlatSpec object DataViewTargetSpec { @@ -127,7 +127,6 @@ class DataViewTargetSpec extends ChiselFlatSpec { } it should "support annotating views that cannot be mapped to a single ReferenceTarget" in { - import HWTuple._ class MyBundle extends Bundle { val a, b = Input(UInt(8.W)) val c, d = Output(UInt(8.W)) diff --git a/src/test/scala/chiselTests/experimental/Tuple.scala b/src/test/scala/chiselTests/experimental/Tuple.scala new file mode 100644 index 00000000..5f897fbc --- /dev/null +++ b/src/test/scala/chiselTests/experimental/Tuple.scala @@ -0,0 +1,163 @@ +// See LICENSE for license details. + +package chiselTests.experimental + +import chiselTests.ChiselFlatSpec +import chisel3._ +import chisel3.experimental.conversions._ +import chisel3.stage.ChiselStage + +class TupleSpec extends ChiselFlatSpec { + + behavior of "Tuple" + + it should "enable using Tuple2 like Data" in { + class MyModule extends Module { + val a, b, c, d = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val y, z = IO(Output(UInt(8.W))) + (y, z) := Mux(sel, (a, b), (c, d)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + verilog should include ("assign y = sel ? a : c;") + verilog should include ("assign z = sel ? b : d;") + } + + it should "support nesting of tuples" in { + class MyModule extends Module { + val a, b, c, d = IO(Input(UInt(8.W))) + val w, x, y, z = IO(Output(UInt(8.W))) + ((w, x), (y, z)) := ((a, b), (c, d)) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + chirrtl should include ("w <= a") + chirrtl should include ("x <= b") + chirrtl should include ("y <= c") + chirrtl should include ("z <= d") + } + + it should "enable using Tuple3 like Data" in { + class MyModule extends Module { + val a, b, c = IO(Input(UInt(8.W))) + val f, g, h = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val v, w, x = IO(Output(UInt(8.W))) + (v, w, x) := Mux(sel, (a, b, c), (f, g, h)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + verilog should include ("assign v = sel ? a : f;") + verilog should include ("assign w = sel ? b : g;") + verilog should include ("assign x = sel ? c : h;") + } + + it should "enable using Tuple4 like Data" in { + class MyModule extends Module { + val a, b, c, d = IO(Input(UInt(8.W))) + val f, g, h, i = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val v, w, x, y = IO(Output(UInt(8.W))) + (v, w, x, y) := Mux(sel, (a, b, c, d), (f, g, h, i)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + verilog should include ("assign v = sel ? a : f;") + verilog should include ("assign w = sel ? b : g;") + verilog should include ("assign x = sel ? c : h;") + verilog should include ("assign y = sel ? d : i;") + } + + it should "enable using Tuple5 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4) := Mux(sel, (a0, a1, a2, a3, a4), (b0, b1, b2, b3, b4)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 5) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple6 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5) := Mux(sel, (a0, a1, a2, a3, a4, a5), (b0, b1, b2, b3, b4, b5)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 6) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple7 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5, a6 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5, b6 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5, z6 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5, z6) := Mux(sel, (a0, a1, a2, a3, a4, a5, a6), (b0, b1, b2, b3, b4, b5, b6)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 7) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple8 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5, a6, a7 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5, b6, b7 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5, z6, z7 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5, z6, z7) := Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7), (b0, b1, b2, b3, b4, b5, b6, b7)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 8) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple9 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5, a6, a7, a8 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5, b6, b7, b8 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5, z6, z7, z8 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5, z6, z7, z8) := + Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7, a8), (b0, b1, b2, b3, b4, b5, b6, b7, b8)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 9) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple10 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5, z6, z7, z8, z9 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5, z6, z7, z8, z9) := + Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), (b0, b1, b2, b3, b4, b5, b6, b7, b8, b9)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 10) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + +} diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala index 929e3875..9ceb9b40 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala @@ -629,7 +629,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { } it("7.3: should work with DataView + implicit conversion") { - import chiselTests.experimental.SeqToVec._ + import chisel3.experimental.conversions._ @instantiable class MyModule extends RawModule { private val a = IO(Input(UInt(8.W))) -- cgit v1.2.3 From 849d4a0b7f6f7ea056c5280b9d319dadf5225022 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Thu, 9 Dec 2021 10:25:11 +0800 Subject: catch None.get in BitPat.apply(x: UInt): BitPat (#2276) Co-authored-by: Jack Koenig --- src/main/scala/chisel3/util/BitPat.scala | 1 + src/test/scala/chiselTests/util/BitPatSpec.scala | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index d607be4f..4b94879f 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -89,6 +89,7 @@ object BitPat { * @note the UInt must be a literal */ def apply(x: UInt): BitPat = { + require(x.isLit, s"$x is not a literal, BitPat.apply(x: UInt) only accepts literals") val len = if (x.isWidthKnown) x.getWidth else 0 apply("b" + x.litValue.toString(2).reverse.padTo(len, "0").reverse.mkString) } diff --git a/src/test/scala/chiselTests/util/BitPatSpec.scala b/src/test/scala/chiselTests/util/BitPatSpec.scala index 0c83493f..e14b4496 100644 --- a/src/test/scala/chiselTests/util/BitPatSpec.scala +++ b/src/test/scala/chiselTests/util/BitPatSpec.scala @@ -28,6 +28,14 @@ class BitPatSpec extends AnyFlatSpec with Matchers { (BitPat.Y(4) ## BitPat.dontCare(3) ## BitPat.N(2)).toString should be (s"BitPat(1111???00)") } + it should "throw when BitPat apply to a Hardware" in { + intercept[java.lang.IllegalArgumentException]{ + chisel3.stage.ChiselStage.emitChirrtl(new chisel3.Module { + BitPat(chisel3.Reg(chisel3.Bool())) + }) + } + } + it should "index and return new BitPat" in { val b = BitPat("b1001???") b(0) should be(BitPat.dontCare(1)) -- cgit v1.2.3 From 3f21bbb52363c3105f6a0ff961fa7a411dd0c7ab Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Thu, 9 Dec 2021 11:19:27 -0800 Subject: Better MonoConnect error messages (#2248) Co-authored-by: Megan Wachs --- src/test/scala/chiselTests/ConnectSpec.scala | 35 ++++++++++++++++++++++ src/test/scala/chiselTests/InvalidateAPISpec.scala | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/ConnectSpec.scala b/src/test/scala/chiselTests/ConnectSpec.scala index 367864e6..f9ef5946 100644 --- a/src/test/scala/chiselTests/ConnectSpec.scala +++ b/src/test/scala/chiselTests/ConnectSpec.scala @@ -2,6 +2,8 @@ package chiselTests +import org.scalatest._ + import chisel3._ import chisel3.experimental.{Analog, FixedPoint} import chisel3.stage.ChiselStage @@ -126,4 +128,37 @@ class ConnectSpec extends ChiselPropSpec with Utils { property("Pipe internal connections should succeed") { ChiselStage.elaborate( new PipeInternalWires) } + + property("Connect error messages should have meaningful information") { + class InnerExample extends Module { + val myReg = RegInit(0.U(8.W)) + } + + class OuterAssignExample extends Module { + val inner = Module(new InnerExample()) + inner.myReg := false.B // ERROR + } + + val assignError = the [ChiselException] thrownBy {ChiselStage.elaborate { new OuterAssignExample}} + val expectedAssignError = """.*@: myReg in InnerExample cannot be written from module OuterAssignExample.""" + assignError.getMessage should fullyMatch regex expectedAssignError + + class OuterReadExample extends Module { + val myReg = RegInit(0.U(8.W)) + val inner = Module(new InnerExample()) + myReg := inner.myReg // ERROR + } + + val readError = the [ChiselException] thrownBy {ChiselStage.elaborate { new OuterReadExample }} + val expectedReadError = """.*@: myReg in InnerExample cannot be read from module OuterReadExample.""" + readError.getMessage should fullyMatch regex expectedReadError + + val typeMismatchError = the [ChiselException] thrownBy {ChiselStage.elaborate { new RawModule { + val myUInt = Wire(UInt(4.W)) + val mySInt = Wire(SInt(4.W)) + myUInt := mySInt + }}} + val expectedTypeMismatchError = """.*@: Sink \(UInt<4>\) and Source \(SInt<4>\) have different types.""" + typeMismatchError.getMessage should fullyMatch regex expectedTypeMismatchError + } } diff --git a/src/test/scala/chiselTests/InvalidateAPISpec.scala b/src/test/scala/chiselTests/InvalidateAPISpec.scala index b7db33cc..52ad02b4 100644 --- a/src/test/scala/chiselTests/InvalidateAPISpec.scala +++ b/src/test/scala/chiselTests/InvalidateAPISpec.scala @@ -105,7 +105,7 @@ class InvalidateAPISpec extends ChiselPropSpec with Matchers with BackendCompila ChiselStage.elaborate(new ModuleWithDontCareSink) } } - exception.getMessage should include("DontCare cannot be a connection sink (LHS)") + exception.getMessage should include("DontCare cannot be a connection sink") } property("a DontCare cannot be a connection sink (LHS) for <>") { -- cgit v1.2.3 From 630d05bdca90ec1c80eaaa7834e755f51095463d Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 10 Dec 2021 15:56:56 -0800 Subject: Add support for dynamic indexing on Vec identity views (#2298) --- .../scala/chiselTests/experimental/DataView.scala | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala index 399b0cbc..7c5d170b 100644 --- a/src/test/scala/chiselTests/experimental/DataView.scala +++ b/src/test/scala/chiselTests/experimental/DataView.scala @@ -313,8 +313,26 @@ class DataViewSpec extends ChiselFlatSpec { verilog should include ("assign z = d;") } - it should "error if you try to dynamically index a Vec view" in { + it should "support dynamic indexing for Vec identity views" in { + class MyModule extends Module { + val dataIn = IO(Input(UInt(8.W))) + val addr = IO(Input(UInt(2.W))) + val dataOut = IO(Output(UInt(8.W))) + + val vec = RegInit(0.U.asTypeOf(Vec(4, UInt(8.W)))) + val view = vec.viewAs[Vec[UInt]] + // Dynamic indexing is more of a "generator" in Chisel3 than an individual node + // This style is not recommended, this is just testing the behavior + val selected = view(addr) + selected := dataIn + dataOut := selected + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + chirrtl should include ("vec[addr] <= dataIn") + chirrtl should include ("dataOut <= vec[addr]") + } + it should "error if you try to dynamically index a Vec view that does not correspond to a Vec target" in { class MyModule extends Module { val inA, inB = IO(Input(UInt(8.W))) val outA, outB = IO(Output(UInt(8.W))) @@ -323,6 +341,7 @@ class DataViewSpec extends ChiselFlatSpec { val a, b, c, d = RegInit(0.U) // Dynamic indexing is more of a "generator" in Chisel3 than an individual node + // This style is not recommended, this is just testing the behavior val selected = Seq((a, b), (c, d)).apply(idx) selected := (inA, inB) (outA, outB) := selected -- cgit v1.2.3 From 55cb58877aca898f1ccae5edf29aeede9d1b71ba Mon Sep 17 00:00:00 2001 From: Øyvind Harboe Date: Sat, 11 Dec 2021 04:39:27 +0100 Subject: reduceTree() now operates on Seq (#2292) preserves input/output information of the type being reduced. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- src/test/scala/chiselTests/Vec.scala | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src') diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala index 97aea909..24ba0bf8 100644 --- a/src/test/scala/chiselTests/Vec.scala +++ b/src/test/scala/chiselTests/Vec.scala @@ -313,6 +313,36 @@ class ModuleIODynamicIndexTester(n: Int) extends BasicTester { when (done) { stop() } } +class ReduceTreeTester() extends BasicTester { + class FooIO[T <: Data](n: Int, private val gen: T) extends Bundle { + val in = Flipped(Vec(n, new DecoupledIO(gen))) + val out = new DecoupledIO(gen) + } + + class Foo[T <: Data](n: Int, private val gen: T) extends Module { + val io = IO(new FooIO(n, gen)) + + def foo(a: DecoupledIO[T], b: DecoupledIO[T]) = { + a.ready := true.B + b.ready := true.B + val out = Wire(new DecoupledIO(gen)) + + out.valid := true.B + + val regSel = RegInit(false.B) + out.bits := Mux(regSel, a.bits, b.bits) + out.ready := a.ready + out + } + + io.out <> io.in.reduceTree(foo) + } + + val dut = Module(new Foo(5, UInt(5.W))) + dut.io := DontCare + stop() +} + class VecSpec extends ChiselPropSpec with Utils { // Disable shrinking on error. implicit val noShrinkListVal = Shrink[List[Int]](_ => Stream.empty) @@ -456,4 +486,8 @@ class VecSpec extends ChiselPropSpec with Utils { }} } } + + property("reduceTree should preserve input/output type") { + assertTesterPasses { new ReduceTreeTester() } + } } -- cgit v1.2.3 From 36506c527ff0f51636beee4160f0ce1f6ad2f90a Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Wed, 15 Dec 2021 15:53:52 +0800 Subject: Refactor TruthTable to use Seq (#2217) This makes the resulting Verilog from decoding a TruthTable deterministic.--- src/main/scala/chisel3/util/BitPat.scala | 6 +++ .../experimental/decode/EspressoMinimizer.scala | 3 +- .../util/experimental/decode/QMCMinimizer.scala | 10 ++--- .../util/experimental/decode/TruthTable.scala | 47 +++++++++++----------- .../chisel3/util/experimental/decode/decoder.scala | 2 +- .../util/experimental/TruthTableSpec.scala | 31 +++++++++++--- 6 files changed, 62 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 4b94879f..4f8ae504 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -8,6 +8,12 @@ import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} object BitPat { + + private[chisel3] implicit val bitPatOrder = new Ordering[BitPat] { + import scala.math.Ordered.orderingToOrdered + def compare(x: BitPat, y: BitPat): Int = (x.getWidth, x.value, x.mask) compare (y.getWidth, y.value, y.mask) + } + /** Parses a bit pattern string into (bits, mask, width). * * @return bits the literal value, with don't cares being 0 diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala index 6adf544c..4dcea99e 100644 --- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala @@ -55,7 +55,7 @@ object EspressoMinimizer extends Minimizer with LazyLogging { |""".stripMargin ++ (if (defaultType == '1') invertRawTable else rawTable) } - def readTable(espressoTable: String): Map[BitPat, BitPat] = { + def readTable(espressoTable: String) = { def bitPat(espresso: String): BitPat = BitPat("b" + espresso.replace('-', '?')) espressoTable @@ -63,7 +63,6 @@ object EspressoMinimizer extends Minimizer with LazyLogging { .filterNot(_.startsWith(".")) .map(_.split(' ')) .map(row => bitPat(row(0)) -> bitPat(row(1))) - .toMap } 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 8bd8a03e..59120221 100644 --- a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala @@ -234,11 +234,11 @@ object QMCMinimizer extends Minimizer { val outputBp = BitPat("b" + "?" * (m - i - 1) + "1" + "?" * i) // Minterms, implicants that makes the output to be 1 - val mint: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && t.value.testBit(i) }.keys.map(toImplicant).toSeq + val mint: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && t.value.testBit(i) }.map(_._1).map(toImplicant) // Maxterms, implicants that makes the output to be 0 - val maxt: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && !t.value.testBit(i) }.keys.map(toImplicant).toSeq + val maxt: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && !t.value.testBit(i) }.map(_._1).map(toImplicant) // Don't cares, implicants that can produce either 0 or 1 as output - val dc: Seq[Implicant] = table.table.filter { case (_, t) => !t.mask.testBit(i) }.keys.map(toImplicant).toSeq + val dc: Seq[Implicant] = table.table.filter { case (_, t) => !t.mask.testBit(i) }.map(_._1).map(toImplicant) val (implicants, defaultToDc) = table.default match { case x if x.mask.testBit(i) && !x.value.testBit(i) => // default to 0 @@ -291,7 +291,7 @@ object QMCMinimizer extends Minimizer { (essentialPrimeImplicants ++ getCover(nonessentialPrimeImplicants, uncoveredImplicants)).map(a => (a.bp, outputBp)) }) - minimized.tail.foldLeft(table.copy(table = Map(minimized.head))) { case (tb, t) => + 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) { @@ -300,7 +300,7 @@ object QMCMinimizer extends Minimizer { } else (k, v) }) } else { - tb.copy(table = tb.table + t) + tb.copy(table = tb.table :+ t) } } } diff --git a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala index 683de16b..322466f9 100644 --- a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala +++ b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala @@ -4,8 +4,7 @@ package chisel3.util.experimental.decode import chisel3.util.BitPat -final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) { - +sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default: BitPat, val sort: Boolean) { def inputWidth = table.head._1.getWidth def outputWidth = table.head._2.getWidth @@ -14,10 +13,10 @@ final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) { def writeRow(map: (BitPat, BitPat)): String = s"${map._1.rawString}->${map._2.rawString}" - (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${default.rawString}")).toSeq.sorted.mkString("\n") + (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${default.rawString}")).mkString("\n") } - def copy(table: Map[BitPat, BitPat] = this.table, default: BitPat = this.default) = new TruthTable(table, default) + def copy(table: Seq[(BitPat, BitPat)] = this.table, default: BitPat = this.default, sort: Boolean = this.sort) = TruthTable(table, default, sort) override def equals(y: Any): Boolean = { y match { @@ -28,25 +27,12 @@ final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) { } object TruthTable { - /** Parse TruthTable from its string representation. */ - def apply(tableString: String): TruthTable = { - TruthTable( - tableString - .split("\n") - .filter(_.contains("->")) - .map(_.split("->").map(str => BitPat(s"b$str"))) - .map(bps => bps(0) -> bps(1)) - .toSeq, - BitPat(s"b${tableString.split("\n").filterNot(_.contains("->")).head.replace(" ", "")}") - ) - } - /** Convert a table and default output into a [[TruthTable]]. */ - def apply(table: Iterable[(BitPat, BitPat)], default: BitPat): TruthTable = { + def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = { require(table.map(_._1.getWidth).toSet.size == 1, "input width not equal.") require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.") val outputWidth = table.map(_._2.getWidth).head - new TruthTable(table.toSeq.groupBy(_._1.toString).map { case (key, values) => + val mergedTable = table.groupBy(_._1.toString).map { case (key, values) => // merge same input inputs. values.head._1 -> BitPat(s"b${ Seq.tabulate(outputWidth) { i => @@ -59,9 +45,23 @@ object TruthTable { outputSet.headOption.getOrElse('?') }.mkString }") - }, default) + }.toSeq + import BitPat.bitPatOrder + new TruthTable(if(sort) mergedTable.sorted else mergedTable, default, sort) } + /** Parse TruthTable from its string representation. */ + def fromString(tableString: String): TruthTable = { + TruthTable( + tableString + .split("\n") + .filter(_.contains("->")) + .map(_.split("->").map(str => BitPat(s"b$str"))) + .map(bps => bps(0) -> bps(1)) + .toSeq, + BitPat(s"b${tableString.split("\n").filterNot(_.contains("->")).head.replace(" ", "")}") + ) + } /** consume 1 table, split it into up to 3 tables with the same default bits. * @@ -99,18 +99,17 @@ object TruthTable { tables: Seq[(TruthTable, Seq[Int])] ): TruthTable = { def reIndex(bitPat: BitPat, table: TruthTable, indexes: Seq[Int]): Seq[(Char, Int)] = - (table.table.map(a => a._1.toString -> a._2).getOrElse(bitPat.toString, BitPat.dontCare(indexes.size))).rawString.zip(indexes) + table.table.map(a => a._1.toString -> a._2).collectFirst{ case (k, v) if k == bitPat.toString => v}.getOrElse(BitPat.dontCare(indexes.size)).rawString.zip(indexes) def bitPat(indexedChar: Seq[(Char, Int)]) = BitPat(s"b${indexedChar .sortBy(_._2) .map(_._1) .mkString}") TruthTable( tables - .flatMap(_._1.table.keys) + .flatMap(_._1.table.map(_._1)) .map { key => key -> bitPat(tables.flatMap { case (table, indexes) => reIndex(key, table, indexes) }) - } - .toMap, + }, bitPat(tables.flatMap { case (table, indexes) => table.default.rawString.zip(indexes) }) ) } diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala index 42e374d1..ee2ece48 100644 --- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala +++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala @@ -19,7 +19,7 @@ object decoder extends LazyLogging { */ def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable): UInt = { val minimizedTable = getAnnotations().collect { - case DecodeTableAnnotation(_, in, out) => TruthTable(in) -> TruthTable(out) + case DecodeTableAnnotation(_, in, out) => TruthTable.fromString(in) -> TruthTable.fromString(out) }.toMap.getOrElse(truthTable, minimizer.minimize(truthTable)) if (minimizedTable.table.isEmpty) { val outputs = Wire(UInt(minimizedTable.default.getWidth.W)) diff --git a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala index 743a3cd8..255effaf 100644 --- a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala +++ b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala @@ -2,8 +2,9 @@ package chiselTests.util.experimental +import chisel3._ import chisel3.util.BitPat -import chisel3.util.experimental.decode.TruthTable +import chisel3.util.experimental.decode.{TruthTable, decoder} import org.scalatest.flatspec.AnyFlatSpec class TruthTableSpec extends AnyFlatSpec { @@ -34,16 +35,16 @@ class TruthTableSpec extends AnyFlatSpec { assert(table.toString contains " 0") } "TruthTable" should "deserialize" in { - assert(TruthTable(str) == table) + assert(TruthTable.fromString(str) == table) } "TruthTable" should "merge same key" in { assert( - TruthTable( + TruthTable.fromString( """001100->??1 |001100->1?? |??? |""".stripMargin - ) == TruthTable( + ) == TruthTable.fromString( """001100->1?1 |??? |""".stripMargin @@ -52,7 +53,7 @@ class TruthTableSpec extends AnyFlatSpec { } "TruthTable" should "crash when merging 0 and 1" in { intercept[IllegalArgumentException] { - TruthTable( + TruthTable.fromString( """0->0 |0->1 |??? @@ -60,4 +61,24 @@ class TruthTableSpec extends AnyFlatSpec { ) } } + "TruthTable" should "be reproducible" in { + class Foo extends Module { + + val io = IO(new Bundle{ + val in = Input(UInt(4.W)) + val out = Output(UInt(16.W)) + }) + + + val table = TruthTable( + (0 until 16).map{ + i => BitPat(i.U(4.W)) -> BitPat((1< m.a, "b" -> m.b)) }) } + + property("DataMirror.modulePorts should replace deprecated .getPorts") { + class MyModule extends Module { + val io = IO(new Bundle { + val in = Input(UInt(8.W)) + val out = Output(Vec(2, UInt(8.W))) + }) + val extra = IO(Input(UInt(8.W))) + val delay = RegNext(io.in) + io.out(0) := delay + io.out(1) := delay + extra + } + var mod: MyModule = null + ChiselStage.elaborate { + mod = new MyModule + mod + } + // Note that this is just top-level ports, Aggregates are not flattened + DataMirror.modulePorts(mod) should contain theSameElementsInOrderAs Seq( + "clock" -> mod.clock, + "reset" -> mod.reset, + "io" -> mod.io, + "extra" -> mod.extra + ) + // Delete this when the deprecated API is deleted + // Note this also uses deprecated Port + import chisel3.internal.firrtl.Port + import SpecifiedDirection.{Input => IN, Unspecified} + mod.getPorts should contain theSameElementsInOrderAs Seq( + Port(mod.clock, IN), + Port(mod.reset, IN), + Port(mod.io, Unspecified), + Port(mod.extra, IN) + ): @nowarn // delete when Port and getPorts become private + } + + property("DataMirror.fullModulePorts should return all ports including children of Aggregates") { + class MyModule extends Module { + val io = IO(new Bundle { + val in = Input(UInt(8.W)) + val out = Output(Vec(2, UInt(8.W))) + }) + val extra = IO(Input(UInt(8.W))) + val delay = RegNext(io.in) + io.out(0) := delay + io.out(1) := delay + extra + } + var mod: MyModule = null + ChiselStage.elaborate { + mod = new MyModule + mod + } + val expected = Seq( + "clock" -> mod.clock, + "reset" -> mod.reset, + "io" -> mod.io, + "io_out" -> mod.io.out, + "io_out_0" -> mod.io.out(0), + "io_out_1" -> mod.io.out(1), + "io_in" -> mod.io.in, + "extra" -> mod.extra + ) + DataMirror.fullModulePorts(mod) should contain theSameElementsInOrderAs expected + } + property("A desiredName parameterized by a submodule should work") { ChiselStage.elaborate(new ModuleWrapper(new ModuleWire)).name should be ("ModuleWireWrapper") } -- cgit v1.2.3 From 214115a4cdbf0714d3d1716035f5eb0dd98cba45 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Thu, 16 Dec 2021 09:47:05 +0800 Subject: BitSet API (#2211) BitSet is a new experimental parent type for BitPat. It enables more complex operations on BitPats. Co-authored-by: Ocean Shen --- src/main/scala/chisel3/util/BitPat.scala | 210 +++++++++++++++++++-- .../chisel3/util/experimental/decode/decoder.scala | 33 +++- src/test/scala/chiselTests/util/BitPatSpec.scala | 2 +- src/test/scala/chiselTests/util/BitSetSpec.scala | 119 ++++++++++++ 4 files changed, 348 insertions(+), 16 deletions(-) create mode 100644 src/test/scala/chiselTests/util/BitSetSpec.scala (limited to 'src') diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala index 4f8ae504..808245de 100644 --- a/src/main/scala/chisel3/util/BitPat.scala +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -117,6 +117,119 @@ object BitPat { } } +package experimental { + object BitSet { + + /** Construct a [[BitSet]] from a sequence of [[BitPat]]. + * All [[BitPat]] must have the same width. + */ + def apply(bitpats: BitPat*): BitSet = { + val bs = new BitSet { def terms = bitpats.flatMap(_.terms).toSet } + // check width + bs.getWidth + bs + } + + /** Empty [[BitSet]]. */ + val empty: BitSet = new BitSet { + def terms = Set() + } + + /** Construct a [[BitSet]] from String. + * each line should be a valid [[BitPat]] string with the same width. + */ + def fromString(str: String): BitSet = { + val bs = new BitSet { def terms = str.split('\n').map(str => BitPat(str)).toSet } + // check width + bs.getWidth + bs + } + } + + /** A Set of [[BitPat]] represents a set of bit vector with mask. */ + sealed trait BitSet { outer => + /** all [[BitPat]] elements in [[terms]] make up this [[BitSet]]. + * all [[terms]] should be have the same width. + */ + def terms: Set[BitPat] + + /** Get specified width of said BitSet */ + def getWidth: Int = { + require(terms.map(_.width).size <= 1, s"All BitPats must be the same size! Got $this") + // set width = 0 if terms is empty. + terms.headOption.map(_.width).getOrElse(0) + } + + import BitPat.bitPatOrder + override def toString: String = terms.toSeq.sorted.mkString("\n") + + /** whether this [[BitSet]] is empty (i.e. no value matches) */ + def isEmpty: Boolean = terms.forall(_.isEmpty) + + /** Check whether this [[BitSet]] overlap with that [[BitSet]], i.e. !(intersect.isEmpty) + * + * @param that [[BitSet]] to be checked. + * @return true if this and that [[BitSet]] have overlap. + */ + def overlap(that: BitSet): Boolean = + !terms.flatMap(a => that.terms.map(b => (a, b))).forall { case (a, b) => !a.overlap(b) } + + /** Check whether this [[BitSet]] covers that (i.e. forall b matches that, b also matches this) + * + * @param that [[BitSet]] to be covered + * @return true if this [[BitSet]] can cover that [[BitSet]] + */ + def cover(that: BitSet): Boolean = + that.subtract(this).isEmpty + + /** Intersect `this` and `that` [[BitSet]]. + * + * @param that [[BitSet]] to be intersected. + * @return a [[BitSet]] containing all elements of `this` that also belong to `that`. + */ + def intersect(that: BitSet): BitSet = + terms + .flatMap(a => that.terms.map(b => a.intersect(b))) + .filterNot(_.isEmpty) + .fold(BitSet.empty)(_.union(_)) + + /** Subtract that from this [[BitSet]]. + * + * @param that subtrahend [[BitSet]]. + * @return a [[BitSet]] containing elements of `this` which are not the elements of `that`. + */ + def subtract(that: BitSet): BitSet = + terms.map { a => + that.terms.map(b => a.subtract(b)).fold(a)(_.intersect(_)) + }.filterNot(_.isEmpty).fold(BitSet.empty)(_.union(_)) + + /** Union this and that [[BitSet]] + * + * @param that [[BitSet]] to union. + * @return a [[BitSet]] containing all elements of `this` and `that`. + */ + def union(that: BitSet): BitSet = new BitSet { + def terms = outer.terms ++ that.terms + } + + /** Test whether two [[BitSet]] matches the same set of value + * + * @note + * This method can be very expensive compared to ordinary == operator between two Objects + * + * @return true if two [[BitSet]] is same. + */ + override def equals(obj: Any): Boolean = { + obj match { + case that: BitSet => this.getWidth == that.getWidth && this.cover(that) && that.cover(this) + case _ => false + } + } + } + +} + + /** Bit patterns are literals with masks, used to represent values with don't * care bits. Equality comparisons will ignore don't care bits. * @@ -126,19 +239,19 @@ object BitPat { * "b10001".U === BitPat("b101??") // evaluates to false.B * }}} */ -sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends SourceInfoDoc { - def getWidth: Int = width +sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int) extends util.experimental.BitSet with SourceInfoDoc { + import chisel3.util.experimental.BitSet + def terms = Set(this) + + /** + * Get specified width of said BitPat + */ + override def getWidth: Int = width def apply(x: Int): BitPat = macro SourceInfoTransform.xArg def apply(x: Int, y: Int): BitPat = macro SourceInfoTransform.xyArg def === (that: UInt): Bool = macro SourceInfoTransform.thatArg def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg def ## (that: BitPat): BitPat = macro SourceInfoTransform.thatArg - override def equals(obj: Any): Boolean = { - obj match { - case y: BitPat => value == y.value && mask == y.mask && getWidth == y.getWidth - case _ => false - } - } /** @group SourceInfoTransformMacro */ def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): BitPat = { @@ -167,14 +280,83 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends Sou new BitPat((value << that.getWidth) + that.value, (mask << that.getWidth) + that.mask, this.width + that.getWidth) } - /** Generate raw string of a BitPat. */ - def rawString: String = Seq.tabulate(width) { i => + /** Check whether this [[BitPat]] overlap with that [[BitPat]], i.e. !(intersect.isEmpty) + * + * @param that [[BitPat]] to be checked. + * @return true if this and that [[BitPat]] have overlap. + */ + def overlap(that: BitPat): Boolean = ((mask & that.mask) & (value ^ that.value)) == 0 + + /** Check whether this [[BitSet]] covers that (i.e. forall b matches that, b also matches this) + * + * @param that [[BitPat]] to be covered + * @return true if this [[BitSet]] can cover that [[BitSet]] + */ + def cover(that: BitPat): Boolean = (mask & (~that.mask | (value ^ that.value))) == 0 + + /** Intersect `this` and `that` [[BitPat]]. + * + * @param that [[BitPat]] to be intersected. + * @return a [[BitSet]] containing all elements of `this` that also belong to `that`. + */ + def intersect(that: BitPat): BitSet = { + if (!overlap(that)) { + BitSet.empty + } else { + new BitPat(this.value | that.value, this.mask | that.mask, this.width.max(that.width)) + } + } + + /** Subtract a [[BitPat]] from this. + * + * @param that subtrahend [[BitPat]]. + * @return a [[BitSet]] containing elements of `this` which are not the elements of `that`. + */ + def subtract(that: BitPat): BitSet = { + require(width == that.width) + def enumerateBits(mask: BigInt): Seq[BigInt] = { + if (mask == 0) { + Nil + } else { + // bits comes after the first '1' in a number are inverted in its two's complement. + // therefore bit is always the first '1' in x (counting from least significant bit). + val bit = mask & (-mask) + bit +: enumerateBits(mask & ~bit) + } + } + + val intersection = intersect(that) + val omask = this.mask + if (intersection.isEmpty) { + this + } else { + new BitSet { + val terms = + intersection.terms.flatMap { remove => + enumerateBits(~omask & remove.mask).map { bit => + // Only care about higher than current bit in remove + val nmask = (omask | ~(bit - 1)) & remove.mask + val nvalue = (remove.value ^ bit) & nmask + val nwidth = remove.width + new BitPat(nvalue, nmask, nwidth) + } + } + } + } + } + + 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) => "?" + case (true, true) => "1" + case (false, true) => "0" + case (_, false) => "?" + } } - }.mkString + .mkString override def toString = s"BitPat($rawString)" } diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala index ee2ece48..e0bf83b2 100644 --- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala +++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala @@ -5,7 +5,7 @@ package chisel3.util.experimental.decode import chisel3._ import chisel3.experimental.{ChiselAnnotation, annotate} import chisel3.util.{BitPat, pla} -import chisel3.util.experimental.getAnnotations +import chisel3.util.experimental.{BitSet, getAnnotations} import firrtl.annotations.Annotation import logger.LazyLogging @@ -80,4 +80,35 @@ object decoder extends LazyLogging { qmcFallBack(input, truthTable) } } + + + /** Generate a decoder circuit that matches the input to each bitSet. + * + * The resulting circuit functions like the following but is optimized with a logic minifier. + * {{{ + * when(input === bitSets(0)) { output := b000001 } + * .elsewhen (input === bitSets(1)) { output := b000010 } + * .... + * .otherwise { if (errorBit) output := b100000 else output := DontCare } + * }}} + * + * @param input input to the decoder circuit, width should be equal to bitSets.width + * @param bitSets set of ports to be matched, all width should be the equal + * @param errorBit whether generate an additional decode error bit at MSB of output. + * @return decoded wire + */ + def bitset(input: chisel3.UInt, bitSets: Seq[BitSet], errorBit: Boolean = false): chisel3.UInt = + chisel3.util.experimental.decode.decoder( + input, + chisel3.util.experimental.decode.TruthTable.fromString( + { + bitSets.zipWithIndex.flatMap { + case (bs, i) => + bs.terms.map(bp => + s"${bp.rawString}->${if (errorBit) "0"}${"0" * (bitSets.size - i - 1)}1${"0" * i}" + ) + } ++ Seq(s"${if (errorBit) "1"}${"?" * bitSets.size}") + }.mkString("\n") + ) + ) } diff --git a/src/test/scala/chiselTests/util/BitPatSpec.scala b/src/test/scala/chiselTests/util/BitPatSpec.scala index e14b4496..549e8bca 100644 --- a/src/test/scala/chiselTests/util/BitPatSpec.scala +++ b/src/test/scala/chiselTests/util/BitPatSpec.scala @@ -24,7 +24,7 @@ class BitPatSpec extends AnyFlatSpec with Matchers { intercept[IllegalArgumentException]{BitPat("b")} } - it should "contact BitPat via ##" in { + it should "concat BitPat via ##" in { (BitPat.Y(4) ## BitPat.dontCare(3) ## BitPat.N(2)).toString should be (s"BitPat(1111???00)") } diff --git a/src/test/scala/chiselTests/util/BitSetSpec.scala b/src/test/scala/chiselTests/util/BitSetSpec.scala new file mode 100644 index 00000000..8120cc97 --- /dev/null +++ b/src/test/scala/chiselTests/util/BitSetSpec.scala @@ -0,0 +1,119 @@ +package chiselTests.util + +import chisel3.util.experimental.BitSet +import chisel3.util.BitPat +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class BitSetSpec extends AnyFlatSpec with Matchers { + behavior of classOf[BitSet].toString + + it should "reject unequal width when constructing a BitSet" in { + intercept[IllegalArgumentException] { + BitSet.fromString( + """b0010 + |b00010 + |""".stripMargin) + } + } + + it should "return empty subtraction result correctly" in { + val aBitPat = BitPat("b10?") + val bBitPat = BitPat("b1??") + + aBitPat.subtract(bBitPat).isEmpty should be (true) + } + + it should "return nonempty subtraction result correctly" in { + val aBitPat = BitPat("b10?") + val bBitPat = BitPat("b1??") + val cBitPat = BitPat("b11?") + val dBitPat = BitPat("b100") + + val diffBitPat = bBitPat.subtract(aBitPat) + bBitPat.cover(diffBitPat) should be (true) + diffBitPat.equals(cBitPat) should be (true) + + val largerdiffBitPat = bBitPat.subtract(dBitPat) + aBitPat.cover(dBitPat) should be (true) + largerdiffBitPat.cover(diffBitPat) should be (true) + } + + it should "be able to handle complex subtract between BitSet" in { + val aBitSet = BitSet.fromString( + """b?01?0 + |b11111 + |b00000 + |""".stripMargin) + val bBitSet = BitSet.fromString( + """b?1111 + |b?0000 + |""".stripMargin + ) + val expected = BitPat("b?01?0") + + expected.equals(aBitSet.subtract(bBitSet)) should be (true) + } + + it should "be generated from BitPat union" in { + val aBitSet = BitSet.fromString( + """b001?0 + |b000??""".stripMargin) + val aBitPat = BitPat("b000??") + val bBitPat = BitPat("b001?0") + val cBitPat = BitPat("b00000") + aBitPat.cover(cBitPat) should be (true) + aBitSet.cover(bBitPat) should be (true) + + aBitSet.equals(aBitPat.union(bBitPat)) should be (true) + } + + it should "be generated from BitPat subtraction" in { + val aBitSet = BitSet.fromString( + """b001?0 + |b000??""".stripMargin) + val aBitPat = BitPat("b00???") + val bBitPat = BitPat("b001?1") + + aBitSet.equals(aBitPat.subtract(bBitPat)) should be (true) + } + + it should "union two BitSet together" in { + val aBitSet = BitSet.fromString( + """b001?0 + |b001?1 + |""".stripMargin) + val bBitSet = BitSet.fromString( + """b000?? + |b01??? + |""".stripMargin + ) + val cBitPat = BitPat("b0????") + cBitPat.equals(aBitSet.union(bBitSet)) should be (true) + } + + it should "be decoded" in { + import chisel3._ + import chisel3.util.experimental.decode.decoder + // [0 - 256] part into: [0 - 31], [32 - 47, 64 - 127], [192 - 255] + // "0011????" "10??????" is empty to error + chisel3.stage.ChiselStage.emitSystemVerilog(new Module { + val in = IO(Input(UInt(8.W))) + val out = IO(Output(UInt(4.W))) + out := decoder.bitset(in, Seq( + BitSet.fromString( + "b000?????" + ), + BitSet.fromString( + """b0010???? + |b01?????? + |""".stripMargin + ), + BitSet.fromString( + "b11??????" + ) + ), true) + }) + } + +} -- cgit v1.2.3 From 109b4d8629beb62f7516ca14295258b4131f5849 Mon Sep 17 00:00:00 2001 From: Chick Markley Date: Fri, 17 Dec 2021 10:13:54 -0800 Subject: Improve exception message for aliased bundle fields (#2304) - Shows groups of field names that share a common id (i.e. aliased) - Show, as much as possible, them in the order that fields appear in bundle - Updated BundleSpec's relevant tests Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig --- src/test/scala/chiselTests/BundleSpec.scala | 16 ++++++++++------ src/test/scala/chiselTests/RecordSpec.scala | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/test/scala/chiselTests/BundleSpec.scala b/src/test/scala/chiselTests/BundleSpec.scala index 51dedfb1..d9f82e6d 100644 --- a/src/test/scala/chiselTests/BundleSpec.scala +++ b/src/test/scala/chiselTests/BundleSpec.scala @@ -111,17 +111,21 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils { } } - "Bundles" should "not have aliased fields" in { + "Bundles" should "with aliased fields, should show a helpful error message" in { + class AliasedBundle extends Bundle { + val a = UInt(8.W) + val b = a + val c = SInt(8.W) + val d = c + } + (the[ChiselException] thrownBy extractCause[ChiselException] { ChiselStage.elaborate { new Module { - val io = IO(Output(new Bundle { - val a = UInt(8.W) - val b = a - })) + val io = IO(Output(new AliasedBundle)) io.a := 0.U io.b := 1.U } } - }).getMessage should include("aliased fields") + }).getMessage should include("contains aliased fields named (a,b),(c,d)") } "Bundles" should "not have bound hardware" in { diff --git a/src/test/scala/chiselTests/RecordSpec.scala b/src/test/scala/chiselTests/RecordSpec.scala index f0edca8b..e6986efb 100644 --- a/src/test/scala/chiselTests/RecordSpec.scala +++ b/src/test/scala/chiselTests/RecordSpec.scala @@ -8,6 +8,8 @@ import chisel3.testers.BasicTester import chisel3.util.{Counter, Queue} import chisel3.experimental.DataMirror +import scala.collection.immutable.SeqMap + trait RecordSpecUtils { class MyBundle extends Bundle { val foo = UInt(32.W) @@ -64,6 +66,11 @@ trait RecordSpecUtils { } } + class AliasedRecord extends Module { + val field = UInt(32.W) + val io = IO(new CustomBundle("in" -> Input(field), "out" -> Output(field))) + } + class RecordIOModule extends Module { val io = IO(new CustomBundle("in" -> Input(UInt(32.W)), "out" -> Output(UInt(32.W)))) io("out") := io("in") @@ -103,6 +110,23 @@ class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils { ChiselStage.elaborate { new MyModule(new MyBundle, fooBarType) } } + they should "not allow aliased fields" in { + class AliasedFieldRecord extends Record { + val foo = UInt(8.W) + val elements = SeqMap("foo" -> foo, "bar" -> foo) + override def cloneType: AliasedFieldRecord.this.type = this + } + + val e = intercept[AliasedAggregateFieldException] { + ChiselStage.elaborate { + new Module { + val io = IO(new AliasedFieldRecord) + } + } + } + e.getMessage should include ("contains aliased fields named (bar,foo)") + } + they should "follow UInt serialization/deserialization API" in { assertTesterPasses { new RecordSerializationTest } } -- cgit v1.2.3