@@ -19,23 +19,38 @@ def _remap_pin_assigns_list(
1919 pin_assigns : List [str ],
2020 * ,
2121 invert_remapping : bool = False ,
22- ) -> Dict [str , str ]:
22+ ) -> Dict [str , Tuple [ Optional [ str ], Optional [ str ]] ]:
2323 """Given a remapping dict and a list of pin assigns, returns the mapping as a dict with the remapping applied.
24+ The output is (pin name, pin number), with both being optional.
25+
2426 If invert_remapping is True, the remapping dict is inverted before applying.
2527 Assigns not present in the remapping dict are passed unchanged, eg for non-pin-assigns like bundle containers.
2628 """
2729 if invert_remapping :
2830 remapping = {v : k for k , v in remapping .items ()}
2931
30- remapped_assigns = {}
32+ remapped_assigns : Dict [ str , Tuple [ Optional [ str ], Optional [ str ]]] = {}
3133 for assign in pin_assigns :
3234 name , pindef = assign .split ("=" )
33- pin = pindef .split ("," )[0 ].strip () # take the first (gpio name) if multiple
34- remapped_pin = remapping .get (pin )
35- if remapped_pin is not None :
36- remapped_assigns [name .strip ()] = remapped_pin
35+ name = name .strip ()
36+ split = pindef .split ("," )
37+ split = [s .strip () for s in split ]
38+ if len (split ) == 1 : # ambiguous, could either be pinname or pinnum
39+ pindef = split [0 ].strip ()
40+ if pindef in remapping :
41+ if invert_remapping : # remap pinnum -> pinname
42+ remapped_assigns [name ] = (remapping [pindef ], None )
43+ else : # remap pinname -> pinnum
44+ remapped_assigns [name ] = (pindef , remapping [pindef ])
45+ else : # assume is a pinname or bundle container since it's not remappable
46+ remapped_assigns [name ] = (pindef , None )
47+ elif len (split ) == 2 :
48+ pinname , pinnum = split [0 ], split [1 ]
49+ assert pinname in remapping
50+ remapped_assigns [name ] = (pinname , remapping [pinname ])
3751 else :
38- remapped_assigns [name .strip ()] = pindef # pass unmodified if not remappable, eg bundle containers
52+ raise ValueError (f"unable to parse assign { assign } " )
53+
3954 return remapped_assigns
4055
4156 def _generator_pin_dict (self ) -> Dict [str , Port ]:
@@ -73,48 +88,36 @@ def recurse_port(port: Port, prefix: str = "") -> None:
7388 return pin_dict
7489
7590 def _remap_to_footprint_pinning (
76- self , pin_assigns : Dict [str , str ], valid_pins : Iterable [str ]
91+ self , pin_assigns : Dict [str , Tuple [ Optional [ str ], Optional [ str ]]], pin_dict : Dict [str , Port ]
7792 ) -> Dict [str , HasPassivePort ]:
78- """Given the pin assigns in a dict form as port name -> footprint pin, eg from _remap_pin_assigns_list,
79- returns the footprint-compatible form as footprint pin -> port object .
93+ """Generates pinning that can be passed into a footprint, given the pin assign dict from _remap_pin_assigns_list
94+ and pin dict from _generator_pin_dict .
8095
81- This simplified pin assignment tool requires all pins to be assigned.
82- It does not automatically assign unassigned pins, that is assumed to have happened at a higher level."""
96+ This requires all pins to be assigned."""
8397 pinning : Dict [str , HasPassivePort ] = {}
84- seen_names : Set [str ] = set ()
85-
86- def remap_port_recursive (port : Port , prefix : str = "" ) -> None :
87- """Remaps a port, recursively for bundles"""
88- if isinstance (port , HasPassivePort ):
89- pin = pin_assigns .get (prefix )
90- assert pin is not None , f"pin { prefix } not assigned"
91- assert pin in valid_pins , f"pin { pin } not in valid pins { valid_pins } "
92- pinning [pin ] = port
93-
94- for subport_name , subport in port ._ports .items ():
95- remap_port_recursive (subport , f"{ prefix } .{ subport_name } " )
9698
97- for io_port in self ._io_ports :
98- if isinstance (io_port , Vector ):
99- io_port .defined ()
100- for subport_name in self .get (io_port .requested ()):
101- assert subport_name not in seen_names , f"duplicate pin name { subport_name } "
102- seen_names .add (subport_name )
103- subport = io_port .append_elt (io_port ._tpe .empty (), subport_name )
104- remap_port_recursive (subport , subport_name )
105- elif isinstance (io_port , Port ):
106- if self .get (io_port .is_connected ()):
107- port_name = io_port ._name_from (self )
108- assert port_name not in seen_names , f"duplicate pin name { port_name } "
109- seen_names .add (port_name )
110- remap_port_recursive (io_port , port_name )
111- else :
112- raise NotImplementedError (f"unknown port type { io_port } " )
99+ for name , assign in pin_assigns .items ():
100+ assert name in pin_dict
101+ port = pin_dict [name ]
102+ if not isinstance (port , HasPassivePort ):
103+ continue # ignore non-leaf ports
104+ assert assign [1 ] is not None , f"pin { name } missing pin number assignment"
105+ pinning [assign [1 ]] = port
113106
114107 return pinning
115108
116109 @staticmethod
117- def _remap_assigns_to_value (assigns : Dict [str , str ]) -> List [str ]:
110+ def _remap_assigns_to_value (assigns : Dict [str , Tuple [ Optional [ str ], Optional [ str ]] ]) -> List [str ]:
118111 """Given a dict of pin assigns from _remap_pinning_assigns, returns a list of assign strings
119112 for use in self.actual_pin_assigns"""
120- return [f"{ name } ={ assign } " for name , assign in assigns .items ()]
113+ pin_assigns : List [str ] = []
114+ for name , assign in assigns .items ():
115+ if assign [0 ] is not None and assign [1 ] is not None :
116+ pin_assigns .append (f"{ name } ={ assign [0 ]} , { assign [1 ]} " )
117+ elif assign [0 ] is not None :
118+ pin_assigns .append (f"{ name } ={ assign [0 ]} " )
119+ elif assign [1 ] is not None :
120+ pin_assigns .append (f"{ name } ={ assign [1 ]} " )
121+ else :
122+ raise ValueError (f"invalid assign for { name } : { assign } " )
123+ return pin_assigns
0 commit comments