Skip to content

Commit 7de18d4

Browse files
committed
Add config_models.py file for Pydantic validation
1 parent f26ae0b commit 7de18d4

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

chipflow_lib/config_models.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
import enum
3+
import re
4+
from typing import Dict, List, Optional, Union, Literal, Any
5+
6+
from pydantic import BaseModel, Field, model_validator, ValidationInfo, field_validator
7+
8+
from .platforms.utils import Process
9+
10+
11+
class PadConfig(BaseModel):
12+
"""Configuration for a pad in chipflow.toml."""
13+
type: Literal["io", "i", "o", "oe", "clock", "reset", "power", "ground"]
14+
loc: str
15+
16+
@model_validator(mode="after")
17+
def validate_loc_format(self):
18+
"""Validate that the location is in the correct format."""
19+
if not re.match(r"^[NSWE]?[0-9]+$", self.loc):
20+
raise ValueError(f"Invalid location format: {self.loc}, expected format: [NSWE]?[0-9]+")
21+
return self
22+
23+
@classmethod
24+
def validate_pad_dict(cls, v: dict, info: ValidationInfo):
25+
"""Custom validation for pad dicts from TOML that may not have all fields."""
26+
if isinstance(v, dict):
27+
# Handle legacy format - if 'type' is missing but should be inferred from context
28+
if 'loc' in v and 'type' not in v:
29+
if info.field_name == 'power':
30+
v['type'] = 'power'
31+
32+
# Map legacy 'clk' type to 'clock' to match our enum
33+
if 'type' in v and v['type'] == 'clk':
34+
v['type'] = 'clock'
35+
36+
return v
37+
return v
38+
39+
40+
class SiliconConfig(BaseModel):
41+
"""Configuration for silicon in chipflow.toml."""
42+
process: Process
43+
package: Literal["caravel", "cf20", "pga144"]
44+
pads: Dict[str, PadConfig] = {}
45+
power: Dict[str, PadConfig] = {}
46+
debug: Optional[Dict[str, bool]] = None
47+
48+
@field_validator('pads', 'power', mode='before')
49+
@classmethod
50+
def validate_pad_dicts(cls, v, info: ValidationInfo):
51+
"""Pre-process pad dictionaries to handle legacy format."""
52+
if isinstance(v, dict):
53+
result = {}
54+
for key, pad_dict in v.items():
55+
# Apply the pad validator with context about which field we're in
56+
validated_pad = PadConfig.validate_pad_dict(pad_dict, info)
57+
result[key] = validated_pad
58+
return result
59+
return v
60+
61+
62+
class StepsConfig(BaseModel):
63+
"""Configuration for steps in chipflow.toml."""
64+
silicon: str
65+
66+
67+
class ChipFlowConfig(BaseModel):
68+
"""Root configuration for chipflow.toml."""
69+
project_name: Optional[str] = None
70+
top: Dict[str, Any] = {}
71+
steps: StepsConfig
72+
silicon: SiliconConfig
73+
clocks: Optional[Dict[str, str]] = None
74+
resets: Optional[Dict[str, str]] = None
75+
76+
77+
class Config(BaseModel):
78+
"""Root configuration model for chipflow.toml."""
79+
chipflow: ChipFlowConfig

0 commit comments

Comments
 (0)