Skip to content

Commit 8a1fabf

Browse files
committed
✨ Beta demo sky130 spice-to-layout
1 parent 1d6d35b commit 8a1fabf

24 files changed

Lines changed: 1801 additions & 9 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ cython_debug/
172172
.DS_Store
173173
*Thumbs.db
174174

175+
175176
# Possible generated files
176177
*.cmd
177178
*.tcl
@@ -180,3 +181,5 @@ cython_debug/
180181
*.BAK
181182
*.sav
182183
*.plt
184+
.virtual_documents
185+
.idea

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
gplugins_spice

gplugins/hdl21/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .netlist import *
2+
<<<<<<< HEAD
3+
from .sky130 import *
4+
=======
5+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)

gplugins/hdl21/netlist.py

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
"""
2+
This module provides functions to generate a raw netlist semi-compatible with gdsfactory from a hdl21 module object.
3+
"""
4+
5+
import hdl21 as h
6+
import yaml
7+
8+
__all__ = [
9+
<<<<<<< HEAD
10+
<<<<<<< HEAD
11+
'ParsedProtoVLSIR',
12+
'generate_raw_netlist_dict_from_module',
13+
'generate_raw_yaml_from_module'
14+
=======
15+
"ParsedProtoVLSIR",
16+
"parse_module_to_proto_dict",
17+
"generate_raw_netlist_from_module",
18+
"generate_raw_yaml_from_module",
19+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
20+
=======
21+
"ParsedProtoVLSIR",
22+
"generate_raw_netlist_dict_from_module",
23+
"generate_raw_yaml_from_module",
24+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
25+
]
26+
27+
ParsedProtoVLSIR = dict
28+
29+
30+
<<<<<<< HEAD
31+
<<<<<<< HEAD
32+
=======
33+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
34+
def _parse_module_to_proto_dict(module: h.module) -> ParsedProtoVLSIR:
35+
=======
36+
def parse_module_to_proto_dict(module: h.module) -> ParsedProtoVLSIR:
37+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
38+
"""
39+
Parse a hdl21 module object into a dictionary with the same structure as the proto VLSIR format.
40+
"""
41+
42+
def parse_value(lines, index):
43+
value = {}
44+
while index < len(lines):
45+
line = lines[index].strip()
46+
if line == "}":
47+
return value, index
48+
elif line.endswith("{"):
49+
key = line[:-1].strip()
50+
sub_value, new_index = parse_value(lines, index + 1)
51+
if key not in value:
52+
value[key] = []
53+
value[key].append(sub_value)
54+
index = new_index
55+
else:
56+
key, val = line.split(":", 1)
57+
value[key.strip()] = val.strip().strip('"')
58+
index += 1
59+
return value, index
60+
61+
raw_proto_str = str(h.to_proto(module))
62+
lines = raw_proto_str.split("\n")
63+
result = {}
64+
index = 0
65+
while index < len(lines):
66+
line = lines[index].strip()
67+
if line.endswith("{"):
68+
key = line[:-1].strip()
69+
sub_value, new_index = parse_value(lines, index + 1)
70+
if key not in result:
71+
result[key] = []
72+
result[key].append(sub_value)
73+
index = new_index
74+
else:
75+
index += 1
76+
77+
return result
78+
79+
80+
def _parse_connections(proto_dict: ParsedProtoVLSIR) -> dict:
81+
"""
82+
Extract the connections from the proto_dict and return a dictionary with the connections.
83+
"""
84+
connections = {}
85+
86+
# Extract the instances and their connections
87+
for module in proto_dict.get("modules", []):
88+
for instance in module.get("instances", []):
89+
instance_name = instance["name"]
90+
for connection in instance.get("connections", []):
91+
portname = connection["portname"]
92+
target_signal = connection["target"][0]["sig"]
93+
connection_key = f"{instance_name},{portname}"
94+
# Find the target instance and port
95+
<<<<<<< HEAD
96+
<<<<<<< HEAD
97+
target_instance_port = _find_target_instance_port(proto_dict, target_signal, instance_name)
98+
=======
99+
target_instance_port = find_target_instance_port(
100+
proto_dict, target_signal, instance_name
101+
)
102+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
103+
=======
104+
target_instance_port = _find_target_instance_port(
105+
proto_dict, target_signal, instance_name
106+
)
107+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
108+
if target_instance_port:
109+
connections[connection_key] = target_instance_port
110+
111+
return connections
112+
113+
114+
<<<<<<< HEAD
115+
<<<<<<< HEAD
116+
def _find_target_instance_port(proto_dict: ParsedProtoVLSIR,
117+
target_signal,
118+
current_instance_name):
119+
=======
120+
def find_target_instance_port(
121+
proto_dict: ParsedProtoVLSIR, target_signal, current_instance_name
122+
):
123+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
124+
=======
125+
def _find_target_instance_port(
126+
proto_dict: ParsedProtoVLSIR, target_signal, current_instance_name
127+
):
128+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
129+
"""
130+
Find the target instance and port of the target signal in the proto_dict.
131+
"""
132+
# Search in the same module
133+
for module in proto_dict.get("modules", []):
134+
for instance in module.get("instances", []):
135+
if instance["name"] == current_instance_name:
136+
continue
137+
for connection in instance.get("connections", []):
138+
if connection["target"][0]["sig"] == target_signal:
139+
return f"{instance['name']},{connection['portname']}"
140+
# Search in external modules
141+
for ext_module in proto_dict.get("ext_modules", []):
142+
for port in ext_module.get("ports", []):
143+
if port["signal"] == target_signal:
144+
for instance in module.get("instances", []):
145+
if instance["name"] == current_instance_name:
146+
continue
147+
for connection in instance.get("connections", []):
148+
if connection["target"][0]["sig"] == target_signal:
149+
return f"{instance['name']},{connection['portname']}"
150+
151+
return None
152+
153+
154+
def _generate_top_level_connections(proto_dict: ParsedProtoVLSIR):
155+
"""
156+
Generate the top-level connections from the proto_dict.
157+
"""
158+
top_level_connections = {}
159+
160+
# Iterate over the top-level module ports
161+
<<<<<<< HEAD
162+
<<<<<<< HEAD
163+
for module in proto_dict.get('modules', []):
164+
for port in module.get('ports', []):
165+
port_signal = port['signal']
166+
=======
167+
for module in proto_dict.get("modules", []):
168+
for port in module.get("ports", []):
169+
port_signal = port["signal"]
170+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
171+
connection = _find_port_connection(proto_dict, port_signal)
172+
=======
173+
for module in proto_dict.get("modules", []):
174+
for port in module.get("ports", []):
175+
port_signal = port["signal"]
176+
connection = find_port_connection(proto_dict, port_signal)
177+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
178+
if connection:
179+
top_level_connections[port_signal] = connection
180+
181+
return top_level_connections
182+
183+
184+
def _find_port_connection(proto_dict: ParsedProtoVLSIR, port_signal):
185+
"""
186+
Find the connection of the port signal in the proto_dict.
187+
"""
188+
# Search within the module instances
189+
for module in proto_dict.get("modules", []):
190+
for instance in module.get("instances", []):
191+
instance_name = instance["name"]
192+
for connection in instance.get("connections", []):
193+
if connection["target"][0]["sig"] == port_signal:
194+
return f"{instance_name},{connection['portname']}"
195+
return None
196+
197+
198+
def _extract_instance_parameters(proto_dict: ParsedProtoVLSIR):
199+
"""
200+
Extract the instance parameters from the proto_dict.
201+
"""
202+
instance_parameters = {}
203+
204+
for module in proto_dict.get("modules", []):
205+
for instance in module.get("instances", []):
206+
instance_name = instance["name"]
207+
instance_info = {
208+
<<<<<<< HEAD
209+
<<<<<<< HEAD
210+
'component': _extract_component_name(instance),
211+
'info': {},
212+
'settings': {}
213+
}
214+
215+
# Extract parameters into the settings
216+
for parameter in instance.get('parameters', []):
217+
param_name = parameter['name']
218+
param_value = _extract_parameter_value(parameter['value'])
219+
instance_info['settings'][param_name] = param_value
220+
=======
221+
"component": extract_component_name(instance),
222+
"info": {},
223+
"settings": {},
224+
}
225+
226+
# Extract parameters into the settings
227+
for parameter in instance.get("parameters", []):
228+
param_name = parameter["name"]
229+
param_value = extract_parameter_value(parameter["value"])
230+
instance_info["settings"][param_name] = param_value
231+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
232+
=======
233+
"component": _extract_component_name(instance),
234+
"info": {},
235+
"settings": {},
236+
}
237+
238+
# Extract parameters into the settings
239+
for parameter in instance.get("parameters", []):
240+
param_name = parameter["name"]
241+
param_value = _extract_parameter_value(parameter["value"])
242+
instance_info["settings"][param_name] = param_value
243+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
244+
245+
# Extract connections and add to settings
246+
instance_info["settings"]["ports"] = {}
247+
for connection in instance.get("connections", []):
248+
portname = connection["portname"]
249+
target_signal = connection["target"][0]["sig"]
250+
instance_info["settings"]["ports"][portname] = target_signal
251+
252+
instance_parameters[instance_name] = instance_info
253+
254+
return instance_parameters
255+
256+
257+
def _extract_component_name(instance):
258+
"""
259+
Extract the component name from the instance.
260+
"""
261+
external_modules = instance.get("module", [])
262+
if external_modules:
263+
<<<<<<< HEAD
264+
<<<<<<< HEAD
265+
domain = external_modules[0].get('external', [{}])[0].get('domain', '')
266+
name = external_modules[0].get('external', [{}])[0].get('name', '')
267+
return f"{name}"
268+
return 'unknown_component'
269+
=======
270+
domain = external_modules[0].get("external", [{}])[0].get("domain", "")
271+
name = external_modules[0].get("external", [{}])[0].get("name", "")
272+
return f"{domain}_{name}"
273+
return "unknown_component"
274+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
275+
=======
276+
domain = external_modules[0].get("external", [{}])[0].get("domain", "")
277+
name = external_modules[0].get("external", [{}])[0].get("name", "")
278+
return f"{name}"
279+
return "unknown_component"
280+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
281+
282+
283+
def _extract_parameter_value(value):
284+
"""
285+
Extract the parameter value from the value dictionary.
286+
"""
287+
if value and "literal" in value[0]:
288+
return value[0]["literal"]
289+
elif value and "prefixed" in value[0]:
290+
prefix = value[0]["prefixed"][0].get("prefix", "")
291+
int64_value = value[0]["prefixed"][0].get("int64_value", "")
292+
return f"{prefix}_{int64_value}"
293+
return None
294+
295+
296+
def _generate_raw_netlist_dict_from_proto_dict(proto_dict: ParsedProtoVLSIR):
297+
"""
298+
Generate a raw netlist dictionary from the proto_dict.
299+
"""
300+
raw_netlist_dict = {"name": "", "instances": {}, "connections": {}, "ports": {}}
301+
302+
# Extract the top-level module name
303+
if proto_dict.get("modules"):
304+
raw_netlist_dict["name"] = proto_dict["modules"][0].get("name", "")
305+
306+
# Generate instances information
307+
<<<<<<< HEAD
308+
<<<<<<< HEAD
309+
raw_netlist_dict['instances'] = _extract_instance_parameters(proto_dict)
310+
=======
311+
raw_netlist_dict["instances"] = _extract_instance_parameters(proto_dict)
312+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
313+
314+
# Generate connections
315+
raw_netlist_dict["connections"] = _parse_connections(proto_dict)
316+
317+
# Generate top-level connections
318+
<<<<<<< HEAD
319+
raw_netlist_dict['ports'] = _generate_top_level_connections(proto_dict)
320+
=======
321+
raw_netlist_dict["instances"] = extract_instance_parameters(proto_dict)
322+
323+
# Generate connections
324+
raw_netlist_dict["connections"] = parse_connections(proto_dict)
325+
326+
# Generate top-level connections
327+
raw_netlist_dict["ports"] = generate_top_level_connections(proto_dict)
328+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
329+
=======
330+
raw_netlist_dict["ports"] = _generate_top_level_connections(proto_dict)
331+
>>>>>>> a705eac ([pre-commit.ci] auto fixes from pre-commit.com hooks)
332+
333+
return raw_netlist_dict
334+
335+
336+
def generate_raw_netlist_dict_from_module(module: h.module):
337+
"""
338+
Generate a raw netlist dictionary from a hdl21 module object.
339+
This just gives us a raw structure of the hdl21 modules, we cannot use this json equivalently to a gdsfactory netlist.
340+
"""
341+
proto_dict = _parse_module_to_proto_dict(module)
342+
return _generate_raw_netlist_dict_from_proto_dict(proto_dict)
343+
344+
345+
def generate_raw_yaml_from_module(module: h.module):
346+
"""
347+
Generate a raw netlist yaml from a hdl21 module object which could be manually edited for specific instances
348+
related to the corresponding SPICE.
349+
"""
350+
<<<<<<< HEAD
351+
raw_netlist = generate_raw_netlist_dict_from_module(module)
352+
=======
353+
raw_netlist = generate_raw_netlist_from_module(module)
354+
>>>>>>> 75a4e37 ([pre-commit.ci] auto fixes from pre-commit.com hooks)
355+
return yaml.dump(raw_netlist, default_flow_style=False)

0 commit comments

Comments
 (0)