Skip to content

Commit 15d31eb

Browse files
committed
variables: move code from make to defaults.py
Signed-off-by: Øyvind Harboe <[email protected]>
1 parent 5e5387f commit 15d31eb

File tree

2 files changed

+187
-82
lines changed

2 files changed

+187
-82
lines changed

flow/Makefile

Lines changed: 22 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ DESIGN_CONFIG ?= ./designs/nangate45/gcd/config.mk
9090
# this file.
9191
include $(DESIGN_CONFIG)
9292
export DESIGN_NICKNAME?=$(DESIGN_NAME)
93+
export DESIGN_DIR = $(dir $(DESIGN_CONFIG))
9394
# default value "base" is duplicated from variables.yaml because we need it
9495
# earlier in the flow for BLOCKS. BLOCKS is a feature specific to Makefile
9596
# that will not be ported to bazel-orfs.
@@ -178,85 +179,32 @@ include $(PLATFORM_DIR)/config.mk
178179

179180
# __SPACE__ is a workaround for whitespace hell in "foreach"; there
180181
# is no way to escape space in defaults.py and get "foreach" to work.
181-
$(foreach line,$(shell $(SCRIPTS_DIR)/defaults.py),$(eval export $(subst __SPACE__, ,$(line))))
182+
#
183+
# Note! We need to explicitly pass in the environment variables that
184+
# defaults.py *uses* to compute the list of default values. We do NOT
185+
# need to pass in *all* environment variables. defaults.py does not
186+
# use the default value to modify the environment, it computes default
187+
# values for environment variables and has options to print out
188+
# the information in different formats.
189+
$(foreach line,$(shell \
190+
FLOW_HOME=$(FLOW_HOME) \
191+
DESIGN_NAME=$(DESIGN_NAME) \
192+
DESIGN_NICKNAME=$(DESIGN_NICKNAME) \
193+
WORK_HOME=$(WORK_HOME) \
194+
PLATFORM=$(PLATFORM) \
195+
NUM_CORES=$(NUM_CORES) \
196+
TIME_BIN=$(TIME_BIN) \
197+
IN_NIX_SHELL=$(IN_NIX_SHELL) \
198+
OPENROAD_EXE=$(OPENROAD_EXE) \
199+
OPENSTA_EXE=$(OPENSTA_EXE) \
200+
YOSYS_EXE=$(YOSYS_EXE) \
201+
KLAYOUT_CMD=$(KLAYOUT_CMD) \
202+
$(SCRIPTS_DIR)/defaults.py),$(eval export $(subst __SPACE__, ,$(line))))
182203

183204
# Not normally adjusted by user
184205
export SYNTH_OPERATIONS_ARGS ?= -extra-map $(FLOW_HOME)/platforms/common/lcu_kogge_stone.v
185206
export SYNTH_FULL_ARGS ?= $(SYNTH_ARGS) $(SYNTH_OPERATIONS_ARGS)
186207

187-
export DESIGN_CONFIG
188-
export DESIGN_DIR = $(dir $(DESIGN_CONFIG))
189-
export LOG_DIR = $(WORK_HOME)/logs/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)
190-
export OBJECTS_DIR = $(WORK_HOME)/objects/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)
191-
export REPORTS_DIR = $(WORK_HOME)/reports/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)
192-
export RESULTS_DIR = $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)
193-
194-
#-------------------------------------------------------------------------------
195-
ifeq (,$(strip $(NUM_CORES)))
196-
# Linux (utility program)
197-
NUM_CORES := $(shell nproc 2>/dev/null)
198-
199-
ifeq (,$(strip $(NUM_CORES)))
200-
# Linux (generic)
201-
NUM_CORES := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
202-
endif
203-
ifeq (,$(strip $(NUM_CORES)))
204-
# BSD (at least FreeBSD and Mac OSX)
205-
NUM_CORES := $(shell sysctl -n hw.ncpu 2>/dev/null)
206-
endif
207-
ifeq (,$(strip $(NUM_CORES)))
208-
# Fallback
209-
NUM_CORES := 1
210-
endif
211-
endif
212-
export NUM_CORES
213-
214-
#-------------------------------------------------------------------------------
215-
# setup all commands used within this flow
216-
export TIME_BIN ?= env time
217-
TIME_CMD = $(TIME_BIN) -f 'Elapsed time: %E[h:]min:sec. CPU time: user %U sys %S (%P). Peak memory: %MKB.'
218-
TIME_TEST = $(shell $(TIME_CMD) echo foo 2>/dev/null)
219-
ifeq (,$(strip $(TIME_TEST)))
220-
TIME_CMD = $(TIME_BIN)
221-
endif
222-
223-
# The following determine the executable location for each tool used by this flow.
224-
# Priority is given to
225-
# 1 user explicit set with variable in Makefile or command line, for instance setting OPENROAD_EXE
226-
# 2 ORFS compiled tools: openroad, yosys
227-
ifneq (${IN_NIX_SHELL},)
228-
export OPENROAD_EXE := $(shell command -v openroad)
229-
else
230-
export OPENROAD_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/OpenROAD/bin/openroad)
231-
endif
232-
ifneq (${IN_NIX_SHELL},)
233-
export OPENSTA_EXE := $(shell command -v sta)
234-
else
235-
export OPENSTA_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/OpenROAD/bin/sta)
236-
endif
237-
238-
OPENROAD_ARGS = -no_init -threads $(NUM_CORES) $(OR_ARGS)
239-
OPENROAD_CMD = $(OPENROAD_EXE) -exit $(OPENROAD_ARGS)
240-
OPENROAD_NO_EXIT_CMD = $(OPENROAD_EXE) $(OPENROAD_ARGS)
241-
OPENROAD_GUI_CMD = $(OPENROAD_EXE) -gui $(OR_ARGS)
242-
243-
ifneq (${IN_NIX_SHELL},)
244-
YOSYS_EXE := $(shell command -v yosys)
245-
else
246-
YOSYS_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/yosys/bin/yosys)
247-
endif
248-
249-
# Use locally installed and built klayout if it exists, otherwise use klayout in path
250-
KLAYOUT_DIR = $(abspath $(FLOW_HOME)/../tools/install/klayout/)
251-
KLAYOUT_BIN_FROM_DIR = $(KLAYOUT_DIR)/klayout
252-
253-
ifeq ($(wildcard $(KLAYOUT_BIN_FROM_DIR)), $(KLAYOUT_BIN_FROM_DIR))
254-
KLAYOUT_CMD ?= sh -c 'LD_LIBRARY_PATH=$(dir $(KLAYOUT_BIN_FROM_DIR)) $$0 "$$@"' $(KLAYOUT_BIN_FROM_DIR)
255-
else
256-
ifeq ($(KLAYOUT_CMD),)
257-
KLAYOUT_CMD := $(shell command -v klayout)
258-
endif
259-
endif
260208
KLAYOUT_FOUND = $(if $(KLAYOUT_CMD),,$(error KLayout not found in PATH))
261209

262210
ifneq ($(shell command -v stdbuf),)

flow/scripts/defaults.py

Lines changed: 165 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,172 @@
11
#!/usr/bin/env python3
22

33
import os
4+
import multiprocessing
5+
import subprocess
46
import yaml
57

6-
dir_path = os.path.dirname(os.path.realpath(__file__))
78

8-
yaml_path = os.path.join(dir_path, "variables.yaml")
9-
with open(yaml_path, "r") as file:
10-
data = yaml.safe_load(file)
9+
def get_num_cores():
10+
"""Determine the number of CPU cores available."""
11+
try:
12+
# Linux (utility program)
13+
num_cores = int(
14+
subprocess.check_output(["nproc"], stderr=subprocess.DEVNULL).strip()
15+
)
16+
except (subprocess.CalledProcessError, FileNotFoundError):
17+
try:
18+
# Linux (generic)
19+
with open("/proc/cpuinfo", "r") as f:
20+
num_cores = sum(1 for line in f if line.startswith("processor"))
21+
except FileNotFoundError:
22+
try:
23+
# BSD (at least FreeBSD and macOS)
24+
num_cores = int(
25+
subprocess.check_output(
26+
["sysctl", "-n", "hw.ncpu"], stderr=subprocess.DEVNULL
27+
).strip()
28+
)
29+
except (subprocess.CalledProcessError, FileNotFoundError):
30+
# Fallback
31+
num_cores = 1
32+
return num_cores
1133

12-
for key, value in data.items():
13-
if value.get("default", None) is None:
14-
continue
15-
print(f'export {key}?={str(value["default"]).replace(" ", "__SPACE__")}')
34+
35+
def env_blank(name):
36+
return name not in os.environ or os.environ[name] == ""
37+
38+
39+
def get_time_cmd(time_bin):
40+
"""Set up the time command with appropriate formatting."""
41+
time_cmd = f"{time_bin} -f 'Elapsed time: %E[h:]min:sec. CPU time: user %U sys %S (%P). Peak memory: %MKB.'"
42+
43+
try:
44+
# Test if the time command works
45+
subprocess.run(
46+
f"{time_cmd} echo foo",
47+
shell=True,
48+
check=True,
49+
stderr=subprocess.DEVNULL,
50+
stdout=subprocess.DEVNULL,
51+
)
52+
except subprocess.CalledProcessError:
53+
# Fallback to a simpler time command if the test fails
54+
time_cmd = time_bin
55+
56+
return time_cmd
57+
58+
59+
def main():
60+
dir_path = os.path.dirname(os.path.realpath(__file__))
61+
62+
yaml_path = os.path.join(dir_path, "variables.yaml")
63+
with open(yaml_path, "r") as file:
64+
info = yaml.safe_load(file)
65+
66+
variables = {
67+
name: value["default"] for name, value in info.items() if "default" in value
68+
}
69+
70+
# 'variables' is a dictionary that contains settings. Historically,
71+
# these settings were managed in variables in the Makefile. We are
72+
# moving code from the Makefile to Python to generate the
73+
# entries in the 'variables' dictionary.
74+
for name in ["FLOW_HOME", "WORK_HOME", "PLATFORM", "DESIGN_NAME"]:
75+
variables[name] = os.environ[name]
76+
77+
if env_blank("DESIGN_NICKNAME"):
78+
variables["DESIGN_NICKNAME"] = variables["DESIGN_NAME"]
79+
else:
80+
variables["DESIGN_NICKNAME"] = os.environ["DESIGN_NAME"]
81+
82+
for name, folder in [
83+
("OBJECTS_DIR", "objects"),
84+
("REPORTS_DIR", "reports"),
85+
("RESULTS_DIR", "results"),
86+
("LOG_DIR", "logs"),
87+
]:
88+
variables[name] = os.path.join(
89+
variables["WORK_HOME"],
90+
folder,
91+
variables["PLATFORM"],
92+
variables["DESIGN_NICKNAME"],
93+
variables["FLOW_VARIANT"],
94+
)
95+
96+
if env_blank("NUM_CORES"):
97+
variables["NUM_CORES"] = get_num_cores()
98+
else:
99+
variables["NUM_CORES"] = os.environ["NUM_CORES"]
100+
101+
if env_blank("TIME_BIN"):
102+
variables["TIME_BIN"] = "env time"
103+
else:
104+
variables["TIME_BIN"] = os.environ["TIME_BIN"]
105+
variables["TIME_CMD"] = get_time_cmd(variables["TIME_BIN"])
106+
107+
if not env_blank("IN_NIX_SHELL"):
108+
variables["OPENROAD_EXE"] = subprocess.getoutput("command -v openroad")
109+
variables["OPENSTA_EXE"] = subprocess.getoutput("command -v sta")
110+
else:
111+
variables["OPENROAD_EXE"] = (
112+
os.path.abspath(
113+
os.path.join(
114+
variables["FLOW_HOME"], "../tools/install/OpenROAD/bin/openroad"
115+
)
116+
)
117+
if env_blank("OPENROAD_EXE")
118+
else os.environ["OPENROAD_EXE"]
119+
)
120+
variables["OPENSTA_EXE"] = (
121+
os.path.abspath(
122+
os.path.join(
123+
variables["FLOW_HOME"], "../tools/install/OpenROAD/bin/sta"
124+
)
125+
)
126+
if env_blank("OPENSTA_EXE")
127+
else os.environ["OPENSTA_EXE"]
128+
)
129+
130+
variables["OPENROAD_ARGS"] = (
131+
f"-no_init -threads {variables['NUM_CORES']} {variables.get('OR_ARGS', '')}"
132+
)
133+
variables["OPENROAD_CMD"] = (
134+
f"{variables['OPENROAD_EXE']} -exit {variables['OPENROAD_ARGS']}"
135+
)
136+
variables["OPENROAD_NO_EXIT_CMD"] = (
137+
f"{variables['OPENROAD_EXE']} {variables['OPENROAD_ARGS']}"
138+
)
139+
variables["OPENROAD_GUI_CMD"] = (
140+
f"{variables['OPENROAD_EXE']} -gui {variables.get('OR_ARGS', '')}"
141+
)
142+
143+
if not env_blank("IN_NIX_SHELL"):
144+
variables["YOSYS_EXE"] = subprocess.getoutput("command -v yosys")
145+
else:
146+
variables["YOSYS_EXE"] = (
147+
os.path.abspath(
148+
os.path.join(variables["FLOW_HOME"], "../tools/install/yosys/bin/yosys")
149+
)
150+
if env_blank("YOSYS_EXE")
151+
else os.environ["YOSYS_EXE"]
152+
)
153+
154+
KLAYOUT_DIR = os.path.abspath(
155+
os.path.join(variables["FLOW_HOME"], "../tools/install/klayout/")
156+
)
157+
KLAYOUT_BIN_FROM_DIR = os.path.join(KLAYOUT_DIR, "klayout")
158+
if os.path.exists(KLAYOUT_BIN_FROM_DIR):
159+
variables["KLAYOUT_CMD"] = (
160+
f"sh -c 'LD_LIBRARY_PATH={os.path.dirname(KLAYOUT_BIN_FROM_DIR)} $$0 \"$$@\"' {KLAYOUT_BIN_FROM_DIR}"
161+
)
162+
else:
163+
variables["KLAYOUT_CMD"] = os.environ.get("KLAYOUT_CMD", "klayout")
164+
if len(variables["KLAYOUT_CMD"]) == 0:
165+
variables["KLAYOUT_CMD"] = subprocess.getoutput("command -v klayout")
166+
167+
for key, value in variables.items():
168+
print(f'export {key}?={str(value).replace(" ", "__SPACE__")}')
169+
170+
171+
if __name__ == "__main__":
172+
main()

0 commit comments

Comments
 (0)