11import json
2- import logging
32import re
4- import sys
53
6- from amaranth import Shape
4+ from pprint import pprint
75from pathlib import Path
8- from pprint import pformat
96
10- from chipflow_lib . platforms . iostream import PORT_LAYOUT_SCHEMA
7+ from amaranth import Shape
118from chipflow_lib .cli import _parse_config , _get_cls_by_reference
12-
13- logger = logging .getLogger (__name__ )
9+ from chipflow_lib .platforms import PACKAGE_DEFINITIONS
1410
1511def has_consecutive_numbers (lst ):
1612 if not lst :
@@ -69,114 +65,111 @@ def coalesce_triples(sig: dict) -> None:
6965 if sig ['type' ] == 'port' :
7066 pass
7167
72- def count_pins (port ):
73- width = 0
74- for _ , v in port . items ():
75- if type ( v ) is dict :
68+ def count_pins (member ):
69+ if member [ 'type' ] == 'interface' :
70+ width = 0
71+ for _ , v in member [ 'members' ]. items () :
7672 width += count_pins (v )
73+ return width
74+ elif member ['type' ] == 'port' :
75+ return member ['width' ]
76+
77+ def allocate_pins (name , member , pins , pin_map ):
78+ print (f"allocate_pins: { pins } " )
79+ if member ['type' ] == 'interface' :
80+ for k , v in member ['members' ].items ():
81+ n = '_' .join ([name ,k ])
82+ pins = allocate_pins (n , v , pins , pin_map )
83+ return pins
84+ elif member ['type' ] == 'port' :
85+ name = name
86+ width = member ['width' ]
87+ if width == 1 :
88+ pin_map [name ] = {'pin' :pins [0 ], 'type' :member ['dir' ]}
7789 else :
78- width += v [1 ]
79- return width
80-
81-
82- def allocate_pins (name , port , pins ):
83- pin_map = {}
84- logger .debug (f"allocate_pins: name={ name } , port={ port } , pins={ pins } " )
85- for k , v in port .items ():
86- n = '_' .join ([name ,k ])
87- logger .debug (f"{ k } ,{ v } ,{ n } " )
88- if type (v ) is dict :
89- _map , pins = allocate_pins (n , v , pins )
90- pin_map |= _map
91- logger .debug (f"{ pin_map } ,{ _map } " )
90+ pin_map [name ] = {'start' :pins [0 ],
91+ 'end' :pins [width - 1 ],
92+ 'type' :member ['dir' ]}
93+ return pins [width :]
94+
95+
96+ def check_pins (name , member , old_map , new_map ):
97+ if member ['type' ] == 'interface' :
98+ for k , v in member ['members' ].items ():
99+ n = '_' .join ([name ,k ])
100+ check_pins (n , v , old_map , new_map )
101+ elif member ['type' ] == 'port' :
102+ width = member ['width' ]
103+ if width == 1 :
104+ assert 'pin' in old_map [name ]
92105 else :
93- direction , width = v
106+ assert 'start' in old_map [name ]
107+ assert 'end' in old_map [name ]
108+ assert old_map [name ]['end' ] - old_map [name ]['start' ] + 1 == width
109+ new_map [name ] = old_map [name ]
110+
111+ def connect_pins (pin_map ):
112+ for k ,v in interfaces .items ():
113+ if member ['type' ] == 'interface' :
114+ for k , v in member ['members' ].items ():
115+ n = '_' .join ([name ,k ])
116+ check_pins (n , v , old_map , new_map )
117+ elif member ['type' ] == 'port' :
118+ width = member ['width' ]
94119 if width == 1 :
95- pin_map [ n ] = { 'pin' : pins [ 0 ], 'type' : direction }
120+ assert 'pin' in old_map [ name ]
96121 else :
97- pin_map [n ] = {'start' :pins [0 ],
98- 'end' :pins [width - 1 ],
99- 'type' :direction }
100- logger .debug (f"pin_map[{ n } ]={ pin_map [n ]} " )
101- pins = pins [width :]
102- return pin_map , pins
103-
104-
105- def assign_pins (ports , old_lock , unallocated ):
106- old_ports = old_lock ["ports" ] if "ports" in old_lock else {}
107- old_map = old_lock ["map" ]["ports" ] if "map" in old_lock else {}
108- pin_map = {}
109-
110- # we try to keep pins together for each port
111- for k ,v in ports .items ():
112- logger .debug (f"Port { k } :\n { pformat (v )} " )
113- width = count_pins (v )
114- logger .debug (f"member { k } total width = { width } " )
115-
116- if k in old_ports :
117- logger .debug (f"{ k } already has pins defined" )
118- if width != count_pins (old_ports [k ]):
119- raise Exception ("Port {k} has changed size. Use -c to allocate new pins non-contigously" )
120- _map = old_map [k ]
121- old_pins = [v ['pin' ] for v in old_map [k ].values ()]
122- logger .debug ("old pins = {old_pins}" )
123- unallocated = sorted (list (set (unallocated ) - set (old_pins )))
124- else :
125- pins = find_consecutive_sequence (unallocated , width )
126- logger .debug (f"allocated range: { pins } " )
127- if pins is None :
128- raise Exception (f"Error allocating pins for { k } ,{ v } in { ports } " )
129-
130-
131- newpins = unallocated [pins ]
132- unallocated [pins ] = []
133- _map ,_ = allocate_pins (k , v , newpins )
134-
135- pin_map [k ] = _map
136- return pin_map
122+ assert 'start' in old_map [name ]
123+ assert 'end' in old_map [name ]
124+ assert old_map [name ]['end' ] - old_map [name ]['start' ] + 1 == width
125+ new_map [name ] = old_map [name ]
137126
138127
139- logging .basicConfig (level = logging .DEBUG , stream = sys .stdout )
140128config = _parse_config ()
141129used_pins = set ()
142130pin_map = {}
143131lockfile = Path ('pins.lock' )
144132if lockfile .exists ():
145133 with open (lockfile ) as f :
146134 old_lock = json .load (f )
147- old_map = old_lock ["map" ]
135+ old_interfaces = old_lock ['interfaces' ]
136+ old_map = old_lock ['map' ]
148137else :
149- old_lock = {}
150138 old_map = {}
139+ old_interfaces = {}
140+
141+ package = config ["chipflow" ]["silicon" ]["padring" ]
151142
152- for d , default in [("pads" , "i" ), ("power" ,"pwr" )]:
153- logger .debug (f"Checking [chipflow.silicon.{ d } ]:" )
154- pin_map [d ] = {}
143+ if package not in PACKAGE_DEFINITIONS :
144+ print (f"Package '{ package } is unknown" )
145+
146+ for d in ("pads" , "power" ):
147+ print (f"Checking [chipflow.silicon.{ d } ]:" )
155148 for k , v in config ["chipflow" ]["silicon" ][d ].items ():
156- pin = int ( v ['loc' ])
149+ pin = v ['loc' ]
157150 used_pins .add (pin )
158- if d in old_map and k in old_map [ d ] and old_map [ d ] [k ]['pin' ] != pin :
151+ if k in old_map and old_map [k ]['pin' ] != pin :
159152 print (f"chipflow.toml conflicts with pins.lock: "
160- f"{ k } had pin { old_map [d ][ k ]} , now { pin } ." )
153+ f"{ k } had pin { old_map [k ]} , now { pin } ." )
161154 exit (1 )
162- pin_map [d ][ k ] = {
155+ pin_map [k ] = {
163156 'pin' : pin ,
164157 'type' : v ['type' ] if 'type' in v else None }
165158
166159
167- logger . info (f'Pins in use:\n { pformat ( sorted (used_pins ) )} ' )
160+ print (f'Pins in use: { sorted (used_pins )} ' )
168161
169- unallocated = sorted (set ( range ( 144 )) - used_pins )
162+ unallocated = sorted (PACKAGE_DEFINITIONS [ package ] - used_pins )
170163
171- ports = {}
164+ interfaces = {}
172165top_components = config ["chipflow" ]["top" ].items ()
173166component_configs = {}
174167top = {}
175168
176169for name , conf in top_components :
177170 if '.' in name :
178171 assert conf is dict
179- logger . debug ("Config found for {name}" )
172+ print ("Config found for {name}" )
180173 component_configs [name .split ('.' )[0 ]] = conf
181174
182175for name , ref in top_components :
@@ -186,16 +179,38 @@ def assign_pins(ports, old_lock, unallocated):
186179 else :
187180 top [name ] = cls ()
188181 metadata = top [name ].metadata .as_json ()
189- logger .debug (f"{ name } .metadata = { metadata } " )
190- ports |= metadata ['interface' ]['annotations' ][PORT_LAYOUT_SCHEMA ]['ports' ]
191-
192- logger .debug (f"All ports: { list (ports .keys ())} " )
193-
194- pin_map ["ports" ] = assign_pins (ports , old_lock , unallocated )
182+ interfaces |= metadata ['interface' ]['members' ]
183+
184+ print (f"All interfaces: { interfaces .keys ()} " )
185+ pin_map_interfaces = {}
186+
187+ # we try to keep pins together for each interface
188+ for k ,v in interfaces .items ():
189+ print (f"Interface { k } :" )
190+ pprint (v )
191+ width = count_pins (v )
192+ print (f"member { k } total width = { width } " )
193+ pins = find_consecutive_sequence (unallocated , width )
194+ print (f"allocated range: { pins } " )
195+ if pins is None :
196+ print ("ERROR" )
197+ if k in old_interfaces :
198+ if old_interfaces [k ]['start' ] != pins .start or \
199+ old_interfaces [k ]['end' ] != pins .stop :
200+ # TODO: option to allocate new pins nonconsecutively
201+ print ("top level interface has changed size" )
202+ exit (1 )
203+ check_pins (k , v , old_map , pin_map )
204+ pin_map_interfaces [k ] = {'top' : True , 'start' :pins .start , 'end' :pins .stop }
205+ else :
206+ pin_map_interfaces [k ] = {'top' : True , 'start' :pins .start , 'end' :pins .stop }
207+ newpins = unallocated [pins ]
208+ unallocated [pins ] = []
209+ allocate_pins (k , v , newpins , pin_map )
195210
196211with open ('pins.lock' , 'w' ) as f :
197- newlock = {'map ' : pin_map ,
198- 'ports ' : ports }
212+ newlock = {'interfaces ' : pin_map_interfaces ,
213+ 'map ' : pin_map }
199214
200215 json .dump (newlock , f , indent = 2 , sort_keys = True )
201216#
0 commit comments