Skip to content

Commit 0a4c1bc

Browse files
committed
Assign io power pins
1 parent e79a06d commit 0a4c1bc

File tree

3 files changed

+101
-67
lines changed

3 files changed

+101
-67
lines changed

chipflow_lib/platforms/_packages.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from ._utils import QuadPackageDef, BareDiePackageDef, Package
1+
from ._utils import QuadPackageDef, BareDiePackageDef, GAPackageDef, Package
22
from ._openframe import OpenframePackageDef
33

44
# Add any new package types to both PACKAGE_DEFINITIONS and the PackageDef union
55
PACKAGE_DEFINITIONS = {
66
"pga144": QuadPackageDef(name="pga144", width=36, height=36),
77
"cf20": BareDiePackageDef(name="cf20", width=7, height=3),
8+
"bga144": GAPackageDef(name="bga144", width=36, height=36),
89
"openframe": OpenframePackageDef()
910
}
1011

chipflow_lib/platforms/_utils.py

Lines changed: 98 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@
77
from collections import OrderedDict, deque, defaultdict
88
from collections.abc import Iterable
99
from pprint import pformat
10-
from typing import Set, List, Dict, Optional, Union, Literal, Tuple
10+
from typing import Set, List, Dict, Optional, Union, Literal, Tuple, TypeVar
1111

1212
from dataclasses import dataclass, asdict
1313
from enum import Enum, IntEnum, StrEnum, auto
1414
from math import ceil, floor
1515
from typing import (
16-
Any, Annotated, NamedTuple, Self,
17-
TYPE_CHECKING
16+
Any, Annotated, NamedTuple, Self, TYPE_CHECKING
1817
)
1918
from typing_extensions import (
2019
TypedDict, Unpack, NotRequired
@@ -267,8 +266,9 @@ def BidirIOSignature(width: int, **kwargs: Unpack[IOModelOptions]):
267266
model: IOModel = kwargs | {'width': width, 'direction': io.Direction.Bidir} # type: ignore[reportGeneralTypeIssues]
268267
return IOSignature(**model)
269268

269+
# TODO: limit to pyantic serialisable types?
270270

271-
Pin = Union[Tuple[Any,...], str, int]
271+
Pin = TypeVar('Pin')
272272
PinSet = Set[Pin]
273273
PinList = List[Pin]
274274
Pins = Union[PinSet, PinList]
@@ -403,7 +403,6 @@ def _group_consecutive_items(ordering: PinList, lst: PinList) -> OrderedDict[int
403403
d.setdefault(len(g), []).append(g)
404404
return d
405405

406-
407406
def _find_contiguous_sequence(ordering: PinList, lst: PinList, total: int) -> PinList:
408407
"""Find the next sequence of n consecutive numbers in a sorted list
409408
@@ -664,8 +663,8 @@ def _allocate_bringup(self, config: 'Config') -> Component:
664663
vss = "vss"
665664
vdd = "vdd"
666665
if pp.name:
667-
vss = f"vss{pp.name}"
668-
vdd = f"vdd{pp.name}"
666+
vss = f"{pp.name}vss"
667+
vdd = f"{pp.name}vdd"
669668
powerpins[vss].append(pp.power)
670669
powerpins[vdd].append(pp.ground)
671670

@@ -769,12 +768,14 @@ def model_post_init(self, __context):
769768

770769
@property
771770
def bringup_pins(self) -> BringupPins:
772-
core_power = PowerPins(
773-
(_Side.N, 1),
774-
(_Side.N, 2)
775-
)
771+
#TODO, this makes no sense for anything that isn't tiny..
772+
core_power = [
773+
PowerPins((_Side.N, 1), (_Side.N, 2)),
774+
PowerPins((_Side.W, 1), (_Side.W, 2), name='d')
775+
]
776+
776777
return BringupPins(
777-
core_power=[core_power],
778+
core_power=core_power,
778779
core_clock=(_Side.N, 3),
779780
core_reset=(_Side.N, 3),
780781
core_heartbeat=(_Side.E, 1),
@@ -849,27 +850,34 @@ def _power(self) -> List[PowerPins]:
849850
Power pins are always a matched pair in the middle of a side, with the number
850851
varying with the size of the package.
851852
We don't move power pins from these locations to allow for easier bring up test.
853+
returns two lists, core power pins and io power pins
852854
"""
853-
pins = []
855+
pins: List[PowerPins] = []
856+
# heuristic for sensible number of power pins for a given size
854857
n = (self.width + self.height)//12
855858
# Left
856859
p = self.height//2 + self.height//2
857-
pins.append(PowerPins(p, p +1))
860+
assert p > 3
861+
pins.append(PowerPins(p-2, p-1))
862+
pins.append(PowerPins(p, p+1, name='d'))
858863
# Bottom
859864
start = self.height
860865
if n > 2:
861-
p = start + self.width//2 + self.width//2
862-
pins.append(PowerPins(p, p+1))
866+
p = start + self.width//2
867+
pins.append(PowerPins(p-2, p-1))
868+
pins.append(PowerPins(p, p+1, name='d'))
863869
# Right
864870
start = start + self.width
865871
if n > 1:
866-
p = start + self.height//2 + self.height//2
867-
pins.append(PowerPins(p, p+1))
872+
p = start + self.height//2
873+
pins.append(PowerPins(p-2, p-1))
874+
pins.append(PowerPins(p, p+1, name='d'))
868875
# Top
869876
start = start + self.height
870877
if n > 3:
871-
p = start + self.width//2 + self.width//2
872-
pins.append(PowerPins(p, p+1))
878+
p = start + self.width//2
879+
pins.append(PowerPins(p-2, p-1))
880+
pins.append(PowerPins(p, p+1, name='d'))
873881
return pins
874882

875883

@@ -961,75 +969,77 @@ class GAPackageDef(BasePackageDef):
961969
width:int
962970
height: int
963971
layout_type: GALayout= GALayout.FULL
964-
channel_width: Optional[int]
965-
island_width: Optional[int]
966-
missing_pins: Optional[Set[GAPin]]
967-
additional_pins: Optional[Set[GAPin]]
968-
969-
def model_post_init(self, __context):
970-
def int_to_alpha(i: int):
971-
"Covert int to alpha representation, starting at 1"
972-
valid_letters = "ABCDEFGHJKLMPRSTUVWXY"
973-
out = ''
974-
while i > 0:
975-
char = i % len(valid_letters)
976-
i = i // len(valid_letters)
977-
out = valid_letters[char-1] + out
978-
return out
979-
972+
channel_width: Optional[int] = None
973+
island_width: Optional[int] = None
974+
missing_pins: Optional[Set[GAPin]] = None
975+
additional_pins: Optional[Set[GAPin]] = None
976+
977+
@staticmethod
978+
def _int_to_alpha(i: int):
979+
"Covert int to alpha representation, starting at 1"
980+
valid_letters = "ABCDEFGHJKLMPRSTUVWXY"
981+
out = ''
982+
while i > 0:
983+
char = i % len(valid_letters)
984+
i = i // len(valid_letters)
985+
out = valid_letters[char-1] + out
986+
return out
987+
988+
def _get_all_pins(self) -> Tuple[Set[GAPin], Set[GAPin] | None]:
980989
def pins_for_range(h1: int, h2: int, w1: int, w2: int) -> Set[GAPin]:
981-
pins = [GAPin(int_to_alpha(h),w) for h in range(h1, h2) for w in range(w1, w2)]
990+
pins = [GAPin(self._int_to_alpha(h),w) for h in range(h1, h2) for w in range(w1, w2)]
982991
return set(pins)
983992

984-
def sort_by_quadrant(pins: Set[GAPin]) -> List[Pin]:
985-
quadrants:List[Set[GAPin]] = [set(), set(), set(), set()]
986-
midline_h = int_to_alpha(self.height // 2)
987-
midline_w = self.width // 2
988-
for pin in pins:
989-
if pin.h < midline_h and pin.w < midline_w:
990-
quadrants[0].add(pin)
991-
if pin.h >= midline_h and pin.w < midline_w:
992-
quadrants[1].add(pin)
993-
if pin.h < midline_h and pin.w >= midline_w:
994-
quadrants[2].add(pin)
995-
if pin.h >= midline_h and pin.w >= midline_w:
996-
quadrants[3].add(pin)
997-
ret = []
998-
for q in range(0,3):
999-
ret.append(sorted(quadrants[q]))
1000-
return ret
1001993

1002-
self._ordered_pins: List[Pin] = []
1003994
match self.layout_type:
1004995
case GALayout.FULL:
1005996
pins = pins_for_range(1, self.height, 1, self.width)
1006-
pins -= self.bringup_pins.to_set()
1007-
self._ordered_pins = sort_by_quadrant(pins)
997+
return (pins, None)
1008998

1009999
case GALayout.PERIMETER:
10101000
assert self.channel_width is not None
10111001
pins = pins_for_range(1, self.height, 1, self.width) - \
10121002
pins_for_range(1 + self.channel_width, self.height-self.channel_width, 1 + self.channel_width, self.width - self.channel_width)
1013-
pins -= self.bringup_pins.to_set()
1014-
self._ordered_pins = sort_by_quadrant(pins)
1003+
return (pins, None)
10151004

10161005
case GALayout.ISLAND:
10171006
assert self.channel_width is not None
10181007
assert self.island_width is not None
10191008
outer_pins = pins_for_range(1, self.height, 1, self.width) - \
10201009
pins_for_range(1 + self.channel_width, self.height-self.channel_width, 1 + self.channel_width, self.width - self.channel_width)
1021-
outer_pins -= self.bringup_pins.to_set()
10221010
inner_pins = pins_for_range(ceil(self.height/ 2 - self.island_width /2), floor(self.height/2 + self.island_width /2),
10231011
ceil(self.width / 2 - self.island_width /2), floor(self.width /2 + self.island_width /2))
1024-
# TODO, allocate island as power
1025-
self._ordered_pins = sort_by_quadrant(outer_pins) + sorted(inner_pins)
1012+
return (outer_pins, inner_pins)
10261013

10271014
case GALayout.CHANNEL:
10281015
assert self.channel_width is not None
10291016
pins = pins_for_range(1, self.channel_width + 1, 1, self.width) | \
10301017
pins_for_range(self.height - self.channel_width, self.height, 1, self.width)
1031-
pins -= self.bringup_pins.to_set()
1032-
self._ordered_pins = sort_by_quadrant(pins)
1018+
return (pins, None)
1019+
1020+
def model_post_init(self, __context):
1021+
def sort_by_quadrant(pins: Set[GAPin]) -> List[GAPin]:
1022+
quadrants:List[Set[GAPin]] = [set(), set(), set(), set()]
1023+
midline_h = self._int_to_alpha(self.height // 2)
1024+
midline_w = self.width // 2
1025+
for pin in pins:
1026+
if pin.h < midline_h and pin.w < midline_w:
1027+
quadrants[0].add(pin)
1028+
if pin.h >= midline_h and pin.w < midline_w:
1029+
quadrants[1].add(pin)
1030+
if pin.h < midline_h and pin.w >= midline_w:
1031+
quadrants[2].add(pin)
1032+
if pin.h >= midline_h and pin.w >= midline_w:
1033+
quadrants[3].add(pin)
1034+
ret = []
1035+
for q in range(0,3):
1036+
ret.extend(sorted(quadrants[q]))
1037+
return ret
1038+
1039+
self._ordered_pins: List[GAPin] = []
1040+
pins, _ = self._get_all_pins()
1041+
pins -= self.bringup_pins.to_set()
1042+
self._ordered_pins = sort_by_quadrant(pins)
10331043

10341044
return super().model_post_init(__context)
10351045

@@ -1061,8 +1071,31 @@ def bringup_pins(self) -> BringupPins:
10611071

10621072
@property
10631073
def _power(self) -> List[PowerPins]:
1064-
return [PowerPins(1,2)]
1074+
#TODO build an internal padring mapping
1075+
# for now, just distribute evenly
1076+
power_pins = []
10651077

1078+
pins, inner = self._get_all_pins()
1079+
#allocate all of inner to core pins, alternating
1080+
try:
1081+
if inner:
1082+
it = iter(sorted(inner))
1083+
for p in it:
1084+
power_pins.append(PowerPins(p, next(it)))
1085+
except StopIteration:
1086+
pass
1087+
# distribute the rest evenly
1088+
try:
1089+
it = iter(sorted(pins))
1090+
for p in it:
1091+
for name in ('','d'):
1092+
power_pins.append(PowerPins(p, next(it)))
1093+
for i in range(0,15):
1094+
next(it)
1095+
except StopIteration:
1096+
pass
1097+
1098+
return power_pins
10661099

10671100
@property
10681101
def _jtag(self) -> JTAGPins:

chipflow_lib/platforms/silicon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from amaranth import Module, Signal, ClockDomain, ClockSignal, ResetSignal, unsigned
1515
from amaranth.lib import wiring, io, data
1616
from amaranth.lib.cdc import FFSynchronizer
17-
from amaranth.lib.wiring import Component, In, PureInterface
17+
from amaranth.lib.wiring import Component, In
1818
from amaranth.back import rtlil #type: ignore[reportAttributeAccessIssue]
1919
from amaranth.hdl import Fragment
2020
from amaranth.hdl._ir import PortDirection

0 commit comments

Comments
 (0)