summaryrefslogtreecommitdiff
path: root/src/test/scala/chiselTests
diff options
context:
space:
mode:
authorJiuyang Liu2021-09-22 02:56:13 +0800
committerGitHub2021-09-21 18:56:13 +0000
commit6e9740efd138523dca3de5a871104f91d884c476 (patch)
treefba91edd5d0c3decfb90e88b973ee4941453deeb /src/test/scala/chiselTests
parent958904cb2f2f65d02b2ab3ec6d9ec2e06d04e482 (diff)
implement trace API. (#2077)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Diffstat (limited to 'src/test/scala/chiselTests')
-rw-r--r--src/test/scala/chiselTests/experimental/TraceSpec.scala309
1 files changed, 309 insertions, 0 deletions
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")))
+ }
+}