Skip to content

Commit 5feb02a

Browse files
committed
clean iocontroller wrapper infrastructure
1 parent e457b5c commit 5feb02a

4 files changed

Lines changed: 55 additions & 48 deletions

File tree

edg/abstract_parts/BaseIoControllerWrapped.py

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -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

edg/parts/microcontroller/Rp2040.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,8 @@ def generate(self) -> None:
421421
"14": self.vcc, # VUsb
422422
}
423423
remapped_pin_assigns = self._remap_pin_assigns_list(self._PIN_REMAPPING, self.get(self.pin_assigns))
424-
pinning.update(self._remap_to_footprint_pinning(remapped_pin_assigns, self._PIN_REMAPPING.values()))
424+
pin_dict = self._generator_pin_dict()
425+
pinning.update(self._remap_to_footprint_pinning(remapped_pin_assigns, pin_dict))
425426
self.assign(self.actual_pin_assigns, self._remap_assigns_to_value(remapped_pin_assigns))
426427

427428
self.footprint(

edg/parts/microcontroller/nRF52840.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,8 @@ def generate(self) -> None:
487487
"21": self.p0_18,
488488
}
489489
remapped_pin_assigns = self._remap_pin_assigns_list(self._PIN_REMAPPING, self.get(self.pin_assigns))
490-
pinning.update(self._remap_to_footprint_pinning(remapped_pin_assigns, self._PIN_REMAPPING.values()))
490+
pin_dict = self._generator_pin_dict()
491+
pinning.update(self._remap_to_footprint_pinning(remapped_pin_assigns, pin_dict))
491492
self.assign(self.actual_pin_assigns, self._remap_assigns_to_value(remapped_pin_assigns))
492493

493494
self.footprint(
@@ -653,7 +654,8 @@ def generate(self) -> None:
653654
# 'Vbat': '28',
654655
}
655656
remapped_pin_assigns = self._remap_pin_assigns_list(self._PIN_REMAPPING, self.get(self.pin_assigns))
656-
pinning.update(self._remap_to_footprint_pinning(remapped_pin_assigns, self._PIN_REMAPPING.values()))
657+
pin_dict = self._generator_pin_dict()
658+
pinning.update(self._remap_to_footprint_pinning(remapped_pin_assigns, pin_dict))
657659
self.assign(self.actual_pin_assigns, self._remap_assigns_to_value(remapped_pin_assigns))
658660

659661
self.footprint(

edg/parts/microcontroller/test_mcu_wrapper.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,19 @@ def test_overallocate(self) -> None:
8282

8383
def test_auto_pins(self) -> None:
8484
compiled = ScalaCompiler.compile(AutoPinsTest)
85-
self.assertEqual(compiled.get_value(["dut", "actual_pin_assigns"]), ["0=7", "1=8"])
85+
self.assertEqual(compiled.get_value(["dut", "actual_pin_assigns"]), ["0=GPIO0, 7", "1=GPIO1, 8"])
8686
self.assertEqual(compiled.get_value(["dut", "model", "actual_pin_assigns"]), ["0=GPIO0, 2", "1=GPIO1, 3"])
8787

8888
def test_assigned_pins(self) -> None:
8989
compiled = ScalaCompiler.compile(AssignedPinsTest)
90-
self.assertEqual(compiled.get_value(["dut", "actual_pin_assigns"]), ["0=1", "1=3"])
90+
self.assertEqual(compiled.get_value(["dut", "actual_pin_assigns"]), ["0=GPIO26, 1", "1=GPIO28, 3"])
9191
self.assertEqual(compiled.get_value(["dut", "model", "actual_pin_assigns"]), ["0=GPIO26, 38", "1=GPIO28, 40"])
9292

9393
def test_assigned_i2c(self) -> None:
9494
compiled = ScalaCompiler.compile(AssignedI2cTest)
9595
self.assertEqual(
96-
compiled.get_value(["dut", "actual_pin_assigns"]), ["i2c=I2C1_T", "i2c.scl=6", "i2c.sda=5", "0=7", "1=8"]
96+
compiled.get_value(["dut", "actual_pin_assigns"]),
97+
["i2c=I2C1_T", "i2c.scl=GPIO7, 6", "i2c.sda=GPIO6, 5", "0=GPIO0, 7", "1=GPIO1, 8"],
9798
)
9899
self.assertEqual(
99100
compiled.get_value(["dut", "model", "actual_pin_assigns"]),

0 commit comments

Comments
 (0)