diff options
| author | Jack | 2021-12-18 08:27:38 +0000 |
|---|---|---|
| committer | Jack | 2021-12-18 08:27:38 +0000 |
| commit | dd9ad534771247ac16eaa47eb9794102736b5102 (patch) | |
| tree | d4566d317cb8526b79017de1e438aea8217dd1d4 /src/test/scala/chiselTests/experimental | |
| parent | 440edc4436fb3a8a4175ae425a0d31c4997ee60f (diff) | |
| parent | f50f74f583fba7b98e550c440df091e559ce32b8 (diff) | |
Merge branch 'master' into 3.5-release
Diffstat (limited to 'src/test/scala/chiselTests/experimental')
9 files changed, 759 insertions, 269 deletions
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala index d1620e88..7c5d170b 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))) @@ -397,12 +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 { - import SeqDataProduct._ - import SeqToVec._ - import Tuple2DataProduct._ - import HWTuple._ + 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))) @@ -411,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 @@ -434,7 +365,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 +463,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/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 <memory> + |#include <verilated.h> + | + |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<VerilatedContext> contextp{new VerilatedContext}; + | contextp->commandArgs(argc, argv); + | const std::unique_ptr<V$topName> 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"))) + } +} 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/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)) } diff --git a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala index 19261c36..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 @@ -258,6 +296,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") { @@ -311,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 { @@ -319,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 23b8c9c0..c0f504ff 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala @@ -36,6 +36,19 @@ object Examples { 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))) @public val out = IO(Output(UInt(32.W))) @@ -58,6 +71,33 @@ object Examples { 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 { + @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 { val in = Input(UInt(32.W)) @@ -183,4 +223,17 @@ 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 + } + @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..9ceb9b40 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 { @@ -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") { @@ -353,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 { @@ -361,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) } @@ -379,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 { @@ -620,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))) @@ -705,5 +714,142 @@ 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) + } + } + 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_1".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_1".it, + )) + rel should be (Seq( + "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it, + "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".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_1>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>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_1>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt, + "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_1>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_1>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_1".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_1>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)) } + } + } } 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") - } -} |
