Skip to content

Commit 5898892

Browse files
committed
Catch when we run out of pins
1 parent 44fc078 commit 5898892

File tree

1 file changed

+53
-15
lines changed

1 file changed

+53
-15
lines changed

chipflow_lib/platforms/_utils.py

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ def _find_contiguous_sequence(ordering: PinList, lst: PinList, total: int) -> Pi
416416
if unable to find a consecutive list, allocate as contigously as possible
417417
"""
418418
if not lst or len(lst) < total:
419-
raise ChipFlowError("Invalid request to find_contiguous_argument")
419+
raise ValueError(f"Invalid request to _find_contiguous_sequence: lst={lst}")
420420

421421
grouped = _group_consecutive_items(ordering, lst)
422422

@@ -472,26 +472,37 @@ def _allocate_pins(name: str, member: Dict[str, Any], pins: List[Pin], port_name
472472
logger.debug(f"member={pformat(member)}")
473473

474474
if member['type'] == 'interface' and 'annotations' in member \
475-
and IO_ANNOTATION_SCHEMA in member['annotations']:
475+
and IO_ANNOTATION_SCHEMA in member['annotations']:
476476
model:IOModel = member['annotations'][IO_ANNOTATION_SCHEMA]
477477
logger.debug(f"matched IOSignature {model}")
478478
name = name
479479
width = model['width']
480480
pin_map[name] = PortDesc(pins=pins[0:width], type='io', port_name=port_name, iomodel=model)
481481
logger.debug(f"added '{name}':{pin_map[name]} to pin_map")
482+
if len(pins) - width < 0:
483+
raise ChipFlowError(f"Ran out of available pins when allocating '{port_name}`")
482484
return pin_map, pins[width:]
483485
elif member['type'] == 'interface':
484-
for k, v in member['members'].items():
485-
port_name = '_'.join([name, k])
486-
_map, pins = _allocate_pins(k, v, pins, port_name=port_name)
487-
pin_map |= _map
488-
logger.debug(f"{pin_map},{_map}")
489-
return pin_map, pins
486+
try:
487+
for k, v in member['members'].items():
488+
port_name = '_'.join([name, k])
489+
_map, pins = _allocate_pins(k, v, pins, port_name=port_name)
490+
pin_map |= _map
491+
logger.debug(f"{pin_map},{_map}")
492+
return pin_map, pins
493+
except ChipFlowError as e:
494+
e.add_note("While allocating {name}")
495+
raise e
496+
except ValueError as e:
497+
raise ChipFlowError(f"Ran out of available pins when allocating '{port_name}`")
498+
490499
elif member['type'] == 'port':
491500
logger.warning(f"PortDesc '{name}' has no IOSignature, pin allocation likely to be wrong")
492501
width = member['width']
493502
model = IOModel(width=width, direction=io.Direction(member['dir']))
494503
pin_map[name] = PortDesc(pins=pins[0:width], type='io', port_name=port_name, iomodel=model)
504+
if len(pins) - width < 0:
505+
raise ChipFlowError(f"Ran out of available pins when allocating '{port_name}`")
495506
logger.debug(f"added '{name}':{pin_map[name]} to pin_map")
496507
return pin_map, pins[width:]
497508
else:
@@ -519,12 +530,27 @@ def _add_ports(self, component: str, interface: str, ports: Interface):
519530
self.ports[component] = {}
520531
self.ports[component][interface] = ports
521532

522-
def get_ports(self, component: str, interface: str) -> Interface | None:
523-
533+
def get_ports(self, component: Optional[str] = None, interface: Optional[str] = None) -> Interface | None:
524534
"List the ports allocated in this PortMap for the given `Component` and `Interface`"
525-
if component not in self.ports or interface not in self.ports[component]:
526-
return None
527-
return self.ports[component][interface]
535+
out: Interface = {}
536+
if not component:
537+
for c, v in self.ports.items():
538+
for i, v in self.ports[c].items():
539+
vn = { f"{c}.{i}.{pn}": p for pn, p in v.items() }
540+
out |= vn
541+
return out
542+
elif not interface:
543+
if component not in self.ports:
544+
return None
545+
for i, v in self.ports[component].items():
546+
vn = { f"{i}.{pn}": p for pn, p in v.items() }
547+
out |= vn
548+
return out
549+
else:
550+
if component not in self.ports or interface not in self.ports[component]:
551+
return None
552+
return self.ports[component][interface]
553+
528554

529555
def get_clocks(self) -> List[PortDesc]:
530556
ret = []
@@ -572,6 +598,7 @@ class Package(pydantic.BaseModel):
572598

573599
# TODO: minimise names into more traditional form
574600
def _linear_allocate_components(interfaces: dict, lockfile: LockFile | None, allocate, unallocated) -> PortMap:
601+
assert len(unallocated)
575602
port_map = PortMap()
576603
for component, v in interfaces.items():
577604
for interface, v in v['interface']['members'].items():
@@ -592,9 +619,20 @@ def _linear_allocate_components(interfaces: dict, lockfile: LockFile | None, all
592619
)
593620
port_map._add_ports(component, interface, old_ports)
594621
else:
622+
if len(unallocated) == 0:
623+
ports = port_map.get_ports()
624+
errstr = ''
625+
total = 0
626+
assert ports
627+
for pn,pd in ports.items():
628+
errstr += f"\n {pn}: "
629+
assert pd.pins
630+
errstr += f"{len(pd.pins)} pins"
631+
total += len(pd.pins)
632+
errstr += '\n'
633+
raise ChipFlowError(f"Ran out of available pins when allocating '{component}.{interface}`\n"
634+
f"Ports already allocated were:\n{errstr}\nTotal pins: {total}")
595635
pins = allocate(unallocated, width)
596-
if len(pins) == 0:
597-
raise ChipFlowError("No pins were allocated")
598636
logger.debug(f"allocated range: {pins}")
599637
unallocated = unallocated - set(pins)
600638
_map, _ = _allocate_pins(f"{component}_{interface}", v, pins)

0 commit comments

Comments
 (0)