-
Notifications
You must be signed in to change notification settings - Fork 0
/
Makefile
256 lines (200 loc) · 6.91 KB
/
Makefile
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
251
252
253
254
255
256
# default goal
.DEFAULT_GOAL := help
# phony targets
.PHONY: help config clean
# Compilation is not parallel-safe because most tools use per-library shared
# files that they update after each compilation.
.NOTPARALLEL:
# multiple goals not tested
ifneq ($(words $(MAKECMDGOALS)),1)
ifneq ($(words $(MAKECMDGOALS)),0)
$(error "multiple goals not supported yet")
endif
endif
# absolute real path of TOP directory
TOP := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
# project name
PROJECT := $(notdir $(TOP))
# name of configuration file
CONFIG := config
# include configuration file
ifneq ($(wildcard $(TOP)/$(CONFIG)),)
include $(TOP)/$(CONFIG)
endif
# compute configuration variables
SIM ?= ghdl
# GUI mode
GUI ?= no
ifneq ($(GUI),yes)
ifneq ($(GUI),no)
$(error "$(GUI): invalid GUI value")
endif
endif
# source and test file directories
SRC ?= src
TESTS ?= tests
GHDLAFLAGS ?= --std=08 -frelaxed --workdir=$(TOP)/$(DIR) -Wno-hide -Wno-shared
GHDLRFLAGS ?= --std=08 -frelaxed --workdir=$(TOP)/$(DIR) -Wno-hide -Wno-shared
GHDLRUNOPTS ?=
ifeq ($(SIM),ghdl)
COM = @ghdl -a $(GHDLAFLAGS) --work=$(LIBNAME) $<
SYNT = ghdl --synth $(GHDLRFLAGS) --work=$(SRC) --out=none $(subst _tb, ,$(UNIT))
SCHEMA = yosys -m ghdl -p \
"ghdl $(GHDLRFLAGS) --work=$(SRC) $(UNIT); show -notitle -format dot -prefix $(TOP)/$(DIR)/$(UNIT)"
ifeq ($(GUI),yes)
RUN = ghdl -r $(GHDLRFLAGS) --work=$(LIBNAME) $(UNIT) $(GHDLRUNOPTS) --wave=$(UNIT).ghw; \
printf '\nGHW file: %s.ghw\n' '$(DIR)/$(UNIT)'
else
RUN = ghdl -r $(GHDLRFLAGS) --work=$(LIBNAME) $(UNIT) $(GHDLRUNOPTS)
endif
else
$(error "$(SIM): invalid SIM value")
endif
# temporary build directory
DIR ?= /tmp/$(USER)/$(PROJECT)/$(SIM)
# tags sub-directory of DIR
TAGS := .tags
# verbosity level: 0: quiet, 1: verbose
V ?= 0
ifeq ($(V),0)
.SILENT:
VERBOSE :=
else ifeq ($(V),1)
VERBOSE := yes
else
$(error invalid V value: $(V))
endif
# help messages and goals
define HELP_message
Usage:
make [GOAL] [VARIABLE=VALUE ...]
Examples:
make foo_sim DIR=/tmp/mysim V=1
make foo_sim.sim DIR=/tmp/ghdl_sim SIM=ghdl GUI=yes
Variable valid values description
DIR - temporary build directory
SRC - source file directory
TESTS - test file directory
GHDLAFLAGS - GHDL analysis options
GHDLRFLAGS - GHDL simulation options
GHDLRUNOPTS - GHDL RUNOPTS options
GUI yes|no use Graphical User Interface
SKIP - UNITs to ignore for compilation
V 0|1 verbosity level
Goals:
help this help (default goal)
config list current config values
libs print library names
UNIT compile UNIT.vhd
units print existing UNITs not in SKIP
all compile all source files not in SKIP
UNIT.sim simulate UNIT, also rund synthesis test for DUT
UNIT.wave view UNIT waveform using gtkwave
UNIT.schema generate and open preview of unit schematics
clean delete temporary build directory
endef
export HELP_message
define CONFIG_values
Variable current value
DIR $(DIR)
SRC $(SRC)
TESTS $(TESTS)
GHDLAFLAGS $(GHDLAFLAGS)
GHDLRFLAGS $(GHDLRFLAGS)
GHDLRUNOPTS $(GHDLRUNOPTS)
GUI $(GUI)
SKIP $(SKIP)
V $(V)
endef
export CONFIG_values
help::
@printf '%s\n' "$$HELP_message"
config::
@printf '%s\n' "$$CONFIG_values"
clean:
@printf '[RM] %s\n' "$(DIR)"
rm -rf $(TOP)/$(DIR)
# if not clean or help, and first make invocation
ifneq ($(filter-out clean help ,$(MAKECMDGOALS)),)
ifneq ($(PASS),run)
# double-colon rule in case we want to add something elsewhere (e.g. in
# design-specific files)
# last resort default rule to invoke again with same goal and same Makefile but
# in $(DIR)
%::
mkdir -p $(TOP)/$(DIR)/$(TAGS)
$(MAKE) --no-print-directory -C $(TOP)/$(DIR) -f $(TOP)/Makefile $@ PASS=run
# second make invocation (in $(DIR))
else
# search tag files in $(TAGS)
VPATH := $(TAGS)
# all source and dependency files
SRCMKS := $(shell find -L $(TOP) -type f,l \( -name '*.vhd' -o -name '*.mk' \))
# all source files
SRCS := $(patsubst $(TOP)/%,%,$(filter %.vhd,$(SRCMKS)))
# skip units listed in SKIP
SRCS := $(filter-out $(addprefix %/,$(addsuffix .vhd,$(SKIP))),$(SRCS))
# source and test files
PROJECT_FILES := $(filter-out lib/%, $(SRCS))
# unit names (source file base names without .vhd extension)
UNITS := $(patsubst %.vhd,%,$(notdir $(SRCS)))
sorted_units := $(sort $(UNITS))
duplicates := $(sort $(strip $(foreach u,$(sorted_units),$(word 2,$(filter $u,$(UNITS))))))
ifneq ($(duplicates),)
$(error duplicated unit names: $(duplicates))
endif
UNITS := $(sorted_units)
# simulation goals are UNIT.sim
SIMULATIONS := $(addsuffix .sim,$(UNITS))
# all dependency files under $(TOP)
MKS := $(filter %.mk,$(SRCMKS))
.PHONY: units libs all $(addprefix .schema,$(UNITS)) $(addprefix .sim,$(UNITS)) $(addprefix .wave,$(UNITS))
# include dependency files
include $(MKS)
# library list
LIBS :=
# $(1): source file path relative to $(TOP)
# define target-specific variables (LIBNAME, UNIT)
# instantiate compilation and simulation rules
# in $(DIR) empty files with unit names are used to keep track of last
# compilation times
define GEN_rule
$(1)-unit := $$(patsubst %.vhd,%,$$(notdir $(1)))
$$($(1)-unit)-lib ?= $$(notdir $$(patsubst %/,%,$$(dir $(1))))
$$($(1)-unit) $$($(1)-unit).sim $$($(1)-unit).schema: LIBNAME = $$($$($(1)-unit)-lib)
$$($(1)-unit) $$($(1)-unit).sim $$($(1)-unit).schema: UNIT = $$($(1)-unit)
LIBS += $$($$($(1)-unit)-lib)
$$($(1)-unit): $$(TOP)/$(1)
@printf '[COMPILE] %-70s -> %s\n' "$$(patsubst $$(TOP)/%,%,$$<)" "$$(LIBNAME)"
$$(COM)
touch $(TAGS)/$$@
$$($(1)-unit).sim: all
@printf '\n[SYNTHESIS] %-70s\n\n' "$$(SRC).$$(subst _tb, ,$$(UNIT))"
$$(SYNT)
printf '[SIMULATE] %-70s\n\n' "$$(LIBNAME).$$(UNIT)"
$$(RUN)
$$($(1)-unit).schema: all
@printf '\n[SCHEMATIC] %-70s\n' "$$(LIBNAME).$$(subst _tb, ,$$(UNIT))"
$$(SCHEMA)
dot -T svg -o $$(TOP)/$$(DIR)/$$(UNIT).svg $$(TOP)/$$(DIR)/$$(UNIT).dot
open $$(TOP)/$$(DIR)/$$(UNIT).svg
endef
$(foreach f,$(SRCS),$(eval $(call GEN_rule,$(f))))
# library list without duplicates
LIBS := $(sort $(LIBS))
# list libraries
libs:
@printf '%s\n' $(LIBS)
# list units
units:
@printf '%-40s%-40s\n' $(UNITS)
%.wave:
@printf '\n[WAVE] %-70s\n' "$(subst .wave,.ghw,$@)"
@gtkwave $(TOP)/$(DIR)/$(subst .wave,.ghw,$@)
format:
$(foreach file,$(PROJECT_FILES),echo; vsg -c $(TOP)/vsg_config.json -f $(TOP)/$(file) --fix;)
# compile all units
all: $(UNITS)
endif
endif
# vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab textwidth=0: