@@ -71,7 +71,7 @@ class PowerDomain:
7171class PowerConfig :
7272 domains : Optional [Dict [PowerDomainName , PowerDomain ]] = None
7373 map : Optional [Dict [ComponentName ,
74- Dict [InterfaceName , dict ]
74+ Dict [InterfaceName , dict | str ]
7575 ]
7676 ] = None
7777
@@ -138,7 +138,7 @@ class Port(pydantic.BaseModel):
138138 pins : List [Pin ] | None # None implies must be allocated at end
139139 port_name : str
140140 iomodel : IOModel
141- ic_power_domain : Optional [PowerDomainName ] = None
141+ port_power_domain : Optional [PowerDomainName ] = None
142142
143143 @property
144144 def width (self ):
@@ -154,15 +154,15 @@ def direction(self):
154154 @property
155155 def invert (self ) -> Iterable [bool ] | None :
156156 if 'invert' in self .iomodel :
157- assert self .iomodel ['invert' ] is tuple
157+ assert isinstance ( self .iomodel ['invert' ], tuple )
158158 return self .iomodel ['invert' ]
159159 else :
160160 return None
161161
162162 @property
163- def interface_power_domain (self ) -> Iterable [ bool ] | None :
163+ def interface_power_domain (self ) -> str | None :
164164 if 'interface_power_domain' in self .iomodel :
165- assert self .iomodel ['interface_power_domain' ] is tuple
165+ assert isinstance ( self .iomodel ['interface_power_domain' ], str )
166166 return self .iomodel ['interface_power_domain' ]
167167 else :
168168 return None
@@ -174,6 +174,7 @@ def interface_power_domain(self) -> Iterable[bool] | None:
174174
175175class PortMap (pydantic .BaseModel ):
176176 ports : Dict [str , Component ] = {}
177+ port_power_domains : Dict [str , PowerDomain ] = {}
177178
178179 def get_ports (self , component : str , interface : str ) -> Interface :
179180 "List the ports allocated in this PortMap for the given `Component` and `Interface`"
@@ -217,41 +218,70 @@ def allocate_power(self, config: 'Config'):
217218 "Allocate power domains to top level ports"
218219 if not config .chipflow .power :
219220 return
220- power_config = config .chipflow .power
221221
222- def set_iface_pd (c , i , ipd , pd ):
223- for n , p in self .ports [c ][i ].items ():
224- if p .interface_power_domain == ipd :
225- p .ic_power_domain = pd
222+ # TODO: allow for shell-defined power domains
223+ if not config .chipflow .power .domains :
224+ return
226225
227- def match_iface_pd (c , i , x ):
228- for n1 , _map in x .items ():
229- for ipd , pd in _map .items ():
230- for n2 , p in self .ports [c ][i ].items ():
231- if n1 == n2 and ipd == p .interface_power_domain :
232- p .ic_power_domain = pd
226+ # instantiate port-side power domains
227+ self .port_power_domains = config .chipflow .power .domains
233228
234- if not power_config or not power_config .map :
229+ if not config .chipflow .power .map :
230+ logger .warning ("[chipflow.power.domains] is defined, but no [chipflow.power.map] found" )
235231 return
236- for c , im in power_config .map .items ():
237- # c is top-level component name
232+
233+ # convert nested dict structure into a mapping ic_power_domain:[component, interface, {port,} {ip power domain}]
234+ map_config = config .chipflow .power .map
235+
236+ def map_ports (c , i , * , port_power_domain , port_name = None , interface_power_domain = None ):
237+ # a bit verbose but easier to understand, I hope..
238+ if port_power_domain not in self .port_power_domains :
239+ raise ChipFlowError (f"'{ port_power_domain } ' is not a known power domain in { c } .{ i } { '.' + port_name if port_name else '' } { '.' + interface_power_domain if interface_power_domain else '' } = '{ port_power_domain } ')" )
240+ if not port_name and interface_power_domain :
241+ for p in self .ports [c ][i ].values ():
242+ if p .interface_power_domain == interface_power_domain :
243+ p .port_power_domain = port_power_domain
244+ elif not port_name :
245+ for p in self .ports [c ][i ].values ():
246+ p .port_power_domain = port_power_domain
247+ elif port_power_domain and not interface_power_domain :
248+ self .ports [c ][i ][port_name ].port_power_domain = port_power_domain
249+ else :
250+ p = self .ports [c ][i ][port_name ]
251+ if p .interface_power_domain == interface_power_domain :
252+ p .port_power_domain = port_power_domain
253+
254+ # must be an easier way to do this...
255+ for c , v in map_config .items ():
238256 if c not in self .ports :
239- raise ChipFlowError (f"In [chipflow.silicon.power], '{ c } ' is not a top level component" )
240- for i , pm in im .items ():
241- # i is top-level interface name
242- if i not in self .ports [i ]:
243- raise ChipFlowError (f"In [chipflow.silicon.power], '{ i } ' is not a top level component of { c } " )
244- for x , y in pm .items ():
245- # is x a power domain of i?
246- if x is str and any (x == p .interface_power_domain for p in self .ports [c ][i ].values ()):
247- # set power domain on all items in the port that match
248- set_iface_pd (c ,i ,x , y )
249- # is x a port of i?
250- if isinstance (x , str ) and any (x == p for p in self .ports [c ][i ].keys ()):
251- self .ports [c ][i ][x ].ic_power_domain = y
252- # is x a map of portnames to interface power domains?
253- if isinstance (x , dict ) and any (p1 == p1 for p1 in x .keys () for p2 in self .ports [c ][i ].keys ()):
254- match_iface_pd (c , i , x )
257+ raise ChipFlowError (f"In [chipflow.power.map], '{ c } ' is not a top level component" )
258+ if not isinstance (v , dict ):
259+ raise ChipFlowError (f"Malformed [chipflow.power.map] section: { c } = { v } " )
260+ for i , v in v .items ():
261+ if i not in self .ports [c ]:
262+ raise ChipFlowError (f"In [chipflow.silicon.power], '{ i } ' is not an interface of { c } " )
263+ if isinstance (v , str ):
264+ map_ports (c , i , port_power_domain = v )
265+ if isinstance (v , dict ):
266+ for x , v in v .items ():
267+ # is x a port name?
268+ if x in self .ports [c ][i ]:
269+ if isinstance (v , str ):
270+ map_ports (c , i , port_name = x , port_power_domain = v )
271+ elif isinstance (v , dict ):
272+ for y , v in v .items ():
273+ map_ports (c , i , port_name = x , interface_power_domain = y , port_power_domain = v )
274+ else :
275+ raise ChipFlowError (f"Malformed [chipflow.power.map] section: { c } .{ i } .{ x } = { v } ('{ x } ' is a port)" )
276+ # is x an interface-side power domain?
277+ elif any (x == p .interface_power_domain for p in self .ports [c ][i ].values ()):
278+ if not isinstance (v , str ):
279+ raise ChipFlowError (f"Malformed [chipflow.power.map] section: { c } .{ i } .{ x } = { v } ('{ x } ' is a power domaiwn)" )
280+ else :
281+ # map interface-side power domain x to port-side power domain v
282+ map_ports (c , i , interface_power_domain = x , port_power_domain = v )
283+ else :
284+ raise ChipFlowError (f"Malformed [chipflow.power.map] section: { c } .{ i } .{ x } = { v } (unable to interpret '{ x } ')" )
255285
256286
257287def io_annotation_schema ():
0 commit comments