-
Notifications
You must be signed in to change notification settings - Fork 77
Netlist Simulator and Waveform Viewer
Note: netlist simulator is currently experiencing a major makeover. The code has not been merged into master yet but can be obtained in branch v4.0.0
The **netlist simulator** enables the reverse engineer to simulate selected parts of the netlist in a cycle-accurate fashion. It operates on a user-defined set of [gates](Gate) and allows for all kinds of customization. The netlist simulator is not build automatically and needs to be enabled before starting the build process using the `-DPL_NETLIST_SIMULATOR=1` flag when calling `cmake`.
- Loading the Plugin
from hal_plugins import netlist_simulator
pl_sim = hal_py.plugin_manager.get_plugin_instance("netlist_simulator")
- Setting up the Simulator
sim = pl_sim.create_simulator()
Now the user must specify the subset of the netlist he wants to simulate. For this purpose, a list of gates must be specified and passed to the simulator instance `sim` such that it can automatically determine input and output [nets](Net) of the subgraph. This can be done using the `add_gates` function as shown below.
gate_list = [g1, g2, g3, g4] # collect gates to simulate in a list
sim.add_gates(gate_list) # add the gates to the simulation instance
As stated before, the simulator will automatically detect all inputs and outputs to the simulated subgraph. Using `get_input_nets` and `get_output_nets`, the user can retrieve those nets and may use them later on to, e.g., set input values during simulation.
sim.get_input_nets() # get all input nets
sim.get_output_nets() # get all output nets
Next, the clock signal needs to be specified. This can be done using either `add_clock_frequency` or `add_clock_period`, which take the net connected to the clock and a clock frequency or period as input. Hence, the function assignes a specific clock frequency to the given net and thus allows for different clock domains.
sim.add_clock_frequency(clk, 1000000) # assign a clock frequency of 1 MHz to input net 'clk'
To avoid getting stuck in infinite loops, it may be helpful to set a iteration timeout that stops the simulation after a pre-defined number of iterations. The timeout is given in number of iterations and can be controlled using `set_iteration_timeout` and `get_iteration_timeout`. It defaults to `10000000` iterations and assigning a value of `0` disables the timeout.
sim.set_iteration_timeout(1000) # set the timeout to 1000 iterations
In some cases, sequential gates may come with an initial value that is assigned to their internal state during device startup. For example, this is the case for flip-flops within FPGA netlists, which may retrieve their initial state from the netlist or rather bitstream file. To accommodate this during simulation, these initial values can be loaded into the internal state of such sequential elements using `load_initial_values_from_netlist`. Further, `load_initial_values` may be used to specify an initial value to load into all sequential elements before running the simulation.
sim.load_initial_values_from_netlist() # load initial values into sequential gates if available
sim.load_initial_values(hal_py.BooleanFunction.Value.ZERO) # load logical 0 into all FFs before running simulation
- Running the Simulation
sim.set_input(in1, hal_py.BooleanFunction.Value.ONE) # assign a logical 1 to input net in1
sim.set_input(in2, hal_py.BooleanFunction.Value.ZERO) # assign a logical 0 to input net in2
sim.simulate(3000) # simulate for 3000 ps
sim.set_input(in1, hal_py.BooleanFunction.Value.ZERO) # change the value of in1 to a logical 0
sim.simulate(2000) # simulate for another 2000 ps
- Retrieving Simulation Results
state = sim.get_simulation_state() # retrieve the simulation state
val = state.get_net_value(net, 1000) # get the value of net 'net' after 1000 ps
Furthermore, the simulation state holds a list of all events incurred during simulation that can be obtained using `get_events`. This list may also be expanded by the user by creating and adding a new event using `add_event`. The current simulation state of the simulator instance may be overwritten using `set_simulation_state`. More on these operations can be found in the official Python API documentation.
- Generating a Waveform File
sim.generate_vcd("trace.vcd", 0, 300000)
- Example: Simulating a simple counter
from hal_plugins import netlist_simulator
pl_sim = hal_py.plugin_manager.get_plugin_instance("netlist_simulator")
sim = pl_sim.create_simulator()
sim.add_gates(netlist.get_gates())
sim.load_initial_values(hal_py.BooleanFunction.Value.ZERO)
clock_enable_B = netlist.get_net_by_id(8)
clock = netlist.get_net_by_id(9)
reset = netlist.get_net_by_id(7)
output_0 = netlist.get_net_by_id(6)
output_1 = netlist.get_net_by_id(5)
output_2 = netlist.get_net_by_id(4)
output_3 = netlist.get_net_by_id(3)
sim.add_clock_period(clock, 10000)
sim.set_input(clock_enable_B, hal_py.BooleanFunction.Value.ONE)
sim.set_input(reset, hal_py.BooleanFunction.Value.ZERO)
sim.simulate(40 * 1000)
sim.set_input(clock_enable_B, hal_py.BooleanFunction.Value.ZERO)
sim.simulate(110 * 1000)
sim.set_input(reset, hal_py.BooleanFunction.Value.ONE)
sim.simulate(20 * 1000)
sim.set_input(reset, hal_py.BooleanFunction.Value.ZERO)
sim.simulate(70 * 1000)
sim.set_input(clock_enable_B, hal_py.BooleanFunction.Value.ONE)
sim.simulate(23 * 1000)
sim.set_input(reset, hal_py.BooleanFunction.Value.ONE)
sim.simulate(20 * 1000)
sim.simulate(20 * 1000)
sim.simulate(5 * 1000)
sim.generate_vcd("counter.vcd", 0, 300000)
The generated vcd can be viewed using gtkwave.
![Waveform](https://github.com/emsec/hal/blob/master/wiki_images/simulator/counter_gtkwave.png)