diff --git a/fault/verilator_target.py b/fault/verilator_target.py index 0c2f8f31..6734ad60 100644 --- a/fault/verilator_target.py +++ b/fault/verilator_target.py @@ -15,6 +15,10 @@ def flatten(l): src_tpl = """\ {includes} +#if VM_TRACE +VerilatedVcdC* tracer; +#endif + void my_assert( unsigned int got, unsigned int expected, @@ -26,6 +30,9 @@ def flatten(l): std::cerr << \"Expected : \" << expected << std::endl; std::cerr << \"i : \" << i << std::endl; std::cerr << \"Port : \" << port << std::endl; +#if VM_TRACE + tracer->close(); +#endif exit(1); }} }} @@ -34,8 +41,21 @@ def flatten(l): Verilated::commandArgs(argc, argv); V{circuit_name}* top = new V{circuit_name}; +#if VM_TRACE + vluint64_t main_time = 0; + + Verilated::traceEverOn(true); + tracer = new VerilatedVcdC; + top->trace(tracer, 99); + mkdir("logs", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + tracer->open("logs/{circuit_name}.vcd"); +#endif + {main_body} +#if VM_TRACE + tracer->close(); +#endif }} """ @@ -118,12 +138,17 @@ def generate_action_code(i, action): return [f"my_assert(top->{name}, {value}, " f"{i}, \"{action.port.name}\");"] if isinstance(action, actions.Eval): - return ["top->eval();"] + return ["top->eval();", "#if VM_TRACE", "tracer->dump(main_time);", + "main_time++;", "#endif"] if isinstance(action, actions.Step): name = verilator_utils.verilator_name(action.clock.name) code = [] for step in range(action.steps): code.append("top->eval();") + code.append("#if VM_TRACE") + code.append("tracer->dump(main_time);") + code.append("main_time++;") + code.append("#endif") code.append(f"top->{name} ^= 1;") return code raise NotImplementedError(action) @@ -134,6 +159,9 @@ def generate_code(self, actions): f'"V{circuit_name}.h"', '"verilated.h"', '', + '', + '', + '', ] main_body = "" diff --git a/tests/test_verilator_target.py b/tests/test_verilator_target.py index 48053a9d..e8ee29d5 100644 --- a/tests/test_verilator_target.py +++ b/tests/test_verilator_target.py @@ -7,6 +7,7 @@ from fault.actions import Poke, Expect, Eval, Step, Print, Peek from fault.random import random_bv import copy +import os.path def run(circ, actions, flags=[]): @@ -104,3 +105,31 @@ def test_verilator_target_tuple(): Expect(circ.O.b, 11), ] run(circ, actions) + + +def test_verilator_trace(): + circ = common.TestBasicClkCircuit + actions = [ + Poke(circ.I, 0), + Print(circ.I), + Expect(circ.O, 0), + Poke(circ.CLK, 0), + Print(circ.O), + Step(circ.CLK, 1), + Poke(circ.I, BitVector(1, 1)), + Eval(), + Print(circ.O), + ] + flags = ["-Wno-lint", "--trace"] + + with tempfile.TemporaryDirectory() as tempdir: + assert not os.path.isfile(f"{tempdir}/logs/BasicClkCircuit.vcd"), \ + "Expected logs to be empty" + m.compile(f"{tempdir}/{circ.name}", circ, + output="coreir-verilog") + target = fault.verilator_target.VerilatorTarget( + circ, directory=f"{tempdir}/", + flags=flags, skip_compile=True) + target.run(actions) + assert os.path.isfile(f"{tempdir}/logs/BasicClkCircuit.vcd"), \ + "Expected VCD to exist"