Skip to content

Commit 9d633f7

Browse files
committed
Add pin-lock functionality and remove providers
In order to remove the need for users to define their own SiliconStep and pin layout.This introduces a number of mechanisms: - PinSignature: a mechanism for Components to label wiring that should be routed to pads/pins and the requriments. - Pin lock mechanism: addition of `pins` subcommand to `chipflow` cli tool. This inspects the top level components and maps the ports to pins, with pin behaviour defined by the package definition. - Package definitions - basis for package definitions in chipflow-lib - General purpose SiliconStep Still remaining follow on changes are: - Encoding power, clock, heartbeat and jtag pin locations in package definitions. - Pin lock for FPGA boards - Removal of need for user to define other steps (sim, software, board, export verilog)
1 parent f10918f commit 9d633f7

File tree

13 files changed

+989
-571
lines changed

13 files changed

+989
-571
lines changed

chipflow_lib/__init__.py

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,144 @@
1-
# SPDX-License-Identifier: BSD-2-Clause
1+
import importlib.metadata
2+
import jsonschema
3+
import os
4+
import sys
5+
import tomli
6+
7+
__version__ = importlib.metadata.version("chipflow_lib")
8+
29

310
class ChipFlowError(Exception):
411
pass
12+
13+
14+
def _get_cls_by_reference(reference, context):
15+
module_ref, _, class_ref = reference.partition(":")
16+
try:
17+
module_obj = importlib.import_module(module_ref)
18+
except ModuleNotFoundError as e:
19+
raise ChipFlowError(f"Module `{module_ref}` referenced by {context} is not found") from e
20+
try:
21+
return getattr(module_obj, class_ref)
22+
except AttributeError as e:
23+
raise ChipFlowError(f"Module `{module_ref}` referenced by {context} does not define "
24+
f"`{class_ref}`") from e
25+
26+
27+
def _ensure_chipflow_root():
28+
if "CHIPFLOW_ROOT" not in os.environ:
29+
os.environ["CHIPFLOW_ROOT"] = os.getcwd()
30+
if os.environ["CHIPFLOW_ROOT"] not in sys.path:
31+
sys.path.append(os.environ["CHIPFLOW_ROOT"])
32+
return os.environ["CHIPFLOW_ROOT"]
33+
34+
35+
# TODO: convert to pydantic, one truth of source for the schema
36+
config_schema = {
37+
"$schema": "https://json-schema.org/draft/2020-12/schema",
38+
"$id": "https://chipflow.io/meta/chipflow.toml.schema.json",
39+
"title": "chipflow.toml",
40+
"type": "object",
41+
"required": [
42+
"chipflow"
43+
],
44+
"properties": {
45+
"chipflow": {
46+
"type": "object",
47+
"required": [
48+
"steps",
49+
"silicon"
50+
],
51+
"additionalProperties": False,
52+
"properties": {
53+
"project_name": {
54+
"type": "string",
55+
},
56+
"top": {
57+
"type": "object",
58+
},
59+
"steps": {
60+
"type": "object",
61+
},
62+
"clocks": {
63+
"type": "object",
64+
"patternPropertues": {
65+
".+": {"type": "string"}
66+
},
67+
},
68+
"resets": {
69+
"type": "object",
70+
"patternPropertues": {
71+
".+": {"type": "string"}
72+
},
73+
},
74+
"silicon": {
75+
"type": "object",
76+
"required": [
77+
"process",
78+
"package",
79+
],
80+
"additionalProperties": False,
81+
"properties": {
82+
"process": {
83+
"enum": ["sky130", "gf180", "customer1", "gf130bcd", "ihp_sg13g2"]
84+
},
85+
"package": {
86+
"enum": ["caravel", "cf20", "pga144"]
87+
},
88+
"pads": {"$ref": "#/$defs/pin"},
89+
"power": {"$ref": "#/$defs/pin"},
90+
"debug": {
91+
"type": "object",
92+
"properties": {
93+
"heartbeat": {"type": "boolean"}
94+
}
95+
}
96+
},
97+
},
98+
},
99+
},
100+
},
101+
"$defs": {
102+
"pin": {
103+
"type": "object",
104+
"additionalProperties": False,
105+
"minProperties": 1,
106+
"patternProperties": {
107+
".+": {
108+
"type": "object",
109+
"required": [
110+
"type",
111+
"loc",
112+
],
113+
"additionalProperties": False,
114+
"properties": {
115+
"type": {
116+
"enum": ["io", "i", "o", "oe", "clock", "reset", "power", "ground"]
117+
},
118+
"loc": {
119+
"type": "string",
120+
"pattern": "^[NSWE]?[0-9]+$"
121+
},
122+
}
123+
}
124+
}
125+
}
126+
}
127+
}
128+
129+
130+
def _parse_config():
131+
chipflow_root = _ensure_chipflow_root()
132+
config_file = f"{chipflow_root}/chipflow.toml"
133+
return _parse_config_file(config_file)
134+
135+
136+
def _parse_config_file(config_file):
137+
with open(config_file, "rb") as f:
138+
config_dict = tomli.load(f)
139+
140+
try:
141+
jsonschema.validate(config_dict, config_schema)
142+
return config_dict
143+
except jsonschema.ValidationError as e:
144+
raise ChipFlowError(f"Syntax error in `chipflow.toml` at `{'.'.join(e.path)}`: {e.message}")

chipflow_lib/cli.py

Lines changed: 59 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,173 +1,83 @@
11
# SPDX-License-Identifier: BSD-2-Clause
2-
3-
import os
4-
import sys
5-
import inspect
6-
import importlib
72
import argparse
8-
import tomli
9-
import jsonschema
10-
11-
from . import ChipFlowError
12-
13-
14-
def _get_cls_by_reference(reference, context):
15-
module_ref, _, class_ref = reference.partition(":")
16-
try:
17-
module_obj = importlib.import_module(module_ref)
18-
except ModuleNotFoundError as e:
19-
raise ChipFlowError(f"Module `{module_ref}` referenced by {context} is not found")
20-
try:
21-
return getattr(module_obj, class_ref)
22-
except AttributeError as e:
23-
raise ChipFlowError(f"Module `{module_ref}` referenced by {context} does not define "
24-
f"`{class_ref}`") from None
25-
26-
27-
def _ensure_chipflow_root():
28-
if "CHIPFLOW_ROOT" not in os.environ:
29-
os.environ["CHIPFLOW_ROOT"] = os.getcwd()
30-
if os.environ["CHIPFLOW_ROOT"] not in sys.path:
31-
sys.path.append(os.environ["CHIPFLOW_ROOT"])
32-
return os.environ["CHIPFLOW_ROOT"]
3+
import inspect
4+
import sys
5+
import traceback
6+
import logging
337

8+
from pprint import pformat
349

35-
config_schema = {
36-
"$schema": "https://json-schema.org/draft/2020-12/schema",
37-
"$id": "https://chipflow.io/meta/chipflow.toml.schema.json",
38-
"title": "chipflow.toml",
39-
"type": "object",
40-
"required": [
41-
"chipflow"
42-
],
43-
"properties": {
44-
"chipflow": {
45-
"type": "object",
46-
"required": [
47-
"steps",
48-
"silicon"
49-
],
50-
"additionalProperties": False,
51-
"properties": {
52-
"project_id": {
53-
"type": "integer",
54-
},
55-
"steps": {
56-
"type": "object",
57-
},
58-
"silicon": {
59-
"type": "object",
60-
"required": [
61-
"process",
62-
"pad_ring",
63-
"pads",
64-
],
65-
"additionalProperties": False,
66-
"properties": {
67-
"process": {
68-
"enum": ["sky130", "gf180", "customer1", "gf130bcd", "ihp_sg13g2"]
69-
},
70-
"pad_ring": {
71-
"enum": ["caravel", "cf20", "pga144"]
72-
},
73-
"pads": {
74-
"type": "object",
75-
"additionalProperties": False,
76-
"minProperties": 1,
77-
"patternProperties": {
78-
".+": {
79-
"type": "object",
80-
"required": [
81-
"type",
82-
"loc",
83-
],
84-
"additionalProperties": False,
85-
"properties": {
86-
"type": {
87-
"enum": ["io", "i", "o", "oe", "clk"]
88-
},
89-
"loc": {
90-
"type": "string",
91-
"pattern": "^[NSWE]?[0-9]+$"
92-
},
93-
}
94-
}
95-
}
96-
},
97-
"power": {
98-
"type": "object",
99-
"additionalProperties": False,
100-
"patternProperties": {
101-
".+": {
102-
"type": "object",
103-
"required": [
104-
"loc",
105-
],
106-
"additionalProperties": False,
107-
"properties": {
108-
"loc": {
109-
"type": "string",
110-
"pattern": "^[NSWE]?[0-9]+$"
111-
},
112-
}
113-
}
114-
}
115-
},
116-
}
117-
},
118-
},
119-
}
120-
}
121-
}
10+
from . import (
11+
ChipFlowError,
12+
_get_cls_by_reference,
13+
_parse_config,
14+
)
15+
from .pin_lock import PinCommand
12216

12317

124-
def _parse_config():
125-
chipflow_root = _ensure_chipflow_root()
126-
config_file = f"{chipflow_root}/chipflow.toml"
127-
return _parse_config_file(config_file)
18+
logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
12819

12920

130-
def _parse_config_file(config_file):
131-
with open(config_file, "rb") as f:
132-
config_dict = tomli.load(f)
133-
134-
try:
135-
jsonschema.validate(config_dict, config_schema)
136-
return config_dict
137-
except jsonschema.ValidationError as e:
138-
raise ChipFlowError(f"Syntax error in `chipflow.toml` at `{'.'.join(e.path)}`: {e.message}")
21+
class UnexpectedError(ChipFlowError):
22+
pass
13923

14024

14125
def run(argv=sys.argv[1:]):
14226
config = _parse_config()
14327

144-
steps = {}
28+
commands = {}
29+
commands["pin"] = PinCommand(config)
30+
14531
for step_name, step_reference in config["chipflow"]["steps"].items():
14632
step_cls = _get_cls_by_reference(step_reference, context=f"step `{step_name}`")
14733
try:
148-
steps[step_name] = step_cls(config)
34+
commands[step_name] = step_cls(config)
14935
except Exception:
15036
raise ChipFlowError(f"Encountered error while initializing step `{step_name}` "
151-
f"using `{step_reference}`")
152-
153-
parser = argparse.ArgumentParser()
154-
step_argument = parser.add_subparsers(dest="step", required=True)
155-
for step_name, step_cls in steps.items():
156-
step_subparser = step_argument.add_parser(step_name, help=inspect.getdoc(step_cls))
37+
f"using `{step_reference}`")
38+
39+
parser = argparse.ArgumentParser(
40+
prog="chipflow",
41+
description="Command line tool for interacting with the ChipFlow platform")
42+
43+
parser.add_argument(
44+
"--verbose", "-v",
45+
dest="log_level",
46+
action="append_const",
47+
const=10,
48+
help="increase verbosity of messages; can be supplied multiple times to increase verbosity"
49+
)
50+
51+
command_argument = parser.add_subparsers(dest="command", required=True)
52+
for command_name, command in commands.items():
53+
command_subparser = command_argument.add_parser(command_name, help=inspect.getdoc(command))
15754
try:
158-
step_cls.build_cli_parser(step_subparser)
55+
command.build_cli_parser(command_subparser)
15956
except Exception:
16057
raise ChipFlowError(f"Encountered error while building CLI argument parser for "
161-
f"step `{step_name}`")
58+
f"step `{command_name}`")
16259

60+
# each verbose flag increases versbosity (e.g. -v -v, -vv, --verbose --verbose)
61+
# cute trick using append_const and summing
16362
args = parser.parse_args(argv)
164-
try:
165-
steps[args.step].run_cli(args)
166-
except ChipFlowError:
167-
raise
168-
except Exception:
169-
raise ChipFlowError(f"Encountered error while running CLI for step `{args.step}`")
170-
63+
if args.log_level:
64+
log_level = max(logging.DEBUG, logging.WARNING - sum(args.log_level))
65+
logging.getLogger().setLevel(log_level)
17166

172-
if __name__ == '__main__':
173-
run()
67+
try:
68+
try:
69+
commands[args.command].run_cli(args)
70+
except ChipFlowError:
71+
raise
72+
except Exception as e:
73+
# convert to ChipFlowError so all handling is same.
74+
raise UnexpectedError(
75+
f"Unexpected error, please report to ChipFlow:\n"
76+
f"args =\n{pformat(args)}\n"
77+
f"traceback =\n{''.join(traceback.format_exception(e))}"
78+
) from e
79+
except ChipFlowError as e:
80+
cmd = args.command
81+
if hasattr(args, "action"):
82+
cmd += f" {args.action}"
83+
print(f"Error while executing `{cmd}`: {e}")

chipflow_lib/errors.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
class ChipFlowError(Exception):
3+
pass

0 commit comments

Comments
 (0)