]> begriffs open source - cmsis/blob - CMSIS/CoreValidation/Project/build.py
Run CoreValidation in VHT models
[cmsis] / CMSIS / CoreValidation / Project / build.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 import logging
5
6 from datetime import datetime
7 from enum import Enum
8 from glob import glob, iglob
9 from pathlib import Path
10
11 from lxml.etree import XMLSyntaxError
12 from zipfile import ZipFile
13
14 from matrix_runner import main, matrix_axis, matrix_action, matrix_command, matrix_filter, \
15     ConsoleReport, CropReport, TransformReport, JUnitReport
16
17
18 @matrix_axis("device", "d", "Device(s) to be considered.")
19 class DeviceAxis(Enum):
20     CM0 = ('Cortex-M0', 'CM0')
21     CM0plus = ('Cortex-M0plus', 'CM0plus')
22     CM3 = ('Cortex-M3', 'CM3')
23     CM4 = ('Cortex-M4', 'CM4')
24     CM4FP = ('Cortex-M4FP', 'CM4FP')
25     CM7 = ('Cortex-M7', 'CM7')
26     CM7SP = ('Cortex-M7SP', 'CM7SP')
27     CM7DP = ('Cortex-M7DP', 'CM7DP')
28     CM23 = ('Cortex-M23', 'CM23')
29     CM23S = ('Cortex-M23S', 'CM23S')
30     CM23NS = ('Cortex-M23NS', 'CM23NS')
31     CM33 = ('Cortex-M33', 'CM33')
32     CM33S = ('Cortex-M33S', 'CM33S')
33     CM33NS = ('Cortex-M33NS', 'CM33NS')
34     CM35P = ('Cortex-M35P', 'CM35P')
35     CM35PS = ('Cortex-M35PS', 'CM35PS')
36     CM35PNS = ('Cortex-M35PNS', 'CM35PNS')
37     CM55S = ('Cortex-M55S', 'CM55S')
38     CM55NS = ('Cortex-M55NS', 'CM55NS')
39     CM85S = ('Cortex-M85S', 'CM85S')
40     CM85NS = ('Cortex-M85NS', 'CM85NS')
41     CA5 = ('Cortex-A5', 'CA5')
42     CA7 = ('Cortex-A7', 'CA7')
43     CA9 = ('Cortex-A9', 'CA9')
44 #    CA5NEON = ('Cortex-A5neon', 'CA5neon')
45 #    CA7NEON = ('Cortex-A7neon', 'CA7neon')
46 #    CA9NEON = ('Cortex-A9neon', 'CA9neon')
47
48     def has_bl(self):
49         return self in [
50             DeviceAxis.CM23NS,
51             DeviceAxis.CM33NS,
52             DeviceAxis.CM35PNS,
53             DeviceAxis.CM55NS,
54             DeviceAxis.CM85NS
55         ]
56
57     @property
58     def bl_device(self):
59         bld = {
60             DeviceAxis.CM23NS: 'CM23S',
61             DeviceAxis.CM33NS: 'CM33S',
62             DeviceAxis.CM35PNS: 'CM35PS',
63             DeviceAxis.CM55NS: 'CM55S',
64             DeviceAxis.CM85NS: 'CM85S'
65         }
66         return bld[self]
67
68
69 @matrix_axis("compiler", "c", "Compiler(s) to be considered.")
70 class CompilerAxis(Enum):
71     AC6 = ('AC6')
72     AC6LTM = ('AC6LTM')
73     GCC = ('GCC')
74     IAR = ('IAR')
75     CLANG = ('Clang')
76
77     @property
78     def image_ext(self):
79         ext = {
80             CompilerAxis.AC6: 'axf',
81             CompilerAxis.AC6LTM: 'axf',
82             CompilerAxis.GCC: 'elf',
83             CompilerAxis.IAR: 'elf',
84             CompilerAxis.CLANG: 'elf',
85         }
86         return ext[self]
87
88     @property
89     def toolchain(self):
90         ext = {
91             CompilerAxis.AC6: 'AC6',
92             CompilerAxis.AC6LTM: 'AC6@6.16.2',
93             CompilerAxis.GCC: 'GCC',
94             CompilerAxis.IAR: 'IAR',
95             CompilerAxis.CLANG: 'CLANG'
96         }
97         return ext[self]
98
99
100 @matrix_axis("optimize", "o", "Optimization level(s) to be considered.")
101 class OptimizationAxis(Enum):
102     NONE = ('none')
103     BALANCED = ('balanced')
104     SPEED = ('speed')
105     SIZE = ('size')
106
107
108 @matrix_axis("model", "m", "Model variant(s) to be considered.")
109 class ModelAxis(Enum):
110     VHT = ('VHT')
111     FVP = ('FVP')
112
113 MODEL_EXECUTABLE = {
114     DeviceAxis.CM0: ("_MPS2_Cortex-M0", []),
115     DeviceAxis.CM0plus: ("_MPS2_Cortex-M0plus", []),
116     DeviceAxis.CM3: ("_MPS2_Cortex-M3", []),
117     DeviceAxis.CM4: ("_MPS2_Cortex-M4", []),
118     DeviceAxis.CM4FP: ("_MPS2_Cortex-M4", []),
119     DeviceAxis.CM7: ("_MPS2_Cortex-M7", []),
120     DeviceAxis.CM7DP: ("_MPS2_Cortex-M7", []),
121     DeviceAxis.CM7SP: ("_MPS2_Cortex-M7", []),
122     DeviceAxis.CM23: ("_MPS2_Cortex-M23", []),
123     DeviceAxis.CM23S: ("_MPS2_Cortex-M23", []),
124     DeviceAxis.CM23NS: ("_MPS2_Cortex-M23", []),
125     DeviceAxis.CM33: ("_MPS2_Cortex-M33", []),
126     DeviceAxis.CM33S: ("_MPS2_Cortex-M33", []),
127     DeviceAxis.CM33NS: ("_MPS2_Cortex-M33", []),
128     DeviceAxis.CM35P: ("_MPS2_Cortex-M35P", []),
129     DeviceAxis.CM35PS: ("_MPS2_Cortex-M35P", []),
130     DeviceAxis.CM35PNS: ("_MPS2_Cortex-M35P", []),
131     DeviceAxis.CM55S: ("_MPS2_Cortex-M55", []),
132     DeviceAxis.CM55NS: ("_MPS2_Cortex-M55", []),
133     DeviceAxis.CM85S: ("_MPS2_Cortex-M85", []),
134     DeviceAxis.CM85NS: ("_MPS2_Cortex-M85", []),
135     DeviceAxis.CA5: ("_VE_Cortex-A5x1", []),
136     DeviceAxis.CA7: ("_VE_Cortex-A7x1", []),
137     DeviceAxis.CA9: ("_VE_Cortex-A9x1", []),
138 #    DeviceAxis.CA5NEON: ("_VE_Cortex-A5x1", []),
139 #    DeviceAxis.CA7NEON: ("_VE_Cortex-A7x1", []),
140 #    DeviceAxis.CA9NEON: ("_VE_Cortex-A9x1", [])
141 }
142
143 def config_suffix(config, timestamp=True):
144     suffix = f"{config.compiler[0]}-{config.optimize[0]}-{config.device[1]}"
145     if timestamp:
146         suffix += f"-{datetime.now().strftime('%Y%m%d%H%M%S')}"
147     return suffix
148
149
150 def project_name(config):
151     return f"Validation.{config.compiler}_{config.optimize}+{config.device[1]}"
152
153
154 def bl_project_name(config):
155     return f"Bootloader.{config.compiler}_{config.optimize}+{config.device.bl_device}"
156
157
158 def output_dir(config):
159     return f"Validation/outdir"
160
161
162 def bl_output_dir(config):
163     return f"Bootloader/outdir"
164
165
166 def model_config(config):
167     return f"../Layer/Target/{config.device[1]}/model_config.txt"
168
169
170 def build_dir(config):
171     return f"build/{config.device[1]}/{config.compiler.toolchain}/{config.optimize}"
172
173
174 @matrix_action
175 def clean(config):
176     """Build the selected configurations using CMSIS-Build."""
177     yield cbuild_clean(f"{project_name(config)}/{project_name(config)}.cprj")
178
179
180 @matrix_action
181 def build(config, results):
182     """Build the selected configurations using CMSIS-Build."""
183
184     logging.info("Compiling Tests...")
185
186     yield cbuild(config)
187
188     if not all(r.success for r in results):
189         return
190
191     file = f"build/CoreValidation-{config_suffix(config)}.zip"
192     logging.info("Archiving build output to %s...", file)
193     with ZipFile(file, "w") as archive:
194         for content in iglob(f"{build_dir(config)}/**/*", recursive=True):
195             if Path(content).is_file():
196                 archive.write(content)
197
198
199 @matrix_action
200 def extract(config):
201     """Extract the latest build archive."""
202     archives = sorted(glob(f"build/CoreValidation-{config_suffix(config, timestamp=False)}-*.zip"), reverse=True)
203     yield unzip(archives[0])
204
205
206 @matrix_action
207 def run(config, results):
208     """Run the selected configurations."""
209     logging.info("Running Core Validation on Arm model ...")
210     yield model_exec(config)
211
212     try:
213         results[0].test_report.write(f"build/CoreValidation-{config_suffix(config)}.junit")
214     except RuntimeError as ex:
215         if isinstance(ex.__cause__, XMLSyntaxError):
216             logging.error("No valid test report found in model output!")
217         else:
218             logging.exception(ex)
219
220
221 @matrix_command()
222 def cbuild_clean(project):
223     return ["cbuild", "-c", project]
224
225
226 @matrix_command()
227 def unzip(archive):
228     return ["bash", "-c", f"unzip {archive}"]
229
230
231 @matrix_command()
232 def preprocess(infile, outfile):
233     return ["arm-none-eabi-gcc", "-xc", "-E", infile, "-P", "-o", outfile]
234
235
236 @matrix_command()
237 def cbuild(config):
238     return ["cbuild", "--toolchain", config.compiler.toolchain, "--update-rte", \
239              "--context", f".{config.optimize}+{config.device[1]}", \
240              "Validation.csolution.yml" ]
241
242
243 @matrix_command(test_report=ConsoleReport() |
244                             CropReport('<\?xml version="1.0"\?>', '</report>') |
245                             TransformReport('validation.xsl') |
246                             JUnitReport(title=lambda title, result: f"{result.command.config.compiler}."
247                                                                     f"{result.command.config.optimize}."
248                                                                     f"{result.command.config.device}."
249                                                                     f"{title}"))
250 def model_exec(config):
251     cmdline = [f"{config.model}{MODEL_EXECUTABLE[config.device][0]}", "-q", "--simlimit", 100, "-f", model_config(config)]
252     cmdline += MODEL_EXECUTABLE[config.device][1]
253     cmdline += ["-a", f"{build_dir(config)}/{output_dir(config)}/Validation.{config.compiler.image_ext}"]
254     if config.device.has_bl():
255         cmdline += ["-a", f"{build_dir(config)}/{bl_output_dir(config)}/Bootloader.{config.compiler.image_ext}"]
256     return cmdline
257
258
259 @matrix_filter
260 def filter_clang_v8m(config):
261     return config.compiler == CompilerAxis.CLANG and config.device.match('CM[2358][35]*S')
262
263
264 @matrix_filter
265 def filter_clang_cortex_a(config):
266     return config.compiler == CompilerAxis.CLANG and config.device.match('CA*')
267
268
269 if __name__ == "__main__":
270     main()