@@ -180,8 +180,9 @@ def model_post_init(self, __context):
180180
181181 @property
182182 def width (self ):
183- assert self .pins and 'width' in self .iomodel
184- assert len (self .pins ) == self .iomodel ['width' ]
183+ assert 'width' in self .iomodel
184+ if self .pins :
185+ assert len (self .pins ) == self .iomodel ['width' ]
185186 return self .iomodel ['width' ]
186187
187188 @property
@@ -206,6 +207,40 @@ def interface_power_domain(self) -> str | None:
206207 return None
207208
208209
210+ def create_ports (name : str , member : Dict [str , Any ], port_name : str ) -> Dict [str , Port ]:
211+ "Allocate pins based of Amaranth member metadata"
212+ pin_map : Dict [str , Port ] = {}
213+
214+ logger .debug (f"create_ports: name={ name } " )
215+ logger .debug (f"member={ pformat (member )} " )
216+
217+ if member ['type' ] == 'interface' and 'annotations' in member \
218+ and IO_ANNOTATION_SCHEMA in member ['annotations' ]:
219+ model :IOModel = member ['annotations' ][IO_ANNOTATION_SCHEMA ]
220+ logger .debug (f"matched IOSignature { model } " )
221+ pin_map [name ] = Port (type = 'io' , port_name = port_name , iomodel = model , pins = None )
222+ logger .debug (f"added '{ name } ':{ pin_map [name ]} to pin_map" )
223+ return pin_map
224+ elif member ['type' ] == 'interface' :
225+ for k , v in member ['members' ].items ():
226+ port_name = '_' .join ([name , k ])
227+ _map = create_ports (name = k , member = v , port_name = port_name )
228+ pin_map |= _map
229+ logger .debug (f"{ pin_map } ,{ _map } " )
230+ return pin_map
231+ elif member ['type' ] == 'port' :
232+ logger .warning (f"Port '{ name } ' has no IOSignature, pin allocation likely to be wrong" )
233+ width = member ['width' ]
234+ model = IOModel (width = width , direction = io .Direction (member ['dir' ]))
235+ pin_map [name ] = Port (type = 'io' , port_name = port_name , iomodel = model , pins = None )
236+ logger .debug (f"added '{ name } ':{ pin_map [name ]} to pin_map" )
237+ return pin_map
238+ else :
239+ logging .debug (f"Shouldnt get here. member = { member } " )
240+ assert False
241+
242+
243+
209244Interface = Dict [str , Port ]
210245Component = Dict [str , Interface ]
211246AllocateFunc = Callable [[PinSet , int ], PinList ]
@@ -272,16 +307,10 @@ def populate(self, interfaces: dict, lockfile: Optional['LockFile'] = None):
272307 )
273308 self .add_ports (component , interface , old_ports )
274309 else :
275- print (f"i { interface } , v { v } " )
276- for name , member in v ['members' ].items ():
277- print (member )
278- if member ['type' ] == 'interface' and 'annotations' in member \
279- and IO_ANNOTATION_SCHEMA in member ['annotations' ]:
280- iomodel : IOModel = member ['annotations' ][IO_ANNOTATION_SCHEMA ]
281- port = Port (type = 'io' , pins = None , port_name = name , iomodel = iomodel )
282- self .add_port (component , interface , name , port )
283- else
284-
310+ print (f"Creating ports for component: { component } , interface: { interface } " )
311+ if component not in self .ports :
312+ self .ports [component ] = {}
313+ self .ports [component ][interface ] = create_ports (interface , v , interface )
285314
286315 def allocate_power (self , config : 'Config' ):
287316 "Allocate power domains to top level ports"
0 commit comments