forked from riscv/riscv-arch-test
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
250 lines (197 loc) · 9.64 KB
/
Copy pathMakefile
File metadata and controls
250 lines (197 loc) · 9.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# Jordan Carlin jcarlin@hmc.edu
# Created Sept 10, 2025
# Modified April 5, 2026
# SPDX-License-Identifier: Apache-2.0
########## Runtime Options ##########
# CONFIG_FILES is used as the default input configs when running `make` and will produce elfs in the `work/<config-name>/elfs` directory.
# COVERAGE_CONFIG_FILES is used as the default input configs when running `make coverage` and will generate coverage reports in addition to the elfs.
CONFIG_FILES ?= config/spike/spike-rv32-max/test_config.yaml config/spike/spike-rv64-max/test_config.yaml
COVERAGE_CONFIG_FILES ?= config/sail/sail-rv64-max/test_config.yaml config/sail/sail-rv32-max/test_config.yaml
# WORKDIR is where all of the generated files are created
WORKDIR ?= work
# EXTENSIONS is a comma-separated list of extensions to generate tests for. Leave blank to generate for all tests.
# EXCLUDE_EXTENSIONS overrides EXTENSIONS to exclude particular extensions from test generation. Applies as a negative filter after EXTENSIONS.
# Default exclusion reasons:
# - Sm, S: Insufficient WARL configuration options.
# - Sv,Svade,Svadu,SvaduPMP,SvPMP,SvZicbo: sail-riscv missing support for Svade/Svadu causes mismatches. Resolved in upcoming sail-riscv release.
# - ExceptionsZalrsc: See sail-riscv issue 1574. Resolved in upcoming sail-riscv release.
# - ExceptionsZaamo: Configuration needed between access and misaligned faults
# - InterruptsSm,InterruptsS,InterruptsU,PMPSm,PMPZca,PMPmisaligned: Additional testing needed on a wider range of configs. Some missing config options to match ref model.
EXTENSIONS ?=
EXCLUDE_EXTENSIONS ?= Sm,S,InterruptsSm,InterruptsS,InterruptsU,ExceptionsZalrsc,ExceptionsZaamo,PMPSm,PMPZca,PMPmisaligned,Sv,Svade,Svadu,SvaduPMP,SvPMP,SvZicbo,SvPMPZicbo
# Strip spaces from comma-separated lists so shell word-splitting doesn't break CLI arguments
empty :=
space := $(empty) $(empty)
override EXTENSIONS := $(subst $(space),$(empty),$(EXTENSIONS))
override EXCLUDE_EXTENSIONS := $(subst $(space),$(empty),$(EXCLUDE_EXTENSIONS))
# DEBUG, FAST, and VERBOSE are runtime options for controlling build output. DEBUG and FAST are mutually exclusive.
# DEBUG enables debug output (signature objdump, trace files, and trap report). This will slow down ELF generation significantly.
# FAST disables objdump generation for faster builds. This speeds up ELF generation significantly, but makes debugging mismatches harder.
# VERBOSE implies DEBUG, serializes all commands (JOBS=1), and prints each command as it is issued.
DEBUG ?=
FAST ?=
VERBOSE ?=
# VERBOSE implies DEBUG and serializes the build
ifneq ($(VERBOSE),)
DEBUG := True
JOBS := 1
endif
# COVERAGE_SIMULATOR is only used when collecting coverage (make coverage)
COVERAGE_SIMULATOR ?= questa # Coverage simulator backend: questa or vcs
# Number of parallel build jobs for test compilation.
# Automatically derived from make's -j or --jobs flag (e.g., make -j4). Can be overridden with JOBS=N.
# 0 (default) = auto-detect CPU count.
# Setting to 1 is helpful for debugging test hangs so that only a single test runs at a time.
JOBS ?= $(or $(patsubst -j%,%,$(filter -j%,$(MAKEFLAGS))),0)
########## Directories ##########
TESTDIR := tests
SRCDIR64 := $(TESTDIR)/rv64i
SRCDIR64E := $(TESTDIR)/rv64e
SRCDIR32 := $(TESTDIR)/rv32i
SRCDIR32E := $(TESTDIR)/rv32e
PRIVDIR := $(TESTDIR)/priv
COVERPOINT_DIR := coverpoints
UNPRIV_COVERPOINTS_DIR := $(COVERPOINT_DIR)/unpriv
COVERAGE_HELPERS_DIR := $(COVERPOINT_DIR)/coverage
TEMPLATEDIR := templates
TESTGEN_SRC_DIR := generators/testgen
COVERGROUPGEN_SRC_DIR := generators/coverage
TESTGEN_DEPS := $(shell find $(TESTGEN_SRC_DIR) -type f)
COVERGROUPGEN_DEPS := $(shell find $(COVERGROUPGEN_SRC_DIR) -type f)
TESTPLANS_DIR := testplans
TESTPLANS := $(wildcard $(TESTPLANS_DIR)/*.csv $(TESTPLANS_DIR)/**/*.csv)
STAMP_DIR := $(WORKDIR)/stamps
$(STAMP_DIR):
@mkdir -p $@
########## Installation Check ##########
# Tool management — prefer mise, then uv, then an activated venv with the
# CLIs already installed. uv/mise always wins over VIRTUAL_ENV.
MISE := $(shell command -v mise 2> /dev/null)
UV := $(shell command -v uv 2> /dev/null)
ifneq ($(MISE),)
UV_RUN := $(MISE) exec -- uv run
else ifneq ($(UV),)
UV_RUN := $(UV) run
else ifneq ($(VIRTUAL_ENV),)
# Activated venv without uv/mise: require the three CLIs on PATH.
MISSING_CLIS := $(strip $(foreach c,act testgen covergroupgen,\
$(if $(shell command -v $(c) 2> /dev/null),,$(c))))
ifneq ($(MISSING_CLIS),)
$(error Activated venv ($(VIRTUAL_ENV)) is missing required CLIs: $(MISSING_CLIS). Install with: pip install -e ./framework -e ./generators/testgen -e ./generators/coverage or use mise/uv)
endif
UV_RUN :=
else
$(error Neither uv nor mise found, and no venv is activated. See the README (Prerequisites) for install options.)
endif
# Ruby/Bundler is required for the UDB gem whenever we are not going through mise.
ifeq ($(MISE),)
BUNDLE := $(shell command -v bundle 2> /dev/null)
ifeq ($(BUNDLE),)
$(error Bundle not found. Ruby and Bundler are required for UDB. See the README for more information.)
endif
endif
########## Test compilation ##########
.DEFAULT_GOAL := elfs
.PHONY: elfs
elfs: tests
@$(UV_RUN) act $(CONFIG_FILES) \
--workdir $(WORKDIR) \
--test-dir $(TESTDIR) \
--jobs $(JOBS) \
$(if $(EXTENSIONS),--extensions $(EXTENSIONS)) \
$(if $(EXCLUDE_EXTENSIONS),--exclude $(EXCLUDE_EXTENSIONS)) \
$(if $(DEBUG),--debug) \
$(if $(FAST),--fast) \
$(if $(VERBOSE),--verbose) \
$(if $(COVERAGE),--coverage) \
$(if $(COVERAGE),--coverage-simulator $(COVERAGE_SIMULATOR))
.PHONY: clean
clean:
@if [ -d $(WORKDIR) ]; then \
find $(WORKDIR) \( -type f -o -type l \) ! -name 'extensions.txt' -delete; \
find $(WORKDIR) -type d -empty -delete; \
fi
########## Test generation ##########
.PHONY: covergroupgen
covergroupgen: $(STAMP_DIR)/covergroupgen.stamp
$(STAMP_DIR)/covergroupgen.stamp: $(COVERGROUPGEN_DEPS) $(TESTPLANS) Makefile | $(STAMP_DIR)
@$(UV_RUN) covergroupgen testplans $(if $(EXTENSIONS),--extensions $(EXTENSIONS)) $(if $(EXCLUDE_EXTENSIONS),--exclude $(EXCLUDE_EXTENSIONS))
@touch $@
.PHONY: testgen
testgen: $(STAMP_DIR)/testgen.stamp
$(STAMP_DIR)/testgen.stamp: $(TESTGEN_DEPS) $(TESTPLANS) Makefile | $(STAMP_DIR)
@$(UV_RUN) testgen testplans -o tests --jobs $(JOBS) $(if $(EXTENSIONS),--extensions $(EXTENSIONS)) $(if $(EXCLUDE_EXTENSIONS),--exclude $(EXCLUDE_EXTENSIONS))
@touch $@
.PHONY: vector-testgen
vector-testgen: $(STAMP_DIR)/vector-testgen-unpriv.stamp
$(STAMP_DIR)/vector-testgen-unpriv.stamp: generators/testgen/scripts/vector-testgen-unpriv.py generators/testgen/scripts/vector_testgen_common.py Makefile | $(STAMP_DIR)
$(UV_RUN) generators/testgen/scripts/vector-testgen-unpriv.py $(if $(EXTENSIONS),--extensions $(EXTENSIONS)) $(if $(EXCLUDE_EXTENSIONS),--exclude $(EXCLUDE_EXTENSIONS))
touch $@
.PHONY: tests
tests: covergroupgen testgen
.PHONY: vector-tests
vector-tests: covergroupgen vector-testgen
.PHONY: clean-tests
clean-tests:
rm -rf $(SRCDIR64) $(SRCDIR32) $(SRCDIR64E) $(SRCDIR32E)
rm -rf $(UNPRIV_COVERPOINTS_DIR) $(COVERAGE_HELPERS_DIR)
rm -rf $(STAMP_DIR)
########### Coverage ###########
# Just sets some variables and then runs the standard elfs target
.PHONY: coverage
coverage: COVERAGE := True
coverage: CONFIG_FILES := $(COVERAGE_CONFIG_FILES)
coverage: elfs
########### Regression ###########
# Clean, run coverage, then run all configs that have a run_cmd.txt, continuing through failures.
.PHONY: regression
regression: clean
@exit_code=0; \
$(MAKE) coverage || exit_code=1; \
CONFIG_FILES="$(patsubst %/run_cmd.txt,%/test_config.yaml,$(RUN_CMD_FILES))" \
$(MAKE) elfs || exit_code=1; \
$(foreach f,$(RUN_CMD_FILES),\
./run_tests.py $(if $(DEBUG),--debug) $(if $(VERBOSE),--verbose) "$$(cat $(f))" $(WORKDIR)/$(notdir $(patsubst %/run_cmd.txt,%,$(f)))/elfs || exit_code=1; ) \
exit $$exit_code
########### Simulators ###########
# Targets are auto-generated from discovered run_cmd.txt files. Every directory name
# in the config path becomes a Make target that runs all configs beneath it:
# make spike-rv64-max — single config
# make spike — all spike configs
# make cvw — all cvw configs
# make cores — all configs under cores/
#
# Note on escaping: $$ defers expansion past $(eval $(call ...)); $$$$ yields a literal $ in the shell.
# Find all configs that provide a run command
RUN_CMD_FILES := $(shell find config -name run_cmd.txt)
# Map each directory name in the path to its run_cmd.txt files.
# e.g., config/cores/cvw/cvw-rv64gc/run_cmd.txt populates _TARGETS_cores, _TARGETS_cvw, _TARGETS_cvw-rv64gc
$(foreach f,$(RUN_CMD_FILES),\
$(foreach d,$(filter-out config,$(subst /, ,$(patsubst %/run_cmd.txt,%,$(f)))),\
$(eval _TARGETS_$(d) += $(f))))
# Collect all unique target names
ALL_RUN_TARGETS := $(sort $(foreach f,$(RUN_CMD_FILES),\
$(filter-out config,$(subst /, ,$(patsubst %/run_cmd.txt,%,$(f))))))
# Each target generates tests, builds ELFs, and runs each config (continuing through failures).
.PHONY: $(ALL_RUN_TARGETS)
define run-target
$(1): tests
CONFIG_FILES="$(patsubst %/run_cmd.txt,%/test_config.yaml,$(_TARGETS_$(1)))" \
$$(MAKE) elfs
@exit_code=0; \
$(foreach f,$(_TARGETS_$(1)),\
./run_tests.py $(if $(DEBUG),--debug) $(if $(VERBOSE),--verbose) "$$$$(cat $(f))" $$(WORKDIR)/$(notdir $(patsubst %/run_cmd.txt,%,$(f)))/elfs || exit_code=1; ) \
exit $$$$exit_code
endef
$(foreach t,$(ALL_RUN_TARGETS),$(eval $(call run-target,$(t))))
########## Linting/Formatting ##########
.PHONY: lint
lint:
$(UV_RUN) ruff check
$(UV_RUN) pyright
.PHONY: lint-fix
lint-fix:
$(UV_RUN) ruff check --fix
.PHONY: format
format:
$(UV_RUN) ruff format