Source code for piel.integration.hdl21_gdsfactory.netlist

"""
This module provides functions to generate a raw netlist semi-compatible with gdsfactory from a hdl21 module object.
"""

from ...types import AnalogueModule

ParsedProtoVLSIR = dict


[docs] def _parse_module_to_proto_dict(module: AnalogueModule) -> ParsedProtoVLSIR: """ Parse a hdl21 module object into a dictionary with the same structure as the proto VLSIR format. """ import hdl21 as h def parse_value(lines, index): value = {} while index < len(lines): line = lines[index].strip() if line == "}": return value, index elif line.endswith("{"): key = line[:-1].strip() sub_value, new_index = parse_value(lines, index + 1) if key not in value: value[key] = [] value[key].append(sub_value) index = new_index else: key, val = line.split(":", 1) value[key.strip()] = val.strip().strip('"') index += 1 return value, index raw_proto_str = str(h.to_proto(module)) lines = raw_proto_str.split("\n") result = {} index = 0 while index < len(lines): line = lines[index].strip() if line.endswith("{"): key = line[:-1].strip() sub_value, new_index = parse_value(lines, index + 1) if key not in result: result[key] = [] result[key].append(sub_value) index = new_index else: index += 1 return result
[docs] def _parse_connections(proto_dict: ParsedProtoVLSIR) -> dict: """ Extract the connections from the proto_dict and return a dictionary with the connections. """ connections = {} # Extract the instances and their connections for module in proto_dict.get("modules", []): for instance in module.get("instances", []): instance_name = instance["name"] for connection in instance.get("connections", []): portname = connection["portname"] target = connection["target"][0] # Handle different structures of target if "sig" in target: target_signal = target["sig"] elif "slice" in target: target_signal = target["slice"][0]["signal"] else: # Log a warning or provide a default value for unknown structures target_signal = "unknown_signal" print( f"Warning: Unknown target structure in connection for instance '{instance_name}', port '{portname}'" ) connection_key = f"{instance_name},{portname}" # Find the target instance and port target_instance_port = _find_target_instance_port( proto_dict, target_signal, instance_name ) if target_instance_port: connections[connection_key] = target_instance_port return connections
[docs] def _find_target_instance_port( proto_dict: ParsedProtoVLSIR, target_signal, current_instance_name ): """ Find the target instance and port of the target signal in the proto_dict. """ # Search in the same module for module in proto_dict.get("modules", []): for instance in module.get("instances", []): if instance["name"] == current_instance_name: continue for connection in instance.get("connections", []): target = connection["target"][0] # Handle different structures of target if "sig" in target: signal = target["sig"] elif "slice" in target: signal = target["slice"][0]["signal"] else: signal = None print( f"Warning: Unknown target structure for instance '{instance['name']}', port '{connection['portname']}'" ) if signal == target_signal: return f"{instance['name']},{connection['portname']}" # Search in external modules for ext_module in proto_dict.get("ext_modules", []): for port in ext_module.get("connection", []): if port["signal"] == target_signal: for instance in module.get("instances", []): if instance["name"] == current_instance_name: continue for connection in instance.get("connections", []): target = connection["target"][0] if "sig" in target: signal = target["sig"] elif "slice" in target: signal = target["slice"][0]["signal"] else: signal = None print( f"Warning: Unknown target structure for instance '{instance['name']}', port '{connection['portname']}'" ) if signal == target_signal: return f"{instance['name']},{connection['portname']}" return None
[docs] def _generate_top_level_connections(proto_dict: ParsedProtoVLSIR): """ Generate the top-level connections from the proto_dict. """ top_level_connections = {} # Iterate over the top-level module connection for module in proto_dict.get("modules", []): for port in module.get("connection", []): port_signal = port["signal"] connection = _find_port_connection(proto_dict, port_signal) if connection: top_level_connections[port_signal] = connection return top_level_connections
[docs] def _find_port_connection(proto_dict: ParsedProtoVLSIR, port_signal): """ Find the connection of the port signal in the proto_dict. """ # Search within the module instances for module in proto_dict.get("modules", []): for instance in module.get("instances", []): instance_name = instance["name"] for connection in instance.get("connections", []): target = connection["target"][0] # Handle different structures of target if "sig" in target: signal = target["sig"] elif "slice" in target: signal = target["slice"][0]["signal"] else: signal = None print( f"Warning: Unknown target structure in connection for instance '{instance_name}', port '{connection['portname']}'" ) if signal == port_signal: return f"{instance_name},{connection['portname']}" return None
[docs] def _extract_instance_parameters(proto_dict: ParsedProtoVLSIR): """ Extract the instance parameters from the proto_dict. """ instance_parameters = {} for module in proto_dict.get("modules", []): for instance in module.get("instances", []): instance_name = instance["name"] instance_info = { "component": _extract_component_name(instance), "info": {}, "settings": {}, } # Extract parameters into the settings for parameter in instance.get("parameters", []): param_name = parameter["name"] param_value = _extract_parameter_value(parameter["value"]) instance_info["settings"][param_name] = param_value # Extract connections and add to settings instance_info["settings"]["connection"] = {} for connection in instance.get("connections", []): portname = connection["portname"] target = connection["target"][0] if "sig" in target: target_signal = target["sig"] elif "slice" in target: target_signal = target["slice"][0]["signal"] else: # Handle cases where 'target' does not have 'sig' or 'slice' target_signal = "unknown_signal" instance_info["settings"]["connection"][portname] = target_signal instance_parameters[instance_name] = instance_info return instance_parameters
[docs] def _extract_component_name(instance): """ Extract the component name from the instance. """ external_modules = instance.get("module", []) if external_modules: name = external_modules[0].get("external", [{}])[0].get("name", "") return f"{name}" return "unknown_component"
[docs] def _extract_parameter_value(value): """ Extract the parameter value from the value dictionary. """ if value and "literal" in value[0]: return value[0]["literal"] elif value and "prefixed" in value[0]: prefix = value[0]["prefixed"][0].get("prefix", "") int64_value = value[0]["prefixed"][0].get("int64_value", "") return f"{prefix}_{int64_value}" return None
[docs] def _generate_raw_netlist_dict_from_proto_dict(proto_dict: ParsedProtoVLSIR): """ Generate a raw netlist dictionary from the proto_dict. """ raw_netlist_dict = { "name": "", "instances": {}, "connections": {}, "connection": {}, } # Extract the top-level module name if proto_dict.get("modules"): raw_netlist_dict["name"] = proto_dict["modules"][0].get("name", "") # Generate instances information raw_netlist_dict["instances"] = _extract_instance_parameters(proto_dict) # Generate connections raw_netlist_dict["connections"] = _parse_connections(proto_dict) # Generate top-level connections raw_netlist_dict["connection"] = _generate_top_level_connections(proto_dict) return raw_netlist_dict
[docs] def generate_raw_netlist_dict_from_module(module: AnalogueModule): """ Generate a raw netlist dictionary from a hdl21 module object. This just gives us a raw structure of the hdl21 modules, we cannot use this json equivalently to a gdsfactory netlist. """ proto_dict = _parse_module_to_proto_dict(module) return _generate_raw_netlist_dict_from_proto_dict(proto_dict)
[docs] def generate_raw_yaml_from_module(module: AnalogueModule): """ Generate a raw netlist yaml from a hdl21 module object which could be manually edited for specific instances related to the corresponding SPICE. """ import yaml raw_netlist = generate_raw_netlist_dict_from_module(module) return yaml.dump(raw_netlist, default_flow_style=False)