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