Skip to content

Commit 580ff8e

Browse files
committed
wip
1 parent 8a080b2 commit 580ff8e

File tree

4 files changed

+374
-289
lines changed

4 files changed

+374
-289
lines changed

chipflow_lib/__init__.py

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

chipflow_lib/cli.py

Lines changed: 39 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1,189 +1,63 @@
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"]
33-
34-
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_name": {
53-
"type": "string",
54-
},
55-
"top": {
56-
"type": "object",
57-
},
58-
"steps": {
59-
"type": "object",
60-
},
61-
"silicon": {
62-
"type": "object",
63-
"required": [
64-
"process",
65-
"pad_ring",
66-
"pads",
67-
],
68-
"additionalProperties": False,
69-
"properties": {
70-
"process": {
71-
"enum": ["sky130", "gf180", "customer1", "gf130bcd", "ihp_sg13g2"]
72-
},
73-
"pad_ring": {
74-
"enum": ["caravel", "cf20", "pga144"]
75-
},
76-
"pads": { "$ref": "#/$defs/pin" },
77-
"clocks": {
78-
"type": "object",
79-
"patternPropertues": {
80-
".+": { "type": "string"}
81-
},
82-
},
83-
"reset": { "type": "string"},
84-
"power": {
85-
"type": "object",
86-
"additionalProperties": False,
87-
"patternProperties": {
88-
".+": {
89-
"type": "object",
90-
"required": [
91-
"loc",
92-
],
93-
"additionalProperties": False,
94-
"properties": {
95-
"loc": {
96-
"type": "string",
97-
"pattern": "^[NSWE]?[0-9]+$"
98-
},
99-
}
100-
}
101-
}
102-
},
103-
104-
},
105-
},
106-
},
107-
},
108-
},
109-
"$defs": {
110-
"pin": {
111-
"type": "object",
112-
"additionalProperties": False,
113-
"minProperties": 1,
114-
"patternProperties": {
115-
".+": {
116-
"type": "object",
117-
"required": [
118-
"type",
119-
"loc",
120-
],
121-
"additionalProperties": False,
122-
"properties": {
123-
"type": {
124-
"enum": ["io", "i", "o", "oe", "clk"]
125-
},
126-
"loc": {
127-
"type": "string",
128-
"pattern": "^[NSWE]?[0-9]+$"
129-
},
130-
}
131-
}
132-
}
133-
}
134-
}
135-
}
136-
137-
138-
def _parse_config():
139-
chipflow_root = _ensure_chipflow_root()
140-
config_file = f"{chipflow_root}/chipflow.toml"
141-
return _parse_config_file(config_file)
3+
import inspect
4+
import sys
5+
import traceback
1426

7+
from pprint import pformat
1438

144-
def _parse_config_file(config_file):
145-
with open(config_file, "rb") as f:
146-
config_dict = tomli.load(f)
9+
from . import (
10+
ChipFlowError,
11+
_get_cls_by_reference,
12+
_ensure_chipflow_root,
13+
_parse_config,
14+
_parse_config_file
15+
)
16+
from .pin_lock import PinCommand
14717

148-
try:
149-
jsonschema.validate(config_dict, config_schema)
150-
return config_dict
151-
except jsonschema.ValidationError as e:
152-
raise ChipFlowError(f"Syntax error in `chipflow.toml` at `{'.'.join(e.path)}`: {e.message}")
15318

19+
class UnexpectedError(ChipFlowError):
20+
pass
15421

15522
def run(argv=sys.argv[1:]):
15623
config = _parse_config()
15724

158-
steps = {}
25+
commands = {}
26+
commands["pin"] = PinCommand(config)
27+
15928
for step_name, step_reference in config["chipflow"]["steps"].items():
16029
step_cls = _get_cls_by_reference(step_reference, context=f"step `{step_name}`")
16130
try:
162-
steps[step_name] = step_cls(config)
31+
commands[step_name] = step_cls(config)
16332
except Exception:
16433
raise ChipFlowError(f"Encountered error while initializing step `{step_name}` "
16534
f"using `{step_reference}`")
16635

16736
parser = argparse.ArgumentParser()
168-
step_argument = parser.add_subparsers(dest="step", required=True)
169-
for step_name, step_cls in steps.items():
170-
step_subparser = step_argument.add_parser(step_name, help=inspect.getdoc(step_cls))
37+
command_argument = parser.add_subparsers(dest="command", required=True)
38+
for command_name, command in commands.items():
39+
command_subparser = command_argument.add_parser(command_name, help=inspect.getdoc(command))
17140
try:
172-
step_cls.build_cli_parser(step_subparser)
41+
command.build_cli_parser(command_subparser)
17342
except Exception:
17443
raise ChipFlowError(f"Encountered error while building CLI argument parser for "
175-
f"step `{step_name}`")
44+
f"step `{command_name}`")
17645

177-
pins = parser.add_subparsers("pins")
178-
lock = lock.add_subparsers("lock")
17946
args = parser.parse_args(argv)
180-
try:
181-
steps[args.step].run_cli(args)
182-
except ChipFlowError:
183-
raise
184-
except Exception:
185-
raise ChipFlowError(f"Encountered error while running CLI for step `{args.step}`")
186-
18747

188-
if __name__ == '__main__':
189-
run()
48+
try:
49+
try:
50+
commands[args.command].run_cli(args)
51+
except ChipFlowError:
52+
raise
53+
except Exception as e:
54+
raise UnexpectedError(
55+
f"Unexpected error, please report to ChipFlow:\n"
56+
f"args =\n{pformat(args)}\n"
57+
f"traceback =\n{''.join(traceback.format_exception(e))}"
58+
) from e
59+
except ChipFlowError as e:
60+
cmd = args.command
61+
if hasattr(args, "action"):
62+
cmd += f" {args.action}"
63+
print(f"Error while excuting `{cmd}`: {e}")

0 commit comments

Comments
 (0)