Skip to content

Commit e85eb47

Browse files
committed
Add openframe package support
1 parent bec37ac commit e85eb47

21 files changed

+563
-240
lines changed

chipflow_lib/_appresponse.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
3+
from dataclasses import dataclass
4+
5+
from pydantic import BaseModel, PlainSerializer, model_serializer
6+
7+
@dataclass
8+
class OmitIfNone:
9+
pass
10+
11+
class AppResponseModel(BaseModel):
12+
@model_serializer
13+
def _serialize(self):
14+
skip_if_none = set()
15+
serialize_aliases = dict()
16+
17+
# Gather fields that should omit if None
18+
for name, field_info in self.model_fields.items():
19+
if any(
20+
isinstance(metadata, OmitIfNone) for metadata in field_info.metadata
21+
):
22+
skip_if_none.add(name)
23+
elif field_info.serialization_alias:
24+
serialize_aliases[name] = field_info.serialization_alias
25+
26+
serialized = dict()
27+
28+
for name, value in self:
29+
# Skip serializing None if it was marked with "OmitIfNone"
30+
if value is None and name in skip_if_none:
31+
continue
32+
serialize_key = serialize_aliases.get(name, name)
33+
34+
# Run Annotated PlainSerializer
35+
for metadata in self.model_fields[name].metadata:
36+
if isinstance(metadata, PlainSerializer):
37+
value = metadata.func(value) # type: ignore
38+
39+
serialized[serialize_key] = value
40+
41+
return serialized

chipflow_lib/cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# SPDX-License-Identifier: BSD-2-Clause
2+
23
import argparse
34
import inspect
45
import sys

chipflow_lib/config_models.py

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,23 @@
11
# SPDX-License-Identifier: BSD-2-Clause
2-
import re
3-
from typing import Dict, Optional, Literal, Any, List
2+
from typing import Dict, Optional, Any, List
43

5-
from pydantic import BaseModel, model_validator, ValidationInfo, field_validator
4+
from pydantic import BaseModel
65

7-
from .platforms.utils import Process
6+
from .platforms._internal import PACKAGE_DEFINITIONS, Process, Voltage
87

9-
class PadConfig(BaseModel):
10-
"""Configuration for a pad in chipflow.toml."""
11-
type: Literal["io", "i", "o", "oe", "clock", "reset", "power", "ground"]
12-
loc: str
138

14-
@model_validator(mode="after")
15-
def validate_loc_format(self):
16-
"""Validate that the location is in the correct format."""
17-
if not re.match(r"^[NSWE]?[0-9]+$", self.loc):
18-
raise ValueError(f"Invalid location format: {self.loc}, expected format: [NSWE]?[0-9]+")
19-
return self
9+
def known_package(package: str):
10+
if package not in PACKAGE_DEFINITIONS.keys():
11+
raise ValueError(f"{package} is not a valid package type. Valid package types are {PACKAGE_DEFINITIONS.keys()}")
2012

21-
@classmethod
22-
def validate_pad_dict(cls, v: dict, info: ValidationInfo):
23-
"""Custom validation for pad dicts from TOML that may not have all fields."""
24-
if isinstance(v, dict):
25-
# Handle legacy format - if 'type' is missing but should be inferred from context
26-
if 'loc' in v and 'type' not in v:
27-
if info.field_name == 'power':
28-
v['type'] = 'power'
29-
30-
# Map legacy 'clk' type to 'clock' to match our enum
31-
if 'type' in v and v['type'] == 'clk':
32-
v['type'] = 'clock'
33-
34-
return v
35-
return v
36-
37-
38-
Voltage = float
3913

4014
class SiliconConfig(BaseModel):
4115
"""Configuration for silicon in chipflow.toml."""
4216
process: 'Process'
43-
package: Literal["caravel", "cf20", "pga144"]
17+
package: str
4418
power: Dict[str, Voltage] = {}
4519
debug: Optional[Dict[str, bool]] = None
4620
# This is still kept around to allow forcing pad locations.
47-
pads: Optional[Dict[str, PadConfig]] = {}
48-
49-
@field_validator('pads', 'power', mode='before')
50-
@classmethod
51-
def validate_pad_dicts(cls, v, info: ValidationInfo):
52-
"""Pre-process pad dictionaries to handle legacy format."""
53-
if isinstance(v, dict):
54-
result = {}
55-
for key, pad_dict in v.items():
56-
# Apply the pad validator with context about which field we're in
57-
validated_pad = PadConfig.validate_pad_dict(pad_dict, info)
58-
result[key] = validated_pad
59-
return result
60-
return v
6121

6222

6323
class ChipFlowConfig(BaseModel):

chipflow_lib/pin_lock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pprint import pformat
77

88
from . import _parse_config, _ensure_chipflow_root, ChipFlowError
9-
from .platforms import top_components, LockFile, PACKAGE_DEFINITIONS
9+
from .platforms._internal import top_components, LockFile, PACKAGE_DEFINITIONS
1010

1111
# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
1212
logger = logging.getLogger(__name__)

chipflow_lib/platforms/__init__.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
77
"""
88

9-
from .silicon import *
10-
from .sim import *
11-
from .utils import *
9+
from .silicon import SiliconPlatformPort, SiliconPlatform
10+
from .sim import SimPlatform
11+
from .utils import (
12+
IO_ANNOTATION_SCHEMA, IOSignature, IOModel,
13+
OutputIOSignature, InputIOSignature, BidirIOSignature,
14+
)
15+
from ._packages import PACKAGE_DEFINITIONS
1216

1317
__all__ = ['IO_ANNOTATION_SCHEMA', 'IOSignature', 'IOModel',
1418
'OutputIOSignature', 'InputIOSignature', 'BidirIOSignature',
15-
'load_pinlock', "PACKAGE_DEFINITIONS", 'top_components', 'LockFile',
16-
'Package', 'PortMap', 'Port', 'Process',
17-
'GAPackageDef', 'QuadPackageDef', 'BareDiePackageDef', 'BasePackageDef',
18-
'BringupPins', 'JTAGPins', 'PowerPins',
1919
'SiliconPlatformPort', 'SiliconPlatform',
20-
'SimPlatform']
20+
'SimPlatform',
21+
'PACKAGE_DEFINITIONS']
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from .silicon import *
2+
from .sim import *
3+
from .utils import *
4+
from ._packages import *
5+
__all__ = ['IO_ANNOTATION_SCHEMA', 'IOSignature', 'IOModel',
6+
'OutputIOSignature', 'InputIOSignature', 'BidirIOSignature',
7+
'load_pinlock', "PACKAGE_DEFINITIONS", 'top_components', 'LockFile',
8+
'Package', 'PortMap', 'PortDesc', 'Process',
9+
'GAPackageDef', 'QuadPackageDef', 'BareDiePackageDef', 'BasePackageDef',
10+
'BringupPins', 'JTAGPins', 'PowerPins',
11+
'SiliconPlatformPort', 'SiliconPlatform',
12+
'SimPlatform']
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
from typing import List, NamedTuple, Optional, Literal
2+
3+
from .utils import Voltage, PowerPins, LinearAllocPackageDef, BringupPins
4+
5+
class OFPin(NamedTuple):
6+
pin: int
7+
kind: str
8+
idx: int = 0
9+
voltage: Optional[Voltage] = None
10+
name: Optional[str] = None
11+
12+
OF_GPIO = [
13+
OFPin(31, "gpio", 0), # gpio[0]
14+
OFPin(32, "gpio", 1), # gpio[1]
15+
OFPin(33, "gpio", 2), # gpio[2]
16+
OFPin(34, "gpio", 3), # gpio[3]
17+
OFPin(35, "gpio", 4), # gpio[4]
18+
OFPin(36, "gpio", 5), # gpio[5]
19+
OFPin(37, "gpio", 6), # gpio[6]
20+
OFPin(41, "gpio", 7), # gpio[7]
21+
OFPin(42, "gpio", 8), # gpio[8]
22+
OFPin(43, "gpio", 9), # gpio[9]
23+
OFPin(44, "gpio", 10), # gpio[10]
24+
OFPin(45, "gpio", 11), # gpio[11]
25+
OFPin(46, "gpio", 12), # gpio[12]
26+
OFPin(48, "gpio", 13), # gpio[13]
27+
OFPin(50, "gpio", 14), # gpio[14]
28+
OFPin(51, "gpio", 15), # gpio[15]
29+
OFPin(53, "gpio", 16), # gpio[16]
30+
OFPin(54, "gpio", 17), # gpio[17]
31+
OFPin(55, "gpio", 18), # gpio[18]
32+
OFPin(57, "gpio", 19), # gpio[19]
33+
OFPin(58, "gpio", 20), # gpio[20]
34+
OFPin(59, "gpio", 21), # gpio[21]
35+
OFPin(60, "gpio", 22), # gpio[22]
36+
OFPin(61, "gpio", 23), # gpio[23]
37+
OFPin(62, "gpio", 24), # gpio[24]
38+
OFPin(2, "gpio", 25), # gpio[25]
39+
OFPin(3, "gpio", 26), # gpio[26]
40+
OFPin(4, "gpio", 27), # gpio[27]
41+
OFPin(5, "gpio", 28), # gpio[28]
42+
OFPin(6, "gpio", 29), # gpio[29]
43+
OFPin(7, "gpio", 30), # gpio[30]
44+
OFPin(8, "gpio", 31), # gpio[31]
45+
OFPin(11, "gpio", 32), # gpio[32]
46+
OFPin(12, "gpio", 33), # gpio[33]
47+
OFPin(13, "gpio", 34), # gpio[34]
48+
OFPin(14, "gpio", 35), # gpio[35]
49+
OFPin(15, "gpio", 36), # gpio[36]
50+
OFPin(16, "gpio", 37), # gpio[37]
51+
# OFPin(22, "gpio", 38) # gpio[38] is assigned as clock
52+
# OFPin(24, "gpio", 39) # gpio[39] is assigned as heartbeat
53+
# OFPin(25, "gpio", 40), # gpio[40] is assign as reset
54+
OFPin(26, "gpio", 41), # gpio[41]
55+
OFPin(27, "gpio", 42), # gpio[42]
56+
OFPin(28, "gpio", 43), # gpio[43]
57+
]
58+
59+
OF_CLOCK_PIN = OFPin(22, "gpio", 38)
60+
OF_HEARTBEAT_PIN = OFPin(24, "gpio", 39)
61+
OF_RESET_PIN = OFPin(25, "gpio", 40)
62+
63+
OF_CORE_POWER = [
64+
(OFPin(18,"vcc", voltage=1.8, name="d"), # Power, Digital power supply
65+
OFPin(23,"vss", name="d")), # Digital power ground
66+
]
67+
68+
OF_OTHER_POWER= [
69+
(OFPin(30,"vdd", voltage=3.3, name="a"), # Power, Analog power supply
70+
OFPin(20,"vss", name="a")), # Analog power ground
71+
72+
(OFPin(49,"vcc", voltage=1.8, name="d1"), # Power, Digital power supply
73+
OFPin(39,"vss", name="d1")), # Digital power ground
74+
75+
(OFPin(17,"vdd", voltage=3.3, name="io"), # Power, ESD and padframe power supply
76+
OFPin(29,"vss", name="io")), # ESD and padframe ground
77+
78+
(OFPin(64,"vdd", voltage=3.3, name="io"), # Power, ESD and padframe power supply
79+
OFPin(56,"vss", name="io")), # ESD and padframe ground
80+
81+
(OFPin(63,"vcc", voltage=1.8, name="d2"), # Power, Digital power supply
82+
OFPin(10,"vss", name="d2")), # Digital power ground
83+
84+
(OFPin(40,"vdd", voltage=3.3, name="a1"), # Power, Analog power supply
85+
OFPin(38,"vss", name="a1")), # Analog power ground
86+
87+
(OFPin(47,"vdd", voltage=3.3, name="a1"), # Power, Analog power supply
88+
OFPin(52,"vss", name="a1")), # Analog power ground
89+
90+
(OFPin(9,"vdd", voltage=3.3, name="a2"), # Power, Analog power supply
91+
OFPin(1,"vss", name="a2")), # Analog power ground
92+
]
93+
94+
OF_OTHER = [
95+
OFPin(19, "NC") # Not connected
96+
]
97+
98+
class OpenframePackageDef(LinearAllocPackageDef):
99+
100+
name: str = "openframe"
101+
package_type: Literal["OpenframePackageDef"] = "OpenframePackageDef"
102+
def model_post_init(self, __context):
103+
self._ordered_pins = OF_GPIO
104+
105+
super().model_post_init(__context)
106+
107+
108+
@property
109+
def _core_power(self) -> List[PowerPins]:
110+
pps = []
111+
112+
for power, ground in OF_CORE_POWER:
113+
pp = PowerPins(power=power, ground=ground, voltage=power.voltage)
114+
pps.append(pp)
115+
116+
return pps
117+
118+
@property
119+
def bringup_pins(self) -> BringupPins:
120+
return BringupPins(
121+
core_power=self._core_power,
122+
core_clock=OF_CLOCK_PIN,
123+
core_reset=OF_RESET_PIN,
124+
core_heartbeat=OF_HEARTBEAT_PIN,
125+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from .utils import QuadPackageDef, BareDiePackageDef, GAPackageDef, Package
2+
from ._openframe import OpenframePackageDef
3+
4+
# Add any new package types to both PACKAGE_DEFINITIONS and the PackageDef union
5+
PACKAGE_DEFINITIONS = {
6+
"pga144": QuadPackageDef(name="pga144", width=36, height=36),
7+
"cf20": BareDiePackageDef(name="cf20", width=7, height=3),
8+
"openframe": OpenframePackageDef()
9+
}
10+
11+
Package.model_rebuild()

0 commit comments

Comments
 (0)