def test_verilog_testbench_does_not_throw_error(self): zero = pyrtl.Input(1, 'zero') counter_output = pyrtl.Output(3, 'counter_output') counter = pyrtl.Register(3, 'counter') counter.next <<= pyrtl.mux(zero, counter + 1, 0) counter_output <<= counter sim_trace = pyrtl.SimulationTrace([counter_output, zero]) sim = pyrtl.Simulation(tracer=sim_trace) for cycle in range(15): sim.step({zero: random.choice([0, 0, 0, 1])}) with io.StringIO() as tbfile: pyrtl.output_verilog_testbench(tbfile, sim_trace)
print("--- Simulation Results ---") sim_trace = pyrtl.SimulationTrace([counter_output, zero]) sim = pyrtl.Simulation(tracer=sim_trace) for cycle in range(15): sim.step({'zero': random.choice([0, 0, 0, 1])}) sim_trace.render_trace() # We already did the "hard" work of generating a test input for this simulation, so # we might want to reuse that work when we take this design through a Verilog toolchain. # The class OutputVerilogTestbench grabs the inputs used in the simulation trace # and sets them up in a standard verilog testbench. print("--- Verilog for the TestBench ---") with io.StringIO() as tbfile: pyrtl.output_verilog_testbench(dest_file=tbfile, simulation_trace=sim_trace) print(tbfile.getvalue()) # Now let's talk about transformations of the hardware block. Many times when you are # doing some hardware-level analysis you might wish to ignore higher level things like # multi-bit wirevectors, adds, concatenation, etc. and just think about wires and basic # gates. PyRTL supports "lowering" of designs into this more restricted set of functionality # though the function "synthesize". Once we lower a design to this form we can then apply # basic optimizations like constant propagation and dead wire elimination as well. By # printing it out to Verilog we can see exactly how the design changed. print("--- Optimized Single-bit Verilog for the Counter ---") pyrtl.synthesize() pyrtl.optimize() with io.StringIO() as vfile:
print("--- Simulation Results ---") sim_trace = pyrtl.SimulationTrace([counter_output, zero]) sim = pyrtl.Simulation(tracer=sim_trace) for cycle in range(15): sim.step({zero: random.choice([0, 0, 0, 1])}) sim_trace.render_trace() # We already did the "hard" work of generating a test input for this simulation so # we might want to reuse that work when we take this design through a verilog toolchain. # The function output_verilog_testbench grabs the inputs used in the simulation trace # and sets them up in a standar verilog testbench. print("--- Verilog for the TestBench ---") with io.StringIO() as tbfile: pyrtl.output_verilog_testbench(tbfile, sim_trace) print(tbfile.getvalue()) # Not let's talk about transformations of the hardware block. Many times when you are # doing some hardware-level analysis you might wish to ignore higher level things like # multi-bit wirevectors, adds, concatination, etc. and just thing about wires and basic # gates. PyRTL supports "lowering" of designs into this more restricted set of functionality # though the function "synthesize". Once we lower a design to this form we can then apply # basic optimizations like constant propgation and dead wire elimination as well. By # printing it out to verilog we can see exactly how the design changed. print("--- Optimized Single-bit Verilog for the Counter ---") pyrtl.synthesize() pyrtl.optimize()
print("--- Simulation Results ---") sim_trace = pyrtl.SimulationTrace([counter_output, zero]) sim = pyrtl.Simulation(tracer=sim_trace) for cycle in range(15): sim.step({'zero': random.choice([0, 0, 0, 1])}) sim_trace.render_trace() # We already did the "hard" work of generating a test input for this simulation so # we might want to reuse that work when we take this design through a verilog toolchain. # The class OutputVerilogTestbench grabs the inputs used in the simulation trace # and sets them up in a standard verilog testbench. print("--- Verilog for the TestBench ---") with io.StringIO() as tbfile: pyrtl.output_verilog_testbench(dest_file=tbfile, simulation_trace=sim_trace) print(tbfile.getvalue()) # Not let's talk about transformations of the hardware block. Many times when you are # doing some hardware-level analysis you might wish to ignore higher level things like # multi-bit wirevectors, adds, concatination, etc. and just thing about wires and basic # gates. PyRTL supports "lowering" of designs into this more restricted set of functionality # though the function "synthesize". Once we lower a design to this form we can then apply # basic optimizations like constant propgation and dead wire elimination as well. By # printing it out to verilog we can see exactly how the design changed. print("--- Optimized Single-bit Verilog for the Counter ---") pyrtl.synthesize() pyrtl.optimize()