You've already forked torvalds-GuitarPedal
mirror of
https://github.com/torvalds/GuitarPedal.git
synced 2026-08-19 13:34:01 +00:00
'Software' was the directory everything that was not KiCad ended up in, which stopped describing anything a while ago - Validation and the web app are software too. Worse, it put the shared parts inside the firmware, where they read as the firmware's own. They are not. Effects/ has three consumers built from it: the firmware, Validation's bench, and the web app's controls, all generated from the same POT: comments by gen_effects.py. Audio/ has two - the bench compiles the same biquads, the same envelope followers and the same single_sample(), which is the whole reason a measurement on a workstation says anything about the pedal. Neither belongs under Firmware/, so neither is under it any more: Effects/ one file per effect Audio/ the DSP they are built from, and the audio loop Firmware/ the rest of what runs on the pedal, and the submodules WebMIDI/ the web app scripts/ what the build runs Validation/ unchanged Hardware/, Documentation/, Images/ CMakeLists.txt and the wrapper Makefile move to the top with them, because the build now consumes four of those directories and generates into a fifth. board.local and build/ come along; MIDI_CC_MAP.md is generated into Documentation/ rather than into the old Software/ root. scripts/ goes with the build rather than staying under the firmware, because six of the ten had nothing to do with the firmware: gen_effects.py reads Effects/ and writes to three different places, pow2/log2/quarter_sine generate Audio/'s tables, check-readme.py compares Effects/ against the README, and server.py serves the web app. Four of them are invoked from Validation, which was reaching into Firmware/ for tooling - the same burying this commit is undoing. The four that really are about the firmware are ELF checks the top-level build drives anyway, and a second scripts directory would only be a second place to look. C includes say "Audio/foo.h" and the generated map says "Effects/bar.h", with the repository root on the include path for both the firmware and the bench. Spelling the directory out rather than relying on a bare name is what keeps Audio/cycles.h shimmable: a quoted include searches the including file's own directory first. The submodules are renamed as well as moved. git mv updates their paths but leaves the section names, and 'Software/pico-sdk' surviving in .gitmodules would be the word this commit removes, still load-bearing. That meant the nested modules under pico-sdk too - six .git files pointing into .git/modules/Software - which is why 'git submodule update --init --recursive' is worth running once after pulling this. Verified rather than assumed: a clean configure and build, make check (failing only on the missing-eeprom case it already failed on), check-effects, all four analysis pages reproducing every series and drawing every chart, and a flash to the board that still measures a routed reverb where it did before. One latent bug fell out of it. bench/coeff declared only quarter_sine.h of the three generated math tables, and Audio/util.h includes pow2.h and log2.h as well - so building that target with an empty gen/ could never have worked. 'make bench' builds bench/bench first, which generates all three, so it stayed hidden until this rebuilt everything from nothing. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
81 lines
3.0 KiB
Python
Executable File
81 lines
3.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Check that the firmware contains no double-precision arithmetic, and
|
|
# no calls into the SDK's math libraries.
|
|
#
|
|
# The FPU on this part is single precision only. A 'double' that sneaks
|
|
# in doesn't fail to build - it quietly pulls in the AAPCS software
|
|
# helpers, which are hundreds of cycles where the hardware would have
|
|
# taken one. That is why the audio code has its own pow2/log2 tables and
|
|
# fastsincos() instead of calling libm, and why -fsingle-precision-constant
|
|
# and -Wdouble-promotion are on. This is the backstop for all of it: the
|
|
# helpers are named, so if one is in the image we can say which.
|
|
#
|
|
# The wrappers are the other half. pico_float and pico_double interpose
|
|
# on sinf(), pow() and the rest with -Wl,--wrap, so a call to one of them
|
|
# is invisible by name: no link error, no warning, it just turns up in
|
|
# the binary. We do all of that arithmetic with the generated tables
|
|
# instead, so one of these appearing means something started calling libm.
|
|
#
|
|
# Called as: check-float.py <elf> [nm]
|
|
#
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
#
|
|
# The AAPCS double helpers. Two shapes: everything operating on a double
|
|
# ('__aeabi_dadd', '__aeabi_cdcmple', '__aeabi_d2iz'), and the promotions
|
|
# into one ('__aeabi_i2d', '__aeabi_f2d').
|
|
#
|
|
DOUBLE = re.compile(r"^__aeabi_(c?d|(f|i|ui|l|ul)2d$)")
|
|
|
|
#
|
|
# The functions pico_float and pico_double interpose on. Both the double
|
|
# name and the float one - pico_float wraps 'sinf', pico_double 'sin'.
|
|
#
|
|
MATH = """sqrt cos sin tan atan2 exp log ldexp copysign trunc floor ceil
|
|
round sincos asin acos atan sinh cosh tanh asinh acosh atanh
|
|
exp2 log2 exp10 log10 pow powint hypot cbrt fmod drem remainder
|
|
remquo expm1 log1p fma""".split()
|
|
|
|
WRAPPED = {"__wrap_" + m for m in MATH} | {"__wrap_" + m + "f" for m in MATH}
|
|
|
|
|
|
def main():
|
|
elf = sys.argv[1]
|
|
nm = (sys.argv[2] if len(sys.argv) > 2 and sys.argv[2]
|
|
else "arm-none-eabi-nm")
|
|
|
|
res = subprocess.run([nm, elf], capture_output=True, text=True)
|
|
if res.returncode:
|
|
sys.exit(f"check-float: {nm} failed:\n{res.stderr}")
|
|
|
|
bad = []
|
|
for line in res.stdout.splitlines():
|
|
field = line.split()
|
|
if len(field) < 2:
|
|
continue
|
|
name = field[-1]
|
|
if DOUBLE.match(name):
|
|
bad.append((name, "double-precision helper"))
|
|
elif name in WRAPPED or name.startswith("__wrap___aeabi_"):
|
|
bad.append((name, "libm call routed through pico_float/pico_double"))
|
|
|
|
if bad:
|
|
print(f"check-float: {len(bad)} symbol(s) that should not be here:",
|
|
file=sys.stderr)
|
|
for name, why in sorted(bad):
|
|
print(f" {name} - {why}", file=sys.stderr)
|
|
print("\nLook for a bare constant without its 'f', an implicit "
|
|
"promotion,\nor a math call that wants doing with a table "
|
|
"instead.", file=sys.stderr)
|
|
return 1
|
|
|
|
print("check-float: no doubles, no libm")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|