Skip to content

Commit 9d1369d

Browse files
committed
variables: break out variables.mk file
The idea is to separate the ORFS variable support and make variables and ORFS agnostic to build systems, even if make is used to evaluate variables. ORFS contains an implementation of a flow using make, bazel-orfs implements a flow using Bazel. Sometimes make is preferable, keep things simple, but for more advanced flows, the simplicity of make introduces more problems than it solves Signed-off-by: Øyvind Harboe <[email protected]>
1 parent 044183f commit 9d1369d

File tree

4 files changed

+285
-199
lines changed

4 files changed

+285
-199
lines changed

flow/Makefile

Lines changed: 9 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,16 @@
8484

8585
# Default design
8686
DESIGN_CONFIG ?= ./designs/nangate45/gcd/config.mk
87-
88-
# Include design and platform configuration before setting default options
89-
# in this file. This allows the DESIGN_CONFIG to set different defaults than
90-
# this file.
87+
export DESIGN_CONFIG
9188
include $(DESIGN_CONFIG)
92-
export DESIGN_NICKNAME?=$(DESIGN_NAME)
89+
90+
export DESIGN_DIR = $(dir $(DESIGN_CONFIG))
91+
9392
# default value "base" is duplicated from variables.yaml because we need it
94-
# earlier in the flow for BLOCKS. BLOCKS is a feature specific to Makefile
95-
# that will not be ported to bazel-orfs.
93+
# earlier in the flow for BLOCKS. BLOCKS is a feature specific to the
94+
# ORFS Makefile.
9695
export FLOW_VARIANT?=base
96+
# BLOCKS is a ORFS make flow specific feature.
9797
ifneq ($(BLOCKS),)
9898
# Normally this comes from variables.yaml, but we need it here to set up these variables
9999
# which are part of the DESIGN_CONFIG. BLOCKS is a Makefile specific concept.
@@ -111,11 +111,6 @@ ifneq ($(BLOCKS),)
111111
endif
112112
endif
113113

114-
# If we are running headless use offscreen rendering for save_image
115-
ifeq ($(DISPLAY),)
116-
export QT_QPA_PLATFORM ?= offscreen
117-
endif
118-
119114
# ==============================================================================
120115
# ____ _____ _____ _ _ ____
121116
# / ___|| ____|_ _| | | | _ \
@@ -138,6 +133,7 @@ MAKEFLAGS += --no-builtin-rules
138133
SHELL := /usr/bin/env bash
139134
.SHELLFLAGS := -o pipefail -c
140135

136+
141137
#-------------------------------------------------------------------------------
142138
# Setup variables to point to root / head of the OpenROAD directory
143139
# - the following settings allowed user to point OpenROAD binaries to different
@@ -148,140 +144,7 @@ FLOW_HOME := $(abspath $(dir $(firstword $(MAKEFILE_LIST))))
148144
endif
149145
export FLOW_HOME
150146

151-
#-------------------------------------------------------------------------------
152-
# Setup variables to point to other location for the following sub directory
153-
# - designs - default is under current directory
154-
# - platforms - default is under current directory
155-
# - work home - default is current directory
156-
# - utils, scripts, test - default is under current directory
157-
export DESIGN_HOME ?= $(FLOW_HOME)/designs
158-
export PLATFORM_HOME ?= $(FLOW_HOME)/platforms
159-
export WORK_HOME ?= .
160-
161-
export UTILS_DIR ?= $(FLOW_HOME)/util
162-
export SCRIPTS_DIR ?= $(FLOW_HOME)/scripts
163-
export TEST_DIR ?= $(FLOW_HOME)/test
164-
165-
PUBLIC=nangate45 sky130hd sky130hs asap7 ihp-sg13g2 gf180
166-
167-
ifneq ($(wildcard $(PLATFORM_HOME)/$(PLATFORM)),)
168-
export PLATFORM_DIR = $(PLATFORM_HOME)/$(PLATFORM)
169-
else ifneq ($(findstring $(PLATFORM),$(PUBLIC)),)
170-
export PLATFORM_DIR = ./platforms/$(PLATFORM)
171-
else ifneq ($(wildcard ../../$(PLATFORM)),)
172-
export PLATFORM_DIR = ../../$(PLATFORM)
173-
else
174-
$(error [ERROR][FLOW] Platform '$(PLATFORM)' not found.)
175-
endif
176-
177-
include $(PLATFORM_DIR)/config.mk
178-
179-
# __SPACE__ is a workaround for whitespace hell in "foreach"; there
180-
# 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-
export DESIGN_CONFIG
184-
export DESIGN_DIR = $(dir $(DESIGN_CONFIG))
185-
export LOG_DIR = $(WORK_HOME)/logs/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)
186-
export OBJECTS_DIR = $(WORK_HOME)/objects/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)
187-
export REPORTS_DIR = $(WORK_HOME)/reports/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)
188-
export RESULTS_DIR = $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_VARIANT)
189-
190-
#-------------------------------------------------------------------------------
191-
ifeq (,$(strip $(NUM_CORES)))
192-
# Linux (utility program)
193-
NUM_CORES := $(shell nproc 2>/dev/null)
194-
195-
ifeq (,$(strip $(NUM_CORES)))
196-
# Linux (generic)
197-
NUM_CORES := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
198-
endif
199-
ifeq (,$(strip $(NUM_CORES)))
200-
# BSD (at least FreeBSD and Mac OSX)
201-
NUM_CORES := $(shell sysctl -n hw.ncpu 2>/dev/null)
202-
endif
203-
ifeq (,$(strip $(NUM_CORES)))
204-
# Fallback
205-
NUM_CORES := 1
206-
endif
207-
endif
208-
export NUM_CORES
209-
210-
#-------------------------------------------------------------------------------
211-
# setup all commands used within this flow
212-
export TIME_BIN ?= env time
213-
TIME_CMD = $(TIME_BIN) -f 'Elapsed time: %E[h:]min:sec. CPU time: user %U sys %S (%P). Peak memory: %MKB.'
214-
TIME_TEST = $(shell $(TIME_CMD) echo foo 2>/dev/null)
215-
ifeq (,$(strip $(TIME_TEST)))
216-
TIME_CMD = $(TIME_BIN)
217-
endif
218-
219-
# The following determine the executable location for each tool used by this flow.
220-
# Priority is given to
221-
# 1 user explicit set with variable in Makefile or command line, for instance setting OPENROAD_EXE
222-
# 2 ORFS compiled tools: openroad, yosys
223-
ifneq (${IN_NIX_SHELL},)
224-
export OPENROAD_EXE := $(shell command -v openroad)
225-
else
226-
export OPENROAD_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/OpenROAD/bin/openroad)
227-
endif
228-
ifneq (${IN_NIX_SHELL},)
229-
export OPENSTA_EXE := $(shell command -v sta)
230-
else
231-
export OPENSTA_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/OpenROAD/bin/sta)
232-
endif
233-
234-
OPENROAD_ARGS = -no_init -threads $(NUM_CORES) $(OR_ARGS)
235-
OPENROAD_CMD = $(OPENROAD_EXE) -exit $(OPENROAD_ARGS)
236-
OPENROAD_NO_EXIT_CMD = $(OPENROAD_EXE) $(OPENROAD_ARGS)
237-
OPENROAD_GUI_CMD = $(OPENROAD_EXE) -gui $(OR_ARGS)
238-
239-
ifneq (${IN_NIX_SHELL},)
240-
YOSYS_EXE := $(shell command -v yosys)
241-
else
242-
YOSYS_EXE ?= $(abspath $(FLOW_HOME)/../tools/install/yosys/bin/yosys)
243-
endif
244-
245-
# Use locally installed and built klayout if it exists, otherwise use klayout in path
246-
KLAYOUT_DIR = $(abspath $(FLOW_HOME)/../tools/install/klayout/)
247-
KLAYOUT_BIN_FROM_DIR = $(KLAYOUT_DIR)/klayout
248-
249-
ifeq ($(wildcard $(KLAYOUT_BIN_FROM_DIR)), $(KLAYOUT_BIN_FROM_DIR))
250-
KLAYOUT_CMD ?= sh -c 'LD_LIBRARY_PATH=$(dir $(KLAYOUT_BIN_FROM_DIR)) $$0 "$$@"' $(KLAYOUT_BIN_FROM_DIR)
251-
else
252-
ifeq ($(KLAYOUT_CMD),)
253-
KLAYOUT_CMD := $(shell command -v klayout)
254-
endif
255-
endif
256-
KLAYOUT_FOUND = $(if $(KLAYOUT_CMD),,$(error KLayout not found in PATH))
257-
258-
ifneq ($(shell command -v stdbuf),)
259-
STDBUF_CMD ?= stdbuf -o L
260-
endif
261-
262-
#-------------------------------------------------------------------------------
263-
WRAPPED_LEFS = $(foreach lef,$(notdir $(WRAP_LEFS)),$(OBJECTS_DIR)/lef/$(lef:.lef=_mod.lef))
264-
WRAPPED_LIBS = $(foreach lib,$(notdir $(WRAP_LIBS)),$(OBJECTS_DIR)/$(lib:.lib=_mod.lib))
265-
export ADDITIONAL_LEFS += $(WRAPPED_LEFS) $(WRAP_LEFS)
266-
export LIB_FILES += $(WRAP_LIBS) $(WRAPPED_LIBS)
267-
268-
export DONT_USE_LIBS = $(patsubst %.lib.gz, %.lib, $(addprefix $(OBJECTS_DIR)/lib/, $(notdir $(LIB_FILES))))
269-
export DONT_USE_SC_LIB ?= $(firstword $(DONT_USE_LIBS))
270-
271-
# Stream system used for final result (GDS is default): GDS, GSDII, GDS2, OASIS, or OAS
272-
STREAM_SYSTEM ?= GDS
273-
ifneq ($(findstring GDS,$(shell echo $(STREAM_SYSTEM) | tr '[:lower:]' '[:upper:]')),)
274-
export STREAM_SYSTEM_EXT := gds
275-
GDSOAS_FILES = $(GDS_FILES)
276-
ADDITIONAL_GDSOAS = $(ADDITIONAL_GDS)
277-
SEAL_GDSOAS = $(SEAL_GDS)
278-
else
279-
export STREAM_SYSTEM_EXT := oas
280-
GDSOAS_FILES = $(OAS_FILES)
281-
ADDITIONAL_GDSOAS = $(ADDITIONAL_OAS)
282-
SEAL_GDSOAS = $(SEAL_OAS)
283-
endif
284-
export WRAPPED_GDSOAS = $(foreach lef,$(notdir $(WRAP_LEFS)),$(OBJECTS_DIR)/$(lef:.lef=_mod.$(STREAM_SYSTEM_EXT)))
147+
include $(FLOW_HOME)/scripts/variables.mk
285148

286149
define GENERATE_ABSTRACT_RULE
287150
ifeq ($(wildcard $(3)),)
@@ -350,18 +213,6 @@ do-klayout_tech:
350213
@mkdir -p $(OBJECTS_DIR)
351214
cp $(TECH_LEF) $(OBJECTS_DIR)/klayout_tech.lef
352215

353-
KLAYOUT_ENV_VAR_IN_PATH_VERSION = 0.28.11
354-
KLAYOUT_VERSION := $(if $(KLAYOUT_CMD),$(shell $(KLAYOUT_CMD) -v 2>/dev/null | grep 'KLayout' | cut -d ' ' -f2),)
355-
356-
KLAYOUT_ENV_VAR_IN_PATH = $(shell \
357-
if [ -z "$(KLAYOUT_VERSION)" ]; then \
358-
echo "not_found"; \
359-
elif [ "$$(echo -e "$(KLAYOUT_VERSION)\n$(KLAYOUT_ENV_VAR_IN_PATH_VERSION)" | sort -V | head -n1)" = "$(KLAYOUT_VERSION)" ] && [ "$(KLAYOUT_VERSION)" != "$(KLAYOUT_ENV_VAR_IN_PATH_VERSION)" ]; then \
360-
echo "invalid"; \
361-
else \
362-
echo "valid"; \
363-
fi)
364-
365216
$(OBJECTS_DIR)/klayout.lyt: $(KLAYOUT_TECH_FILE) $(OBJECTS_DIR)/klayout_tech.lef
366217
$(UNSET_AND_MAKE) do-klayout
367218

@@ -383,12 +234,6 @@ $(OBJECTS_DIR)/klayout_wrap.lyt: $(KLAYOUT_TECH_FILE) $(OBJECTS_DIR)/klayout_tec
383234
do-klayout_wrap:
384235
sed 's,<lef-files>.*</lef-files>,$(foreach file, $(OBJECTS_DIR)/klayout_tech.lef $(WRAP_LEFS),<lef-files>$(shell realpath --relative-to=$(OBJECTS_DIR)/def $(file))</lef-files>),g' $(KLAYOUT_TECH_FILE) > $(OBJECTS_DIR)/klayout_wrap.lyt
385236

386-
# Create Macro wrappers (if necessary)
387-
# ==============================================================================
388-
WRAP_CFG = $(PLATFORM_DIR)/wrapper.cfg
389-
390-
391-
export TCLLIBPATH := util/cell-veneer $(TCLLIBPATH)
392237
$(WRAPPED_LEFS):
393238
mkdir -p $(OBJECTS_DIR)/lef $(OBJECTS_DIR)/def
394239
util/cell-veneer/wrap.tcl -cfg $(WRAP_CFG) -macro $(filter %$(notdir $(@:_mod.lef=.lef)),$(WRAP_LEFS))
@@ -430,15 +275,10 @@ memory:
430275
# Run Synthesis using yosys
431276
#-------------------------------------------------------------------------------
432277

433-
export SYNTH_SCRIPT ?= $(SCRIPTS_DIR)/synth.tcl
434-
export SDC_FILE_CLOCK_PERIOD = $(RESULTS_DIR)/clock_period.txt
435-
436278
$(SDC_FILE_CLOCK_PERIOD): $(SDC_FILE)
437279
mkdir -p $(dir $@)
438280
echo $(ABC_CLOCK_PERIOD_IN_PS) > $@
439281

440-
YOSYS_DEPENDENCIES=$(DONT_USE_LIBS) $(WRAPPED_LIBS) $(DFF_LIB_FILE) $(VERILOG_FILES) $(SYNTH_NETLIST_FILES) $(LATCH_MAP_FILE) $(ADDER_MAP_FILE) $(SDC_FILE_CLOCK_PERIOD)
441-
442282
.PHONY: yosys-dependencies
443283
yosys-dependencies: $(YOSYS_DEPENDENCIES)
444284

@@ -772,7 +612,6 @@ klayout_guides: $(RESULTS_DIR)/5_route.def $(OBJECTS_DIR)/klayout.lyt
772612
# | _| | || |\ || | ___) | _ || || |\ | |_| |
773613
# |_| |___|_| \_|___|____/|_| |_|___|_| \_|\____|
774614
#
775-
GDS_FINAL_FILE = $(RESULTS_DIR)/6_final.$(STREAM_SYSTEM_EXT)
776615
.PHONY: finish
777616
finish: $(LOG_DIR)/6_report.log \
778617
$(RESULTS_DIR)/6_final.v \
@@ -841,7 +680,6 @@ $(WRAPPED_GDSOAS): $(OBJECTS_DIR)/klayout_wrap.lyt $(WRAPPED_LEFS)
841680

842681
# Merge GDS using Klayout
843682
#-------------------------------------------------------------------------------
844-
GDS_MERGED_FILE = $(RESULTS_DIR)/6_1_merged.$(STREAM_SYSTEM_EXT)
845683
$(GDS_MERGED_FILE): $(RESULTS_DIR)/6_final.def $(OBJECTS_DIR)/klayout.lyt $(GDSOAS_FILES) $(WRAPPED_GDSOAS) $(SEAL_GDSOAS)
846684
$(UNSET_AND_MAKE) do-gds-merged
847685

@@ -940,16 +778,8 @@ nuke: clean_test clean_issues
940778
rm -rf *.rpt *.rpt.old *.def.v pin_dumper.log
941779
rm -f $(OBJECTS_DIR)/versions.txt $(OBJECTS_DIR)/copyright.txt dummy.guide
942780

943-
.PHONY: vars
944-
vars:
945-
$(UTILS_DIR)/generate-vars.sh vars
946-
947781
# DEF/GDS/OAS viewer shortcuts
948782
#-------------------------------------------------------------------------------
949-
RESULTS_ODB = $(notdir $(sort $(wildcard $(RESULTS_DIR)/*.odb)))
950-
RESULTS_DEF = $(notdir $(sort $(wildcard $(RESULTS_DIR)/*.def)))
951-
RESULTS_GDS = $(notdir $(sort $(wildcard $(RESULTS_DIR)/*.gds)))
952-
RESULTS_OAS = $(notdir $(sort $(wildcard $(RESULTS_DIR)/*.oas)))
953783
.PHONY: $(foreach file,$(RESULTS_DEF) $(RESULTS_GDS) $(RESULTS_OAS),klayout_$(file))
954784
$(foreach file,$(RESULTS_DEF) $(RESULTS_GDS) $(RESULTS_OAS),klayout_$(file)): klayout_%: $(OBJECTS_DIR)/klayout.lyt
955785
$(KLAYOUT_CMD) -nn $(OBJECTS_DIR)/klayout.lyt $(RESULTS_DIR)/$*
@@ -999,10 +829,6 @@ all_verilog : $(foreach file,$(RESULTS_ODB),$(file).v)
999829
.PHONY: handoff
1000830
handoff : all_defs all_verilog
1001831

1002-
.PHONY: print-%
1003-
# Print any variable, for instance: make print-DIE_AREA
1004-
print-% : ; @echo "$* = $($*)"
1005-
1006832
.PHONY: test-unset-and-make-%
1007833
test-unset-and-make-%: ; $(UNSET_AND_MAKE) $*
1008834

flow/scripts/README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,61 @@
22

33
Various scripts to support flow as well as utilities.
44

5+
## variables.mk
6+
7+
ORFS defines tcl scripts and variables that can be used to implement a flow. Variables in EDA flows is an idiomatic domain feature: placement density, list of .lib, .lef files, etc.
8+
9+
The variables are implemented using the `make` language, which ORFS makes no effort to hide. See examples below for usage. Beyond `make`, ORFS uses Python and bash to implement the variables.
10+
11+
The choice of `make` to implement the ORFS variables is historical and technical. Technically, the `make` language implements features such as default values, forward references, conditional evaluation of variables, environment variables support and specifying variables on the command line. `make` itself is an uncomplicated dependency, even if depending on and sharing makefiles can be trickier. There is no simple and obviously better choice than `make` to support these features and the use-cases.
12+
13+
ORFS avoids the [inversion of control](https://en.wikipedia.org/wiki/Inversion_of_control) trap where the user wants to be in control of the flow and also ORFS wants to be in the flow. To ORFS all build systems are first class citizens and the user can choose if it wants to let ORFS run the flow or if the user wants to be in control of the flow. The job of ORFS is to define and support an interface such that the user can pick a flow implementation that balances simplicity and required features for their project.
14+
15+
`make`'s simplicity reduces the cognitive load when getting started with simple OpenROAD examples, but its simplicity eventually causes more problems than it solves when the flow gets complicated enough. MegaBoom illustrates a how a more complicated flow is better implemented in bazel-orfs.
16+
17+
Some use-cases for `variables.mk`:
18+
19+
- ORFS has a Makefile that implements a flow on top of the variables implemented in `variables.mk` and the ORFS scripts. This is used for CI and local regression testing.
20+
- The has his own Makefile where ORFS is part of the user's flow where they can include and use only `variables.mk` or the ORFS `makefile`, while remaining in charge.
21+
- bazel-orfs currently uses the ORFS `makefile` do- targets where no dependency checking is done to implement an ORFS flow. bazel-orfs may switch to using `variables.mk` to evaluate the variables and invoking OpenROAD directly.
22+
23+
### Variables hello world
24+
25+
It can be useful to run simple experiments to see what variables evaluate to:
26+
27+
$ make --file=scripts/variables.mk PLATFORM=asap7 DESIGN_NAME=gcd print-OBJECTS_DIR
28+
OBJECTS_DIR = ./objects/asap7/gcd/base
29+
30+
### Creating and using a bash sourceable script to set up variables
31+
32+
As an example of evaluating ORFS variables and invoking OpenROAD directly, first run synthesis on an existing design, set up variables, source the environment variables, then invoke floorplan directly:
33+
34+
$ cd .../OpenROAD-flow-scripts/flow
35+
$ make DESIGN_CONFIG=designs/asap7/gcd/config.mk synth
36+
$ make DESIGN_CONFIG=designs/asap7/gcd/config.mk vars
37+
$ . objects/asap7/gcd/base/vars.sh
38+
$ openroad -exit scripts/floorplan.tcl
39+
[deleted]
40+
==========================================================================
41+
floorplan final report_design_area
42+
--------------------------------------------------------------------------
43+
Design area 38 u^2 19% utilization.
44+
$
45+
46+
### Creating a bash sourcable script to set up variables using `variables.mk` directly
47+
48+
It is also possible to evaluate the variables without using the ORFS `Makefile`, but using `variables.mk` directly. In this example we copy the variables set in `designs/asap7/gcd/config.mk` onto the command line:
49+
50+
$ make PLATFORM=asap7 DESIGN_NAME=gcd VERILOG_FILES=$(ls designs/src/gcd/*.v) SDC_FILE=designs/asap7/gcd/constraint.sdc "DIE_AREA=0 0 16.2 16.2" "CORE_AREA=1.08 1.08 15.12 15.12" PLACE_DENSITY=0.35 SKIP_LAST_GASP=1 --file=scripts/variables.mk vars
51+
$ . objects/asap7/gcd/base/vars.sh
52+
$ openroad -exit scripts/floorplan.tcl
53+
[deleted]
54+
==========================================================================
55+
floorplan final report_design_area
56+
--------------------------------------------------------------------------
57+
Design area 38 u^2 19% utilization.
58+
$
59+
560
## make run-yosys
661

762
Sets up all the ORFS environment variables and launches Yosys.

0 commit comments

Comments
 (0)