-
Notifications
You must be signed in to change notification settings - Fork 7
/
Makefile
233 lines (206 loc) · 7.07 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
# To build, run something like `make F3DEX3_BrZ` or`make F3DEX3_BrW_LVP_NOC_PA`.
# For an explanation of what all the suffixes mean, see README.md.
MAKEFLAGS += --no-builtin-rules
MAKEFLAGS += --no-builtin-variables
.SUFFIXES:
default: F3DEX3_BrZ F3DEX3_BrW
# List of all compile-time options supported by the microcode source.
ALL_OPTIONS := \
CFG_G_BRANCH_W \
CFG_NO_OCCLUSION_PLANE \
CFG_LEGACY_VTX_PIPE \
CFG_PROFILING_A \
CFG_PROFILING_B \
CFG_PROFILING_C
ARMIPS ?= armips
PARENT_OUTPUT_DIR ?= ./build
ifeq ($(PARENT_OUTPUT_DIR),.)
$(error Cannot build directly in repo directory; see Makefile for details.)
# The problem is that we want to be able to have targets like F3DEX2_2.08,
# but this would also be the directory itself, whose existence and possible
# modification needs to be handled by the Makefile. It is possible to write
# the Makefile where the directory is the main target for that microcode, but
# this has worse behavior in case of modification to the directory. Worse, if
# it was done this way, then it would break if the user tried to set
# PARENT_OUTPUT_DIR anywhere else. So, better to support building everywhere
# but here than to support only building here.
endif
# Find the N64 toolchain, for creating object files.
ifneq (, $(shell which mips64-linux-gnu-as))
AS := mips64-linux-gnu-as
else
ifneq (, $(shell which mips64-ultra-elf-as))
AS := mips64-ultra-elf-as
else
ifneq (, $(shell which mips64-as))
AS := mips64-as
else
$(warning Could not find N64 linker, not building object files)
AS :=
endif
endif
endif
NO_COL := \033[0m
RED := \033[0;31m
GREEN := \033[0;32m
YELLOW := \033[0;33m
BLUE := \033[0;34m
INFO := $(BLUE)
SUCCESS := $(GREEN)
FAILURE := $(RED)
WARNING := $(YELLOW)
$(PARENT_OUTPUT_DIR):
@printf "$(INFO)Creating parent output directory$(NO_COL)\n"
ifeq ($(OS),Windows_NT)
mkdir $@
else
mkdir -p $@
endif
ALL_UCODES :=
ALL_UCODES_WITH_MD5S :=
ALL_OUTPUT_DIRS :=
ifneq (, $(AS))
%.o: %.o.s
@$(AS) -march=vr4300 -mabi=32 -I . $< -o $@
endif
define reset_vars
NAME :=
DESCRIPTION :=
ID_STR :=
MD5_CODE :=
MD5_DATA :=
OPTIONS :=
EXTRA_DEPS :=
endef
define ucode_rule
# Variables defined outside the function need one dollar sign, whereas
# variables defined within the function need two. This is because make first
# expands all this text, substituting single-dollar-sign variables, and then
# executes all of it, causing all the assignments to actually happen.
ifeq ($(NAME),)
$$(error Microcode name not set!)
endif
UCODE_OUTPUT_DIR := $(PARENT_OUTPUT_DIR)/$(NAME)
CODE_FILE := $$(UCODE_OUTPUT_DIR)/$(NAME).code
DATA_FILE := $$(UCODE_OUTPUT_DIR)/$(NAME).data
SYM_FILE := $$(UCODE_OUTPUT_DIR)/$(NAME).sym
TEMP_FILE := $$(UCODE_OUTPUT_DIR)/$(NAME).tmp.s
OS_FILE := $$(UCODE_OUTPUT_DIR)/gsp$(NAME).o.s
O_FILE := $$(UCODE_OUTPUT_DIR)/gsp$(NAME).o
ALL_UCODES += $(NAME)
ifneq ($(MD5_CODE),)
ALL_UCODES_WITH_MD5S += $(NAME)
endif
ALL_OUTPUT_DIRS += $$(UCODE_OUTPUT_DIR)
OFF_OPTIONS := $(filter-out $(OPTIONS),$(ALL_OPTIONS))
OPTIONS_EQU :=
$$(foreach option,$(OPTIONS),$$(eval OPTIONS_EQU += -equ $$(option) 1))
OFF_OPTIONS_EQU :=
$$(foreach o2,$$(OFF_OPTIONS),$$(eval OFF_OPTIONS_EQU += -equ $$(o2) 0))
ARMIPS_CMDLINE := \
-strequ CODE_FILE $$(CODE_FILE) \
-strequ DATA_FILE $$(DATA_FILE) \
$$(OPTIONS_EQU) \
$$(OFF_OPTIONS_EQU) \
f3dex3.s \
-sym2 $$(SYM_FILE) \
-temp $$(TEMP_FILE)
# Microcode target
.PHONY: $(NAME)
$(NAME): $$(CODE_FILE)
ifneq (, $(AS))
$(NAME): $$(O_FILE)
endif
# Directory target variables, see below.
$$(UCODE_OUTPUT_DIR): UCODE_OUTPUT_DIR:=$$(UCODE_OUTPUT_DIR)
# Directory target recipe
$$(UCODE_OUTPUT_DIR):
@printf "$(INFO)Creating directory $$(UCODE_OUTPUT_DIR)$(NO_COL)\n"
ifeq ($(OS),Windows_NT)
@mkdir $$(subst /,\,$$(UCODE_OUTPUT_DIR))
else
@mkdir -p $$(UCODE_OUTPUT_DIR)
endif
# Code file target variables. make does not expand variables within recipes
# until the recipe is executed, meaning that all the parts of the recipe would
# have the values from the very last microcode in the file. Here, we set
# target-specific variables--effectively local variables within the recipe--
# to the values from the global variables have right now. We are only
# targeting CODE_FILE even though we also want DATA_FILE, because target-
# specific variables may not work as expected with multiple targets from one
# recipe.
$$(CODE_FILE): ARMIPS_CMDLINE:=$$(ARMIPS_CMDLINE)
$$(CODE_FILE): CODE_FILE:=$$(CODE_FILE)
$$(CODE_FILE): DATA_FILE:=$$(DATA_FILE)
$$(OS_FILE): OS_FILE:=$$(OS_FILE)
$$(OS_FILE): NAME:=$$(NAME)
# Target recipe
$$(CODE_FILE): ./f3dex3.s ./rsp/* $(EXTRA_DEPS) | $$(UCODE_OUTPUT_DIR)
@printf "$(INFO)Building microcode: $(NAME): $(DESCRIPTION)$(NO_COL)\n"
@$(ARMIPS) -strequ ID_STR "$(ID_STR)" $$(ARMIPS_CMDLINE)
ifneq ($(MD5_CODE),)
@(printf "$(MD5_CODE) *$$(CODE_FILE)" | md5sum --status -c -) && printf " $(SUCCESS)$(NAME) code matches$(NO_COL)\n" || printf " $(FAILURE)$(NAME) code differs$(NO_COL)\n"
@(printf "$(MD5_DATA) *$$(DATA_FILE)" | md5sum --status -c -) && printf " $(SUCCESS)$(NAME) data matches$(NO_COL)\n" || printf " $(FAILURE)$(NAME) data differs$(NO_COL)\n"
endif
ifneq (, $(AS))
$$(OS_FILE): $$(CODE_FILE)
@sed "s|XXX|$(NAME)|g" ./template.o.s > $$(OS_FILE)
endif
$$(eval $$(call reset_vars))
endef
$(eval $(call reset_vars))
define rule_builder_final
NAME := F3DEX3$(NAME_FINAL)
DESCRIPTION := Will make you want to finally ditch HLE ($(OPTIONS_FINAL))
ID_STR := F3DEX3$(NAME_FINAL) by Sauraen & Yoshitaka Yasumoto/Nintendo
OPTIONS := $(OPTIONS_FINAL)
$$(eval $$(call ucode_rule))
endef
define rule_builder_prof
NAME_FINAL := $(NAME_PROF)
OPTIONS_FINAL := $(OPTIONS_PROF)
$$(eval $$(call rule_builder_final))
NAME_FINAL := $(NAME_PROF)_PA
OPTIONS_FINAL := $(OPTIONS_PROF) CFG_PROFILING_A
$$(eval $$(call rule_builder_final))
NAME_FINAL := $(NAME_PROF)_PB
OPTIONS_FINAL := $(OPTIONS_PROF) CFG_PROFILING_B
$$(eval $$(call rule_builder_final))
NAME_FINAL := $(NAME_PROF)_PC
OPTIONS_FINAL := $(OPTIONS_PROF) CFG_PROFILING_C
$$(eval $$(call rule_builder_final))
endef
define rule_builder_noc
NAME_PROF := $(NAME_NOC)
OPTIONS_PROF := $(OPTIONS_NOC)
$$(eval $$(call rule_builder_prof))
NAME_PROF := $(NAME_NOC)_NOC
OPTIONS_PROF := $(OPTIONS_NOC) CFG_NO_OCCLUSION_PLANE
$$(eval $$(call rule_builder_prof))
endef
define rule_builder_lvp
NAME_NOC := $(NAME_LVP)
OPTIONS_NOC := $(OPTIONS_LVP)
$$(eval $$(call rule_builder_noc))
NAME_NOC := $(NAME_LVP)_LVP
OPTIONS_NOC := $(OPTIONS_LVP) CFG_LEGACY_VTX_PIPE
$$(eval $$(call rule_builder_noc))
endef
define rule_builder_br
NAME_LVP := $(NAME_BR)_BrZ
OPTIONS_LVP := $(OPTIONS_BR)
$$(eval $$(call rule_builder_lvp))
NAME_LVP := $(NAME_BR)_BrW
OPTIONS_LVP := $(OPTIONS_BR) CFG_G_BRANCH_W
$$(eval $$(call rule_builder_lvp))
endef
NAME_BR :=
OPTIONS_BR :=
$(eval $(call rule_builder_br))
.PHONY: default ok all clean
all: $(ALL_UCODES)
clean:
@printf "$(WARNING)Deleting all built microcode files$(NO_COL)\n"
@rm -rf $(ALL_OUTPUT_DIRS)
doc:
doxygen Doxyfile