UCSBarchlab / PyRTL

A collection of classes providing simple hardware specification, simulation, tracing, and testing suitable for teaching and research. Simplicity, usability, clarity, and extensibility are the overarching goals, rather than performance or optimization.
http://ucsbarchlab.github.io/PyRTL
BSD 3-Clause "New" or "Revised" License
257 stars 78 forks source link

Add ability to initialize registers and memories from trace when outputting Verilog testbench #354

Closed mdko closed 3 years ago

mdko commented 3 years ago

Currently, the testbench produced by output_verilog_testbench() sets all registers and memory locations to 0, rather than the values they were initialized to when given a trace.

Before

For example:

import pyrtl

i = pyrtl.Input(2, 'i')
r1 = pyrtl.Register(4, 'r1')
r2 = pyrtl.Register(5)
r3 = pyrtl.Register(2)
m = pyrtl.MemBlock(4, 5)
r2.next <<= r1 + m[4]
m[4] <<= r3 * i
r1.next <<= m[3] + r3
r3.next <<= r1 - 1

sim = pyrtl.Simulation(register_value_map={
    r1: 2,
    r2: 7,
}, memory_value_map={
    m: {
        4: 11,
        3: 7
    }
})

sim.step_multiple({
    'i': [0, 1, 2, 0, 2]  
}, nsteps=5)
sim.tracer.render_trace()
with open("tb.v", "w") as f:
    pyrtl.output_verilog_testbench(f, sim.tracer)

produces the following testbench code:

module tb();
    reg clk;
    reg[1:0] i;

    integer tb_iter;
    toplevel block(.clk(clk), .i(i));

    always
        #5 clk = ~clk;

    initial begin
        $dumpfile ("waveform.vcd");
        $dumpvars;

        clk = 0;
        block.r1 = 0;
        block.tmp0 = 0;
        block.tmp1 = 0;
        for (tb_iter = 0; tb_iter < 32; tb_iter++) begin block.mem_0[tb_iter] = 0; end
        i = 2'd0;

        #10
        i = 2'd1;

        #10
        i = 2'd2;

        #10
        i = 2'd0;

        #10
        i = 2'd2;

        #10
        $finish;
    end
endmodule

After

It now produces:

module tb();
    reg clk;
    reg[1:0] i;

    integer tb_iter;
    toplevel block(.clk(clk), .i(i));

    always
        #5 clk = ~clk;

    initial begin
        $dumpfile ("waveform.vcd");
        $dumpvars;

        clk = 0;
        block.r1 = 2;
        block.tmp0 = 7;
        block.tmp1 = 0;
        for (tb_iter = 0; tb_iter < 32; tb_iter++) begin block.mem_0[tb_iter] = 0; end
        block.mem_0[3] = 7;
        block.mem_0[4] = 11;
        i = 2'd0;

        #10
        i = 2'd1;

        #10
        i = 2'd2;

        #10
        i = 2'd0;

        #10
        i = 2'd2;

        #10
        $finish;
    end
endmodule

Notably, the Python trace:

Screen Shot 2021-04-30 at 7 28 11 PM

didn't match the vcd before:

Screen Shot 2021-04-30 at 7 29 04 PM

but now does:

Screen Shot 2021-04-30 at 7 26 56 PM