Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sky130nm inverter schematic-driven-layout design & hdl21 integration #356

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ cython_debug/
.DS_Store
*Thumbs.db


# Possible generated files
*.cmd
*.tcl
Expand All @@ -180,3 +181,5 @@ cython_debug/
*.BAK
*.sav
*.plt
.virtual_documents
.idea
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gplugins_spice
5 changes: 5 additions & 0 deletions gplugins/hdl21/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .netlist import *
<<<<<<< HEAD
from .sky130 import *
=======
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
355 changes: 355 additions & 0 deletions gplugins/hdl21/netlist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,355 @@
"""
This module provides functions to generate a raw netlist semi-compatible with gdsfactory from a hdl21 module object.
"""

import hdl21 as h
import yaml

__all__ = [
<<<<<<< HEAD
<<<<<<< HEAD
'ParsedProtoVLSIR',
'generate_raw_netlist_dict_from_module',
'generate_raw_yaml_from_module'
=======
"ParsedProtoVLSIR",
"parse_module_to_proto_dict",
"generate_raw_netlist_from_module",
"generate_raw_yaml_from_module",
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
=======
"ParsedProtoVLSIR",
"generate_raw_netlist_dict_from_module",
"generate_raw_yaml_from_module",
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
]

ParsedProtoVLSIR = dict


<<<<<<< HEAD
<<<<<<< HEAD
=======
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
def _parse_module_to_proto_dict(module: h.module) -> ParsedProtoVLSIR:
=======
def parse_module_to_proto_dict(module: h.module) -> ParsedProtoVLSIR:
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
"""
Parse a hdl21 module object into a dictionary with the same structure as the proto VLSIR format.
"""

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


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_signal = connection["target"][0]["sig"]
connection_key = f"{instance_name},{portname}"
# Find the target instance and port
<<<<<<< HEAD
<<<<<<< HEAD
target_instance_port = _find_target_instance_port(proto_dict, target_signal, instance_name)
=======
target_instance_port = find_target_instance_port(
proto_dict, target_signal, instance_name
)
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
=======
target_instance_port = _find_target_instance_port(
proto_dict, target_signal, instance_name
)
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
if target_instance_port:
connections[connection_key] = target_instance_port

return connections


<<<<<<< HEAD
<<<<<<< HEAD
def _find_target_instance_port(proto_dict: ParsedProtoVLSIR,
target_signal,
current_instance_name):
=======
def find_target_instance_port(
proto_dict: ParsedProtoVLSIR, target_signal, current_instance_name
):
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
=======
def _find_target_instance_port(
proto_dict: ParsedProtoVLSIR, target_signal, current_instance_name
):
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
"""
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", []):
if connection["target"][0]["sig"] == 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("ports", []):
if port["signal"] == target_signal:
for instance in module.get("instances", []):
if instance["name"] == current_instance_name:
continue
for connection in instance.get("connections", []):
if connection["target"][0]["sig"] == target_signal:
return f"{instance['name']},{connection['portname']}"

return None


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 ports
<<<<<<< HEAD
<<<<<<< HEAD
for module in proto_dict.get('modules', []):
for port in module.get('ports', []):
port_signal = port['signal']
=======
for module in proto_dict.get("modules", []):
for port in module.get("ports", []):
port_signal = port["signal"]
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
connection = _find_port_connection(proto_dict, port_signal)
=======
for module in proto_dict.get("modules", []):
for port in module.get("ports", []):
port_signal = port["signal"]
connection = find_port_connection(proto_dict, port_signal)
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
if connection:
top_level_connections[port_signal] = connection

return top_level_connections


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", []):
if connection["target"][0]["sig"] == port_signal:
return f"{instance_name},{connection['portname']}"
return None


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 = {
<<<<<<< HEAD
<<<<<<< HEAD
'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
=======
"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
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
=======
"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
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)

# Extract connections and add to settings
instance_info["settings"]["ports"] = {}
for connection in instance.get("connections", []):
portname = connection["portname"]
target_signal = connection["target"][0]["sig"]
instance_info["settings"]["ports"][portname] = target_signal

instance_parameters[instance_name] = instance_info

return instance_parameters


def _extract_component_name(instance):
"""
Extract the component name from the instance.
"""
external_modules = instance.get("module", [])
if external_modules:
<<<<<<< HEAD
<<<<<<< HEAD
domain = external_modules[0].get('external', [{}])[0].get('domain', '')
name = external_modules[0].get('external', [{}])[0].get('name', '')
return f"{name}"
return 'unknown_component'
=======
domain = external_modules[0].get("external", [{}])[0].get("domain", "")
name = external_modules[0].get("external", [{}])[0].get("name", "")
return f"{domain}_{name}"
return "unknown_component"
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
=======
domain = external_modules[0].get("external", [{}])[0].get("domain", "")
name = external_modules[0].get("external", [{}])[0].get("name", "")
return f"{name}"
return "unknown_component"
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)


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


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": {}, "ports": {}}

# Extract the top-level module name
if proto_dict.get("modules"):
raw_netlist_dict["name"] = proto_dict["modules"][0].get("name", "")

# Generate instances information
<<<<<<< HEAD
<<<<<<< HEAD
raw_netlist_dict['instances'] = _extract_instance_parameters(proto_dict)
=======
raw_netlist_dict["instances"] = _extract_instance_parameters(proto_dict)
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)

# Generate connections
raw_netlist_dict["connections"] = _parse_connections(proto_dict)

# Generate top-level connections
<<<<<<< HEAD
raw_netlist_dict['ports'] = _generate_top_level_connections(proto_dict)
=======
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["ports"] = generate_top_level_connections(proto_dict)
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
=======
raw_netlist_dict["ports"] = _generate_top_level_connections(proto_dict)
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)

return raw_netlist_dict


def generate_raw_netlist_dict_from_module(module: h.module):
"""
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)


def generate_raw_yaml_from_module(module: h.module):
"""
Generate a raw netlist yaml from a hdl21 module object which could be manually edited for specific instances
related to the corresponding SPICE.
"""
<<<<<<< HEAD
raw_netlist = generate_raw_netlist_dict_from_module(module)
=======
raw_netlist = generate_raw_netlist_from_module(module)
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
return yaml.dump(raw_netlist, default_flow_style=False)
Loading
Loading