11import inspect
22import json
33import logging
4- import re
5- import sys
64
75from pprint import pformat
86from pathlib import Path
97
10- from amaranth import Shape
11- from chipflow_lib import _parse_config , _get_cls_by_reference
12- from chipflow_lib .platforms import PACKAGE_DEFINITIONS , PIN_ANNOTATION_SCHEMA
8+ from chipflow_lib import _parse_config
9+ from chipflow_lib . platforms import PACKAGE_DEFINITIONS , PIN_ANNOTATION_SCHEMA , top_interfaces
10+ from chipflow_lib .platforms . utils import LockFile , Package , Interface , Port
1311
1412# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
1513logger = logging .getLogger (__name__ )
@@ -30,7 +28,7 @@ def count_pins(name, member):
3028
3129def count_old_pins (d ):
3230 match d :
33- case {'type' :t , 'pins' :p }:
31+ case {'type' :_ , 'pins' :p }:
3432 return len (p )
3533 case _:
3634 return sum ([count_old_pins (v ) for v in d .values ()])
@@ -52,15 +50,14 @@ def allocate_pins(name, member, pins:list):
5250 'type' :'io' }
5351 return pin_map , pins [width :]
5452 elif member ['type' ] == 'interface' :
55- logger .warning ("member without PinSignature, pin allocation likely to be wrong" )
5653 for k , v in member ['members' ].items ():
5754 n = '_' .join ([name ,k ])
5855 _map , pins = allocate_pins (n , v , pins )
5956 pin_map |= _map
6057 logger .debug (f"{ pin_map } ,{ _map } " )
6158 return pin_map , pins
6259 elif member ['type' ] == 'port' :
63- logger .warning (f"Component ` { name } ` in this design is not using PinSignature " )
60+ logger .warning (f"Port ' { name } ' has no PinSignature, pin allocation likely to be wrong " )
6461 name = name
6562 width = member ['width' ]
6663 direction = member ['dir' ]
@@ -87,93 +84,79 @@ def check_pins(name, member, old_map, new_map):
8784def lock_pins ():
8885 config = _parse_config ()
8986 used_pins = set ()
90- pin_map = {}
87+ newlock = LockFile ()
88+ oldlock = None
9189 lockfile = Path ('pins.lock' )
9290 if lockfile .exists ():
93- with open (lockfile ) as f :
94- old_lock = json .load (f )
95- old_map = old_lock ['map' ]
96- else :
97- old_map = {}
91+ json_string = lockfile .read_text ()
92+ oldlock = LockFile .model_validate_json (json_string )
93+
9894 print (f"Locking pins: { 'using pins.lock' if lockfile .exists () else '' } " )
9995 package_name = config ["chipflow" ]["silicon" ]["pad_ring" ]
10096
10197 if package_name not in PACKAGE_DEFINITIONS :
102- logger .debug (f"Package '{ package } is unknown" )
98+ logger .debug (f"Package '{ package_name } is unknown" )
10399 package = PACKAGE_DEFINITIONS [package_name ]
104100
101+ newlock .package .package_name = package_name
105102 for d in ("pads" , "power" ):
106103 logger .debug (f"Checking [chipflow.silicon.{ d } ]:" )
104+ _map = {}
107105 for k , v in config ["chipflow" ]["silicon" ][d ].items ():
108106 pin = str (v ['loc' ])
109107 used_pins .add (pin )
110- if k in old_map and old_map [k ]['pins' ] != [pin ]:
108+ if d in old_map and k in old_map [ d ] and old_map [ d ] [k ]['pins' ] != [pin ]:
111109 print (f"chipflow.toml conflicts with pins.lock: "
112110 f"{ k } had pin { old_map [k ]['pins' ]} , now { [pin ]} ." )
113111 exit (1 )
114- pin_map [k ] = {
112+ _map [k ] = {
115113 'pins' : [pin ],
116- 'type' : v ['type' ] if 'type' in v else None }
114+ 'type' : v ['type' ] if 'type' in v else d }
115+ pin_map [d ] = _map
117116
118117
119118 logger .debug (f'Pins in use: { sorted (used_pins )} ' )
120119
121120 unallocated = package .pins - used_pins
122121
123122 logger .debug (f"unallocated pins = { sorted (unallocated )} " )
124- interfaces = {}
125- top_components = config ["chipflow" ]["top" ].items ()
126- component_configs = {}
127- top = {}
128-
129- for name , conf in top_components :
130- if '.' in name :
131- assert conf is dict
132- logger .debug ("Config found for {name}" )
133- component_configs [name .split ('.' )[0 ]] = conf
134-
135- for name , ref in top_components :
136- cls = _get_cls_by_reference (ref , context = f"top component: { name } " )
137- if name in component_configs :
138- top [name ] = cls (component_configs [name ])
139- else :
140- top [name ] = cls ()
141- logger .debug (pformat (top [name ].metadata .origin .signature .members ))
142- metadata = top [name ].metadata .as_json ()
143- interfaces |= metadata ['interface' ]['members' ]
144-
145- logger .debug (f"All interfaces: { interfaces .keys ()} " )
146- pin_map_interfaces = {}
123+
124+ _ , interfaces = top_interfaces (config )
125+
126+ logger .debug (f"All interfaces: { [v .keys () for i in interfaces ]} " )
147127
148128 # we try to keep pins together for each interface
149- for k ,v in interfaces .items ():
150- logger .debug (f"Interface { k } :" )
151- logger .debug (pformat (v ))
152- width = count_pins (k , v )
153- print (f" { k } : total { width } pins" )
154- if k in old_map :
155- print (f" { k } found in pins.lock, reusing" )
156- logger .debug (pformat (old_map [k ]))
157- old_width = count_old_pins (old_map [k ])
158- if old_width != width :
159- # TODO: option to allocate new pins nonconsecutively
160- print (f"top level interface has changed size. Old size = { old_width } , new size = { width } " )
161- exit (1 )
162- pin_map [k ] = old_map [k ]
163- else :
164- pins = package .allocate (unallocated , width )
165- if len (pins ) == 0 :
166- print ("ERROR: No pins were allocation by {package}" )
167- exit (1 )
168- logger .debug (f"allocated range: { pins } " )
169- unallocated = unallocated - set (pins )
170- _map , _ = allocate_pins (k , v , pins )
171- pin_map [k ] = _map
129+ for component , iface in interfaces .items ():
130+ pin_map [component ] = {}
131+ for k ,v in iface .items ():
132+ logger .debug (f"Interface { component } .{ k } :" )
133+ logger .debug (pformat (v ))
134+ width = count_pins (k , v )
135+ print (f" { k } : total { width } pins" )
136+ if component in old_map and k in old_map [component ]:
137+ print (f" { component } .{ k } found in pins.lock, reusing" )
138+ logger .debug (pformat (old_map [component ][k ]))
139+ old_width = count_old_pins (old_map [k ])
140+ if old_width != width :
141+ # TODO: option to allocate new pins nonconsecutively
142+ print (f"top level interface has changed size. Old size = { old_width } , new size = { width } " )
143+ exit (1 )
144+ pin_map [component ][k ] = old_map [component ][k ]
145+ else :
146+ pins = package .allocate (unallocated , width )
147+ if len (pins ) == 0 :
148+ print ("ERROR: No pins were allocation by {package}" )
149+ exit (1 )
150+ logger .debug (f"allocated range: { pins } " )
151+ unallocated = unallocated - set (pins )
152+ _map , _ = allocate_pins (k , v , pins )
153+ pin_map [component ][k ] = _map
172154
173155 with open ('pins.lock' , 'w' ) as f :
174156 newlock = {'map' : pin_map ,
175- 'metadata' : metadata }
157+ 'metadata' : interfaces }
176158
159+ assert _LockFile .model_validate (newlock )
177160 json .dump (newlock , f , indent = 2 , sort_keys = True )
178161
179162class PinCommand :
@@ -182,7 +165,7 @@ def __init__(self, config):
182165
183166 def build_cli_parser (self , parser ):
184167 action_argument = parser .add_subparsers (dest = "action" )
185- prepare_subparser = action_argument .add_parser (
168+ action_argument .add_parser (
186169 "lock" , help = inspect .getdoc (self .lock ).splitlines ()[0 ])
187170
188171 def run_cli (self , args ):
0 commit comments