@@ -88,7 +88,7 @@ class IOModel(TypedDict):
8888 """
8989
9090 width : NotRequired [int ]
91- direction : NotRequired [io .Direction ]
91+ direction : NotRequired [Annotated [ io .Direction , PlainSerializer ( lambda x : str ( x ))] ]
9292 all_have_oe : NotRequired [bool ]
9393 allocate_power : NotRequired [bool ]
9494 power_voltage : NotRequired [VoltageRange ]
@@ -214,7 +214,7 @@ def BidirIOSignature(width:int , **kwargs: Unpack[IOModel]):
214214 return IOSignature (** kwargs )
215215
216216
217- Pin = Union [tuple , str , int ]
217+ Pin = Union [Tuple [ Any ,...] , str , int ]
218218PinSet = Set [Pin ]
219219PinList = List [Pin ]
220220Pins = Union [PinSet , PinList ]
@@ -400,12 +400,9 @@ def _allocate_pins(name: str, member: Dict[str, Any], pins: List[str], port_name
400400 logger .debug (f"matched PinSignature { sig } " )
401401 name = name
402402 width = sig ['width' ]
403- options = sig ['options' ]
404403 pin_map [name ] = {'pins' : pins [0 :width ],
405- 'direction' : sig ['direction' ],
406404 'type' : 'io' ,
407- 'port_name' : port_name ,
408- 'options' : options }
405+ 'port_name' : port_name } | sig
409406 logger .debug (f"added '{ name } ':{ pin_map [name ]} to pin_map" )
410407 return pin_map , pins [width :]
411408 elif member ['type' ] == 'interface' :
@@ -501,17 +498,16 @@ class LockFile(pydantic.BaseModel):
501498 metadata : dict
502499
503500
504- PackageDef = Union ['GAPackageDef' , 'QuadPackageDef' , 'BareDiePackageDef' , 'BasePackageDef' ]
505-
501+ PackageDef = Union ['GAPackageDef' , 'QuadPackageDef' , 'BareDiePackageDef' ]
506502
507503class Package (pydantic .BaseModel ):
508504 """
509505 Serialisable identifier for a defined packaging option
510506 """
511- package_type : PackageDef = pydantic .Field (discriminator = "package_type" )
507+ type : PackageDef = pydantic .Field (discriminator = "package_type" )
512508
513509
514- def _linear_allocate_components (interfaces : dict , lockfile : LockFile , allocate , unallocated ) -> PortMap :
510+ def _linear_allocate_components (interfaces : dict , lockfile : LockFile | None , allocate , unallocated ) -> PortMap :
515511 port_map = PortMap ()
516512 for component , iface in interfaces .items ():
517513 for k , v in iface ['interface' ]['members' ].items ():
@@ -534,7 +530,7 @@ def _linear_allocate_components(interfaces: dict, lockfile: LockFile , allocate,
534530 else :
535531 pins = allocate (unallocated , width )
536532 if len (pins ) == 0 :
537- raise ChipFlowError ("No pins were allocated by {package} " )
533+ raise ChipFlowError ("No pins were allocated" )
538534 logger .debug (f"allocated range: { pins } " )
539535 unallocated = unallocated - set (pins )
540536 _map , _ = _allocate_pins (k , v , pins )
@@ -558,9 +554,6 @@ class BasePackageDef(pydantic.BaseModel, abc.ABC):
558554
559555 """
560556
561- # Used by pydantic to differentate when deserialising,
562- # override appropriately when you subclass
563- package_type : Literal ["BasePackageDef" ] = "BasePackageDef"
564557 name : str
565558
566559 def model_post_init (self , __context ):
@@ -579,7 +572,7 @@ def register_component(self, name: str, component: wiring.Component) -> None:
579572
580573
581574 @abc .abstractmethod
582- def allocate_pins (self , lockfile : Optional [LockFile ]) -> LockFile :
575+ def allocate_pins (self , process : 'Process' , lockfile : Optional [LockFile ]) -> LockFile :
583576 """
584577 Allocate package pins to the registered component.
585578 Pins should be allocated in the most usable way for *users* of the packaged IC.
@@ -622,16 +615,16 @@ class BareDiePackageDef(BasePackageDef):
622615 height : int
623616
624617 def model_post_init (self , __context ):
625- pins = (
626- set (itertools .product ((_Side .N , _Side .S ), range (self .width )))
627- | set (itertools .product ((_Side .W , _Side .E ), range (self .height )))
628- - set (self .bringup_pins .to_set ())
629- )
630- self ._ordered_pins = sorted (pins )
618+ pins = set (itertools .product ((_Side .N , _Side .S ), range (self .width )))
619+ pins |= set (itertools .product ((_Side .W , _Side .E ), range (self .height )))
620+ pins -= set (self .bringup_pins .to_set ())
621+
622+ self ._ordered_pins : List [Pin ] = sorted (pins )
631623 return super ().model_post_init (__context )
632624
633- def allocate_pins (self , lockfile : LockFile | None ) -> 'LockFile' :
634- return _linear_allocate_components (self ._interfaces , lockfile , self ._allocate , set (self ._ordered_pins ))
625+ def allocate_pins (self , process : 'Process' , lockfile : LockFile | None ) -> LockFile :
626+ portmap = _linear_allocate_components (self ._interfaces , lockfile , self ._allocate , set (self ._ordered_pins ))
627+ return LockFile (package = Package (type = self ), process = process , metadata = self ._interfaces , port_map = portmap )
635628
636629 @property
637630 def bringup_pins (self ) -> BringupPins :
@@ -703,19 +696,20 @@ class QuadPackageDef(BasePackageDef):
703696 allocate_jtag : bool = True
704697
705698 def model_post_init (self , __context ):
706- pins = (
707- set ([i for i in range (1 , self .width * 2 + self .height * 2 )])
708- - set (self ._power )
709- - self ._jtag .to_set ()
710- )
711- self ._ordered_pins = sorted (pins )
699+ pins = set ([i for i in range (1 , self .width * 2 + self .height * 2 )])
700+ pins .difference_update (* [x .to_set () for x in self ._power ])
701+ pins .difference_update (self ._jtag .to_set ())
702+
703+ self ._ordered_pins : List [Pin ] = sorted (pins )
712704 return super ().model_post_init (__context )
713705
714- def allocate_pins (self , lockfile : LockFile | None ) -> 'LockFile' :
715- return _linear_allocate_components (self ._interfaces , lockfile , self ._allocate , set (self ._ordered_pins ))
706+ def allocate_pins (self , process : 'Process' , lockfile : LockFile | None ) -> 'LockFile' :
707+ portmap = _linear_allocate_components (self ._interfaces , lockfile , self ._allocate , set (self ._ordered_pins ))
708+ return LockFile (package = Package (type = self ), process = process , metadata = self ._interfaces , port_map = portmap )
716709
717- def _allocate (self , available : Set [int ], width : int ) -> List [int ]:
718- avail_n = sorted (available )
710+
711+ def _allocate (self , available : Set [int ], width : int ) -> List [Pin ]:
712+ avail_n : List [Pin ] = sorted (available )
719713 logger .debug (f"QuadPackageDef.allocate { width } from { len (avail_n )} remaining: { available } " )
720714 ret = _find_contiguous_sequence (self ._ordered_pins , avail_n , width )
721715 logger .debug (f"QuadPackageDef.returned { ret } " )
@@ -743,19 +737,23 @@ def _power(self) -> List[PowerPins]:
743737 pins = []
744738 n = (self .width + self .height )// 12
745739 # Left
746- pins .append (self .height // 2 + self .height // 2 + 1 )
740+ p = self .height // 2 + self .height // 2
741+ pins .append (PowerPins (p , p + 1 ))
747742 # Bottom
748743 start = self .height
749744 if n > 2 :
750- pins .append (start + self .width // 2 + self .width // 2 + 1 )
745+ p = start + self .width // 2 + self .width // 2
746+ pins .append (PowerPins (p , p + 1 ))
751747 # Right
752748 start = start + self .width
753749 if n > 1 :
754- pins .append (start + self .height // 2 + self .height // 2 + 1 )
750+ p = start + self .height // 2 + self .height // 2
751+ pins .append (PowerPins (p , p + 1 ))
755752 # Top
756753 start = start + self .height
757754 if n > 3 :
758- pins .append (start + self .width // 2 + self .width // 2 + 1 )
755+ p = start + self .width // 2 + self .width // 2
756+ pins .append (PowerPins (p , p + 1 ))
759757 return pins
760758
761759
@@ -861,11 +859,11 @@ def int_to_alpha(i: int):
861859 out = valid_letters [char - 1 ] + out
862860 return out
863861
864- def pins_for_range (h1 : int , h2 : int , w1 : int , w2 : int ) -> Set [GAPin ]:
862+ def pins_for_range (h1 : int , h2 : int , w1 : int , w2 : int ) -> Set [Pin ]:
865863 pins = [GAPin (int_to_alpha (h ),w ) for h in range (h1 , h2 ) for w in range (w1 , w2 )]
866864 return set (pins )
867865
868- def sort_by_quadrant (pins : Set [GAPin ]) -> List [GAPin ]:
866+ def sort_by_quadrant (pins : Set [GAPin ]) -> List [Pin ]:
869867 quadrants :List [Set [GAPin ]] = [set (), set (), set (), set ()]
870868 midline_h = int_to_alpha (self .height // 2 )
871869 midline_w = self .width // 2
@@ -883,6 +881,7 @@ def sort_by_quadrant(pins: Set[GAPin]) -> List[GAPin]:
883881 ret .append (sorted (quadrants [q ]))
884882 return ret
885883
884+ self ._ordered_pins : List [Pin ] = []
886885 match self .layout_type :
887886 case GALayout .FULL :
888887 pins = pins_for_range (1 , self .height , 1 , self .width )
@@ -917,8 +916,9 @@ def sort_by_quadrant(pins: Set[GAPin]) -> List[GAPin]:
917916 return super ().model_post_init (__context )
918917
919918
920- def allocate_pins (self , lockfile : LockFile | None ) -> 'LockFile' :
921- return _linear_allocate_components (self ._interfaces , lockfile , self ._allocate , set (self ._ordered_pins ))
919+ def allocate_pins (self , process : 'Process' , lockfile : LockFile | None ) -> 'LockFile' :
920+ portmap = _linear_allocate_components (self ._interfaces , lockfile , self ._allocate , set (self ._ordered_pins ))
921+ return LockFile (package = Package (type = self ), process = process , metadata = self ._interfaces , port_map = portmap )
922922
923923 def _allocate (self , available : Set [str ], width : int ) -> List [str ]:
924924 avail_n = sorted (available )
0 commit comments