Skip to content

Commit 153027f

Browse files
committed
added hdl21 netlisting functions
1 parent a160cfe commit 153027f

7 files changed

Lines changed: 354 additions & 35 deletions

File tree

.idea/gplugins.iml

Lines changed: 9 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/workspace.xml

Lines changed: 20 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
gplugins
1+
gplugins_spice

gplugins/hdl21/__init__.py

Whitespace-only changes.

gplugins/hdl21/netlist.py

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
"""
2+
This module provides functions to generate a raw netlist semi-compatible with gdsfactory from a hdl21 module object.
3+
"""
4+
import yaml
5+
import hdl21 as h
6+
7+
__all__ = [
8+
'ParsedProtoVLSIR',
9+
'parse_module_to_proto_dict',
10+
'generate_raw_netlist_from_module',
11+
'generate_raw_yaml_from_module'
12+
]
13+
14+
ParsedProtoVLSIR = dict
15+
16+
def parse_module_to_proto_dict(module: h.module) -> ParsedProtoVLSIR:
17+
"""
18+
Parse a hdl21 module object into a dictionary with the same structure as the proto VLSIR format.
19+
"""
20+
def parse_value(lines, index):
21+
value = {}
22+
while index < len(lines):
23+
line = lines[index].strip()
24+
if line == "}":
25+
return value, index
26+
elif line.endswith("{"):
27+
key = line[:-1].strip()
28+
sub_value, new_index = parse_value(lines, index + 1)
29+
if key not in value:
30+
value[key] = []
31+
value[key].append(sub_value)
32+
index = new_index
33+
else:
34+
key, val = line.split(":", 1)
35+
value[key.strip()] = val.strip().strip('"')
36+
index += 1
37+
return value, index
38+
39+
raw_proto_str = str(h.to_proto(module))
40+
lines = raw_proto_str.split("\n")
41+
result = {}
42+
index = 0
43+
while index < len(lines):
44+
line = lines[index].strip()
45+
if line.endswith("{"):
46+
key = line[:-1].strip()
47+
sub_value, new_index = parse_value(lines, index + 1)
48+
if key not in result:
49+
result[key] = []
50+
result[key].append(sub_value)
51+
index = new_index
52+
else:
53+
index += 1
54+
55+
return result
56+
57+
58+
def parse_connections(proto_dict: ParsedProtoVLSIR) -> dict:
59+
"""
60+
Extract the connections from the proto_dict and return a dictionary with the connections.
61+
"""
62+
connections = {}
63+
64+
# Extract the instances and their connections
65+
for module in proto_dict.get('modules', []):
66+
for instance in module.get('instances', []):
67+
instance_name = instance['name']
68+
for connection in instance.get('connections', []):
69+
portname = connection['portname']
70+
target_signal = connection['target'][0]['sig']
71+
connection_key = f"{instance_name},{portname}"
72+
# Find the target instance and port
73+
target_instance_port = find_target_instance_port(data, target_signal, instance_name)
74+
if target_instance_port:
75+
connections[connection_key] = target_instance_port
76+
77+
return connections
78+
79+
80+
def find_target_instance_port(proto_dict: ParsedProtoVLSIR,
81+
target_signal,
82+
current_instance_name):
83+
"""
84+
Find the target instance and port of the target signal in the proto_dict.
85+
"""
86+
# Search in the same module
87+
for module in proto_dict.get('modules', []):
88+
for instance in module.get('instances', []):
89+
if instance['name'] == current_instance_name:
90+
continue
91+
for connection in instance.get('connections', []):
92+
if connection['target'][0]['sig'] == target_signal:
93+
return f"{instance['name']},{connection['portname']}"
94+
# Search in external modules
95+
for ext_module in proto_dict.get('ext_modules', []):
96+
for port in ext_module.get('ports', []):
97+
if port['signal'] == target_signal:
98+
for instance in module.get('instances', []):
99+
if instance['name'] == current_instance_name:
100+
continue
101+
for connection in instance.get('connections', []):
102+
if connection['target'][0]['sig'] == target_signal:
103+
return f"{instance['name']},{connection['portname']}"
104+
105+
return None
106+
107+
108+
def generate_top_level_connections(proto_dict: ParsedProtoVLSIR):
109+
"""
110+
Generate the top-level connections from the proto_dict.
111+
"""
112+
top_level_connections = {}
113+
114+
# Iterate over the top-level module ports
115+
for module in proto_dict.get('modules', []):
116+
for port in module.get('ports', []):
117+
port_signal = port['signal']
118+
connection = find_port_connection(proto_dict, port_signal)
119+
if connection:
120+
top_level_connections[port_signal] = connection
121+
122+
return top_level_connections
123+
124+
125+
def find_port_connection(proto_dict: ParsedProtoVLSIR, port_signal):
126+
"""
127+
Find the connection of the port signal in the proto_dict.
128+
"""
129+
# Search within the module instances
130+
for module in proto_dict.get('modules', []):
131+
for instance in module.get('instances', []):
132+
instance_name = instance['name']
133+
for connection in instance.get('connections', []):
134+
if connection['target'][0]['sig'] == port_signal:
135+
return f"{instance_name},{connection['portname']}"
136+
return None
137+
138+
139+
def extract_instance_parameters(proto_dict: ParsedProtoVLSIR):
140+
"""
141+
Extract the instance parameters from the proto_dict.
142+
"""
143+
instance_parameters = {}
144+
145+
for module in proto_dict.get('modules', []):
146+
for instance in module.get('instances', []):
147+
instance_name = instance['name']
148+
instance_info = {
149+
'component': extract_component_name(instance),
150+
'info': {},
151+
'settings': {}
152+
}
153+
154+
# Extract parameters into the settings
155+
for parameter in instance.get('parameters', []):
156+
param_name = parameter['name']
157+
param_value = extract_parameter_value(parameter['value'])
158+
instance_info['settings'][param_name] = param_value
159+
160+
# Extract connections and add to settings
161+
instance_info['settings']['ports'] = {}
162+
for connection in instance.get('connections', []):
163+
portname = connection['portname']
164+
target_signal = connection['target'][0]['sig']
165+
instance_info['settings']['ports'][portname] = target_signal
166+
167+
instance_parameters[instance_name] = instance_info
168+
169+
return instance_parameters
170+
171+
172+
def extract_component_name(instance):
173+
"""
174+
Extract the component name from the instance.
175+
"""
176+
external_modules = instance.get('module', [])
177+
if external_modules:
178+
domain = external_modules[0].get('external', [{}])[0].get('domain', '')
179+
name = external_modules[0].get('external', [{}])[0].get('name', '')
180+
return f"{domain}_{name}"
181+
return 'unknown_component'
182+
183+
184+
def extract_parameter_value(value):
185+
"""
186+
Extract the parameter value from the value dictionary.
187+
"""
188+
if value and 'literal' in value[0]:
189+
return value[0]['literal']
190+
elif value and 'prefixed' in value[0]:
191+
prefix = value[0]['prefixed'][0].get('prefix', '')
192+
int64_value = value[0]['prefixed'][0].get('int64_value', '')
193+
return f"{prefix}_{int64_value}"
194+
return None
195+
196+
197+
def generate_raw_netlist_from_proto_dict(proto_dict: ParsedProtoVLSIR):
198+
"""
199+
Generate a raw netlist dictionary from the proto_dict.
200+
"""
201+
raw_netlist_dict = {
202+
'name': '',
203+
'instances': {},
204+
'connections': {},
205+
'ports': {}
206+
}
207+
208+
# Extract the top-level module name
209+
if proto_dict.get('modules'):
210+
raw_netlist_dict['name'] = proto_dict['modules'][0].get('name', '')
211+
212+
# Generate instances information
213+
raw_netlist_dict['instances'] = extract_instance_parameters(proto_dict)
214+
215+
# Generate connections
216+
raw_netlist_dict['connections'] = parse_connections(proto_dict)
217+
218+
# Generate top-level connections
219+
raw_netlist_dict['ports'] = generate_top_level_connections(proto_dict)
220+
221+
return raw_netlist_dict
222+
223+
224+
def generate_raw_netlist_from_module(module: h.module):
225+
"""
226+
Generate a raw netlist dictionary from a hdl21 module object.
227+
"""
228+
proto_dict = parse_module_to_proto_dict(module)
229+
return generate_raw_netlist_from_proto_dict(proto_dict)
230+
231+
232+
def generate_raw_yaml_from_module(module: h.module):
233+
"""
234+
Generate a raw netlist yaml from a hdl21 module object.
235+
"""
236+
raw_netlist = generate_raw_netlist_from_module(module)
237+
return yaml.dump(raw_netlist, default_flow_style=False)

0 commit comments

Comments
 (0)