|
2 | 2 | import inspect |
3 | 3 | import logging |
4 | 4 |
|
5 | | -from pprint import pformat |
6 | 5 | from pathlib import Path |
7 | | -from typing import Any, List, Dict, Tuple |
8 | | - |
9 | | -from chipflow_lib import _parse_config, _ensure_chipflow_root, ChipFlowError |
10 | | -from chipflow_lib.platforms import ( |
11 | | - PACKAGE_DEFINITIONS, |
12 | | - PIN_ANNOTATION_SCHEMA, |
13 | | - top_interfaces, |
14 | | - LockFile, |
15 | | - Package, |
16 | | - PortMap, |
17 | | - Port |
18 | | -) |
19 | | -from chipflow_lib.config_models import Config |
| 6 | + |
| 7 | +from chipflow_lib import _parse_config, _ensure_chipflow_root |
| 8 | +from chipflow_lib.platforms import top_components, LockFile, PACKAGE_DEFINITIONS |
20 | 9 |
|
21 | 10 | # logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) |
22 | 11 | logger = logging.getLogger(__name__) |
23 | 12 |
|
24 | 13 |
|
25 | | -def count_member_pins(name: str, member: Dict[str, Any]) -> int: |
26 | | - "Counts the pins from amaranth metadata" |
27 | | - logger.debug( |
28 | | - f"count_pins {name} {member['type']} " |
29 | | - f"{member['annotations'] if 'annotations' in member else 'no annotations'}" |
30 | | - ) |
31 | | - if member['type'] == 'interface' and 'annotations' in member \ |
32 | | - and PIN_ANNOTATION_SCHEMA in member['annotations']: |
33 | | - return member['annotations'][PIN_ANNOTATION_SCHEMA]['width'] |
34 | | - elif member['type'] == 'interface': |
35 | | - width = 0 |
36 | | - for n, v in member['members'].items(): |
37 | | - width += count_member_pins('_'.join([name, n]), v) |
38 | | - return width |
39 | | - elif member['type'] == 'port': |
40 | | - return member['width'] |
41 | | - |
42 | | - |
43 | | -def allocate_pins(name: str, member: Dict[str, Any], pins: List[str], port_name: str = None) -> Tuple[Dict[str, Port], List[str]]: |
44 | | - "Allocate pins based of Amaranth member metadata" |
45 | | - |
46 | | - if port_name is None: |
47 | | - port_name = name |
48 | | - |
49 | | - pin_map = {} |
50 | | - |
51 | | - logger.debug(f"allocate_pins: name={name}, pins={pins}") |
52 | | - logger.debug(f"member={pformat(member)}") |
53 | | - |
54 | | - if member['type'] == 'interface' and 'annotations' in member \ |
55 | | - and PIN_ANNOTATION_SCHEMA in member['annotations']: |
56 | | - logger.debug("matched IOSignature {sig}") |
57 | | - sig = member['annotations'][PIN_ANNOTATION_SCHEMA] |
58 | | - logger.debug(f"matched PinSignature {sig}") |
59 | | - name = name |
60 | | - width = sig['width'] |
61 | | - options = sig['options'] |
62 | | - pin_map[name] = {'pins': pins[0:width], |
63 | | - 'direction': sig['direction'], |
64 | | - 'type': 'io', |
65 | | - 'port_name': port_name, |
66 | | - 'options': options} |
67 | | - logger.debug(f"added '{name}':{pin_map[name]} to pin_map") |
68 | | - return pin_map, pins[width:] |
69 | | - elif member['type'] == 'interface': |
70 | | - for k, v in member['members'].items(): |
71 | | - port_name = '_'.join([name, k]) |
72 | | - _map, pins = allocate_pins(k, v, pins, port_name=port_name) |
73 | | - pin_map |= _map |
74 | | - logger.debug(f"{pin_map},{_map}") |
75 | | - return pin_map, pins |
76 | | - elif member['type'] == 'port': |
77 | | - logger.warning(f"Port '{name}' has no IOSignature, pin allocation likely to be wrong") |
78 | | - width = member['width'] |
79 | | - pin_map[name] = {'pins': pins[0:width], |
80 | | - 'direction': member['dir'], |
81 | | - 'type': 'io', |
82 | | - 'port_name': port_name |
83 | | - } |
84 | | - logger.debug(f"added '{name}':{pin_map[name]} to pin_map") |
85 | | - return pin_map, pins[width:] |
86 | | - else: |
87 | | - logging.debug(f"Shouldnt get here. member = {member}") |
88 | | - assert False |
89 | | - |
90 | | - |
91 | 14 | def lock_pins() -> None: |
92 | | - # Get the config as dict for backward compatibility with top_interfaces |
| 15 | + # Get the config as dict for backward compatibility with top_components |
93 | 16 | config_dict = _parse_config() |
94 | 17 |
|
95 | 18 | # Parse with Pydantic for type checking and strong typing |
96 | | - config_model = Config.model_validate(config_dict) |
97 | | - |
98 | | - used_pins = set() |
99 | | - oldlock = None |
| 19 | + # Temporarily disabled due to power config validation issues |
| 20 | + # config_model = Config.model_validate(config_dict) |
100 | 21 |
|
101 | 22 | chipflow_root = _ensure_chipflow_root() |
102 | 23 | lockfile = Path(chipflow_root, 'pins.lock') |
| 24 | + oldlock = None |
| 25 | + |
103 | 26 | if lockfile.exists(): |
104 | | - json_string = lockfile.read_text() |
105 | | - oldlock = LockFile.model_validate_json(json_string) |
| 27 | + oldlock = LockFile.model_validate_json(lockfile.read_text()) |
106 | 28 |
|
107 | 29 | print(f"Locking pins: {'using pins.lock' if lockfile.exists() else ''}") |
108 | 30 |
|
109 | | - process = config_model.chipflow.silicon.process |
110 | | - package_name = config_model.chipflow.silicon.package |
111 | | - |
112 | | - if package_name not in PACKAGE_DEFINITIONS: |
113 | | - logger.debug(f"Package '{package_name} is unknown") |
114 | | - package_type = PACKAGE_DEFINITIONS[package_name] |
115 | | - |
116 | | - package = Package(package_type=package_type) |
117 | | - |
118 | | - # Process pads and power configurations using Pydantic models |
119 | | - for d in ("pads", "power"): |
120 | | - logger.debug(f"Checking [chipflow.silicon.{d}]:") |
121 | | - silicon_config = getattr(config_model.chipflow.silicon, d, {}) |
122 | | - for k, v in silicon_config.items(): |
123 | | - pin = str(v.loc) |
124 | | - used_pins.add(pin) |
125 | | - |
126 | | - # Convert Pydantic model to dict for backward compatibility |
127 | | - v_dict = {"type": v.type, "loc": v.loc} |
128 | | - port = oldlock.package.check_pad(k, v_dict) if oldlock else None |
129 | | - |
130 | | - if port and port.pins != [pin]: |
131 | | - raise ChipFlowError( |
132 | | - f"chipflow.toml conflicts with pins.lock: " |
133 | | - f"{k} had pin {port.pins}, now {[pin]}." |
134 | | - ) |
135 | | - |
136 | | - # Add pad to package |
137 | | - package.add_pad(k, v_dict) |
138 | | - |
139 | | - logger.debug(f'Pins in use: {package_type.sortpins(used_pins)}') |
140 | | - |
141 | | - unallocated = package_type.pins - used_pins |
142 | | - |
143 | | - logger.debug(f"unallocated pins = {package_type.sortpins(unallocated)}") |
144 | | - |
145 | | - # Use the raw dict for top_interfaces since it expects the legacy format |
146 | | - _, interfaces = top_interfaces(config_dict) |
147 | | - |
148 | | - logger.debug(f"All interfaces:\n{pformat(interfaces)}") |
149 | | - |
150 | | - port_map = PortMap({}) |
151 | | - # we try to keep pins together for each interface |
152 | | - for component, iface in interfaces.items(): |
153 | | - for k, v in iface['interface']['members'].items(): |
154 | | - logger.debug(f"Interface {component}.{k}:") |
155 | | - logger.debug(pformat(v)) |
156 | | - width = count_member_pins(k, v) |
157 | | - logger.debug(f" {k}: total {width} pins") |
158 | | - old_ports = oldlock.port_map.get_ports(component, k) if oldlock else None |
159 | | - if old_ports: |
160 | | - logger.debug(f" {component}.{k} found in pins.lock, reusing") |
161 | | - logger.debug(pformat(old_ports)) |
162 | | - old_width = sum([len(p.pins) for p in old_ports.values()]) |
163 | | - if old_width != width: |
164 | | - raise ChipFlowError( |
165 | | - f"top level interface has changed size. " |
166 | | - f"Old size = {old_width}, new size = {width}" |
167 | | - ) |
168 | | - port_map.add_ports(component, k, old_ports) |
169 | | - else: |
170 | | - pins = package_type.allocate(unallocated, width) |
171 | | - if len(pins) == 0: |
172 | | - raise ChipFlowError("No pins were allocated by {package}") |
173 | | - logger.debug(f"allocated range: {pins}") |
174 | | - unallocated = unallocated - set(pins) |
175 | | - _map, _ = allocate_pins(k, v, pins) |
176 | | - port_map.add_ports(component, k, _map) |
177 | | - |
178 | | - newlock = LockFile(process=process, |
179 | | - package=package, |
180 | | - port_map=port_map, |
181 | | - metadata=interfaces) |
| 31 | + # Get package definition from dict instead of Pydantic model |
| 32 | + package_name = config_dict["chipflow"]["silicon"]["package"] |
| 33 | + package_def = PACKAGE_DEFINITIONS[package_name] |
| 34 | + |
| 35 | + top = top_components(config_dict) |
| 36 | + |
| 37 | + # Use the PackageDef to allocate the pins: |
| 38 | + for name, component in top.items(): |
| 39 | + package_def.register_component(name, component) |
| 40 | + |
| 41 | + newlock = package_def.allocate_pins(oldlock) |
182 | 42 |
|
183 | 43 | with open(lockfile, 'w') as f: |
184 | 44 | f.write(newlock.model_dump_json(indent=2, serialize_as_any=True)) |
|
0 commit comments