Note
Go to the end to download the full example code
Make Instances Unique
Creates definitions for non-leaf instances so each instance has its own definition. Each library in both the original and the uniquified netlist will be printed along with each’s definitions.
ORIGINAL
DEFINITIONS IN ' hdi_primitives ': ['LUT2', 'LUT3', 'IBUF', 'OBUF', 'INV']
DEFINITIONS IN ' work ': ['c', 'b', 'a', 'top']
UNIQUE
DEFINITIONS IN ' hdi_primitives ': ['LUT2', 'LUT3', 'IBUF', 'OBUF', 'INV']
DEFINITIONS IN ' work ': ['c_UNIQUE_0', 'c_UNIQUE_1', 'c_UNIQUE_2', 'c_UNIQUE_3', 'c_UNIQUE_4', 'c_UNIQUE_5', 'c_UNIQUE_6', 'c_UNIQUE_7', 'c_UNIQUE_8', 'c_UNIQUE_9', 'c_UNIQUE_10', 'c_UNIQUE_11', 'c_UNIQUE_12', 'c_UNIQUE_13', 'c_UNIQUE_14', 'c_UNIQUE_15', 'c_UNIQUE_16', 'c_UNIQUE_17', 'c_UNIQUE_18', 'c_UNIQUE_19', 'c_UNIQUE_20', 'c_UNIQUE_21', 'c_UNIQUE_22', 'c_UNIQUE_23', 'c_UNIQUE_24', 'c_UNIQUE_25', 'c', 'b_UNIQUE_0', 'b_UNIQUE_1', 'b_UNIQUE_2', 'b_UNIQUE_3', 'b_UNIQUE_4', 'b_UNIQUE_5', 'b_UNIQUE_6', 'b_UNIQUE_7', 'b', 'a_UNIQUE_0', 'a_UNIQUE_1', 'a', 'top']
import tempfile
import spydrnet as sdn
import collections
from pathlib import Path
# Check if given instance is a black box
# instance: std.Instance to check
# Return True if instance is a black box
# (defined by no listed cables or child within child's reference), else return False
def is_black_box(instance):
definition = instance.reference
if len(definition.cables) != 0 or len(definition.children) != 0:
return False
return True
def increment_definition_count(definition):
if definition not in definition_count:
definition_count[definition] = 1
else:
definition_count[definition] += 1
def trace_definition(definition):
top_order = collections.deque()
for child in definition.children:
if len(child.pins) == 0:
return top_order
inner_pin = list(child.pins.keys())[0]
if inner_pin.wire is None:
continue
top_order.extend(trace_definition(child.reference))
top_order.append(definition)
increment_definition_count(definition)
return top_order
def get_reverse_topological_order(ir):
depth_first_search = collections.deque()
for child in top_def.children:
if not is_black_box(child):
depth_first_search.extend(trace_definition(child.reference))
visited = set()
reverse_topological_order = []
while len(depth_first_search) != 0:
definition = depth_first_search.popleft()
if definition not in visited:
visited.add(definition)
reverse_topological_order.append(definition)
return reverse_topological_order
def copy_metadata(original, copy, copy_num=None):
for key, data in original.data.items():
copy[key] = data
if type(original) is sdn.Definition:
if 'EDIF.identifier' in copy.data:
while copy['EDIF.identifier'] + '_UNIQUE_' + str(copy_num) in definition_count:
copy_num += 1
definition_count[copy['EDIF.identifier'] +
'_UNIQUE_' + str(copy_num)] = 1
copy['EDIF.identifier'] = copy['EDIF.identifier'] + \
'_UNIQUE_' + str(copy_num)
if '.NAME' in copy.data:
copy['.NAME'] = copy['.NAME'] + '_UNIQUE_' + str(copy_num)
def copy_ports(original, copy):
for original_port in original.ports:
new_port = copy.create_port()
copy_metadata(original_port, new_port)
new_port.direction = original_port.direction
for original_inner_pin in original_port.pins:
original_inner_pin_to_new_inner_pin[original_inner_pin] = new_port.create_pin(
)
if hasattr(original_port, 'is_array'):
new_port.is_array = original_port.is_array
if hasattr(original_port, 'is_scalar'):
new_port.is_scalar = original_port.is_scalar
def make_instances_unique(instance):
if len(definition_copies[instance.reference]) == 0:
return
definition = definition_copies[instance.reference].pop()
# instance.reference = None
instance.reference = definition
def copy_children(original, copy):
for original_child in original.children:
new_child = copy.create_child()
copy_metadata(original_child, new_child)
new_child.reference = original_child.reference
for pin in original_child.pins.keys():
outer_pin_map[original_child.pins[pin]] = new_child.pins[pin]
if not is_black_box(original_child):
make_instances_unique(new_child)
instance_map[original_child] = new_child
def copy_cable(original, copy):
for original_cable in original.cables:
new_cable = copy.create_cable()
copy_metadata(original_cable, new_cable)
for original_wire in original_cable.wires:
new_wire = new_cable.create_wire()
for original_pin in original_wire.pins:
if isinstance(original_pin, sdn.InnerPin):
new_wire.connect_pin(
original_inner_pin_to_new_inner_pin[original_pin])
else:
new_wire.connect_pin(outer_pin_map[original_pin])
def copy_definition(def_to_copy, def_copy, i):
copy_metadata(def_to_copy, def_copy, i)
copy_ports(def_to_copy, def_copy)
copy_children(def_to_copy, def_copy)
copy_cable(def_to_copy, def_copy)
def definition_clean_up(definition):
if definition in definition_copies:
for child in definition.children:
if child.reference in definition_copies:
make_instances_unique(child)
def make_definition_copies(def_to_copy, num_of_copies):
copies = {}
copies[def_to_copy] = collections.deque()
definition_copies[def_to_copy] = []
for i in range(num_of_copies):
def_copy = sdn.Definition()
copy_definition(def_to_copy, def_copy, i)
definition_copies[def_to_copy].append(def_copy)
for y in range(len(def_to_copy.library.definitions)):
if def_to_copy == def_to_copy.library.definitions[y]:
break
try:
def_to_copy.library.add_definition(def_copy, y)
except KeyError:
name = def_to_copy['EDIF.identifier']
message = 'Try to add a definition with name of ' + \
name + 'but the name was already use'
raise KeyError(message)
definition_clean_up(def_to_copy)
return definition_copies
def clean(definition):
for child in definition.children:
if child.reference in definition_copies:
make_instances_unique(child)
#print a list of all libraries and definitions in a netlist
def libraries_definitions(my_netlist):
for library in my_netlist.libraries:
definitions = list(definition.name for definition in library.definitions)
print(" DEFINITIONS IN '",library.name,"':",definitions)
definition_count = {}
original_inner_pin_to_new_inner_pin = {}
instance_map = {}
outer_pin_map = {}
definition_copies = {}
example_name = 'unique_challenge'
ir = sdn.load_example_netlist_by_name(example_name)
ir_orig = sdn.load_example_netlist_by_name(example_name) #store the original netlist for display later
top_def = ir.top_instance.reference
reverse_topological_order = get_reverse_topological_order(ir)
for definition in reverse_topological_order:
make_definition_copies(definition, definition_count[definition] - 1)
clean(top_def)
with tempfile.TemporaryDirectory() as td:
file_name = example_name + '_unique.edf'
sdn.compose(ir, Path(td, file_name))
#show the original netlist with its definitions and the new netlist with each instance now as a unique definition
print("ORIGINAL")
libraries_definitions(ir_orig)
print("UNIQUE")
libraries_definitions(ir)
Total running time of the script: (0 minutes 0.055 seconds)