Mapping Scopes and Signals¶
It may now be wanted to apply the read VCD data to the corresponding circuit elements. This means, scopes must be matched to module instances within the circuit, and VCD variables are then equivalent to the wires inside this module. However, the top VCD scope from the testbench may not always match the top module of the circuit. Thus, the user is required to provide a "top scope" name, which is equivalent to the testbench instance of the top module of the circuit. In other words, the user must provide the name of the DUT, so that Netlist Carpentry knows which of the top scopes is the instance of the circuit's top module.
Execute the cell below to read the small circuit file and the VCD file.
from netlist_carpentry import read
from netlist_carpentry.io.vcd import VCDWaveform
c = read('../files/simpleAdder.v', top="simpleAdder")
wf = VCDWaveform("../files/sim/tb_adder_basics.vcd")
To get a view over the total VCD hierarchy, the function get_hierarchy_dict from the io.vcd package can be used.
This function returns a nested dictionary, where each entry contains a subdictionary, where the keys are the subscope names, and the values are nested dictionaries again.
Execute the cell below to retrieve the hierarchy dictionary of the VCD waveform. For the given VCD file, this is rather simple, since the testbench only contains a single instance, which is the flat adder module.
from netlist_carpentry.io.vcd import get_hierarchy_dict
get_hierarchy_dict(wf)
{'tb_adder_basics': {'adder': {}}}
To map the individual signals on wires from the circuit, it is imperative to map the scopes onto modules first.
To achieve this, the top scope name of the DUT is required.
The DUT in this case is the top module instance from the test bench.
This can be done with the function map_names_to_circuit from the io.vcd package.
Execute the cell below to retrieve a mapping, so that each scope of the VCD file is associated with a module from the circuit.
For this concrete case, this is very simple, as the circuit only consists of a single module.
Thus, the scope mapping dictionary only contains a single key-value pair.
from netlist_carpentry.io.vcd import map_names_to_circuit
map_names_to_circuit(c, wf, "adder")
{'tb_adder_basics.adder': Module(simpleAdder)}
The read VCD data can also be applied onto the corresponding circuit elements.
The function apply_vcd_data from the vcd.io package tries to map every signal from the given VCD waveform to an appropriate wire (i.e. a wire with the same name), so that the VCD data can be found when accessing the metadata of said wire.
With wire.metadata.vcd, the VCD values of the wire can be retrieved.
If the wire does not have a metadata category vcd, no VCD data for this wire was present.
The data in the vcd category is a dictionary, where the key is the full hierarchical path to the signal from the VCD waveform, and the value is the list of signal value changes.
Execute the cell below to see how the wires of the module have toggled for the given VCD waveform.
from netlist_carpentry.io.vcd import apply_vcd_data
apply_vcd_data(c, wf, "adder")
module = c.first
for w in module.wires.values():
if w.metadata.has_category("vcd"):
print(f"VCD data of {w.name}: {w.metadata.vcd}")
else:
print(f"No VCD data for wire {w.name}!")
WARNING: No instance with name tb_adder_basics found in circuit /tmp/tmppekr6yf5/simpleAdder.json!
No VCD data for wire §0§out2§7§0§!
VCD data of §0§out§8§0§: {'tb_adder_basics.adder.__0__out__8__0__': [(0, 'xxxxxxxxx'), (1350, 180), (1550, 308), (1750, 382)]}
VCD data of clk: {'tb_adder_basics.adder.clk': [(0, 'x'), (610, 0), (650, 1), (700, 0), (750, 1), (800, 0), (850, 1), (900, 0), (950, 1), (1000, 0), (1050, 1), (1100, 0), (1150, 1), (1200, 0), (1250, 1), (1300, 0), (1350, 1), (1400, 0), (1450, 1), (1500, 0), (1550, 1), (1600, 0), (1650, 1), (1700, 0), (1750, 1), (1800, 0), (1850, 1), (1900, 0), (1950, 1)]}
VCD data of in1: {'tb_adder_basics.adder.in1': [(0, 'xxxxxxxx'), (1350, 165), (1550, 111), (1750, 175)]}
VCD data of in2: {'tb_adder_basics.adder.in2': [(0, 'xxxxxxxx'), (1350, 15), (1550, 197), (1750, 207)]}
VCD data of out: {'tb_adder_basics.adder.out': [(0, 'xxxxxxxxx'), (310, 0), (650, 'xxxxxxxxx'), (1050, 0)]}
No VCD data for wire out2!
VCD data of rst: {'tb_adder_basics.adder.rst': [(0, 'x'), (310, 1), (610, 0), (1050, 1)]}