build: presets.generated runs, and the tier list lives in the sources
make_presets.py documented a presets.generated test that was never registered, so a hand edit to CMakePresets.json could drift unseen; it is registered now, and the generator names its encoding and line ending so a regeneration on Windows writes the same file. The CMake comment's per-tier essay repeated each source's own header - and claimed naked stubs where all four use startup::entry - so it points there instead, and the flash size the boot base and the wrap-around both follow from is named once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bc671618a7
commit
f50032ee46
2 files changed
+24
-41
No files matched your search
+22
-39
@@ -34,9 +34,8 @@ if(PROJECT_IS_TOP_LEVEL)
|
||||
# distribution's compiler speaks in full).
|
||||
#
|
||||
# **A host that cannot build it registers those tests anyway and skips
|
||||
# them.** They used to be left out, which makes the suite a different size
|
||||
# on a different machine - and a suite whose size is a property of the
|
||||
# machine is one nothing can be compared against.
|
||||
# them**: leaving them out would make the suite's size a property of the
|
||||
# machine, and such a suite is one nothing can be compared against.
|
||||
set(TSB_DEVICE ${CMAKE_BINARY_DIR}/tsb_device)
|
||||
find_program(_host_cxx NAMES c++ g++)
|
||||
set(_tsb_absent "${LIBAVR_NO_PYTHON}")
|
||||
@@ -66,6 +65,11 @@ if(PROJECT_IS_TOP_LEVEL)
|
||||
if(_tsb_absent)
|
||||
message(STATUS "the protocol tests skip here - ${_tsb_absent}")
|
||||
endif()
|
||||
|
||||
# CMakePresets.json is generated; the gate holds it to its generator.
|
||||
libavr_launcher(_presets_python "${LIBAVR_NO_PYTHON}" ${Python3_EXECUTABLE})
|
||||
add_test(NAME presets.generated
|
||||
COMMAND ${_presets_python} ${CMAKE_CURRENT_SOURCE_DIR}/tools/make_presets.py --check)
|
||||
endif()
|
||||
|
||||
# The ELF is only a container (symbols, section headers) and is never flashed -
|
||||
@@ -82,48 +86,27 @@ function(add_image_outputs name)
|
||||
$<TARGET_FILE:${name}> $<TARGET_FILE:${name}>.bin)
|
||||
endfunction()
|
||||
|
||||
# The TinySafeBoot protocol reimplemented on libavr in variants that trade
|
||||
# clarity for size. Each links into the ATmega328P boot section (BOOTSZ selects
|
||||
# its size; BOOTRST vectors a reset to its base) with -nostartfiles - a polled
|
||||
# loader has no use for the crt or the vector table. The entry sits in
|
||||
# .vectors, laid first, and runs - avr::startup::entry on the policy tier,
|
||||
# the experiment tiers' own naked stubs elsewhere, each documented in its
|
||||
# source. The boot base is FLASHEND+1 minus the section size; the linker
|
||||
# section-start and the source's boot_bytes agree. tsb_app is
|
||||
# the application's reset vector, pinned to 0 here so the loaders jump to a
|
||||
# named function; --pmem-wrap-around lets relaxation turn that absolute jump
|
||||
# into the wrapped rjmp AVR's modulo-flash PC actually executes.
|
||||
# All four implement the full oracle feature set (see oracle/README.md):
|
||||
# watchdog bail, one-wire half-duplex, config-page activation timeout, password
|
||||
# gate, emergency erase, config/flash/EEPROM read-write. They differ only in how,
|
||||
# and the size gradient is the cost of that "how".
|
||||
# tsb_asm - the tricks tier's C++ with exactly two routines in asm: the
|
||||
# bounded rx and the page-store loop, the two whose remaining
|
||||
# cost is the C ABI itself. Everything else, bring-up to
|
||||
# dispatch, is C++ on libavr.
|
||||
# tsb_tricks - no asm at all: the whole-loader register allocation lives in
|
||||
# global register variables (Y walks the page pointer), every
|
||||
# helper is a tiny noinline primitive placed by the
|
||||
# global-register store rules, pages stream straight to
|
||||
# SPM/EEPROM.
|
||||
# tsb_pure - pure idiomatic libavr, one function per command, TU-local
|
||||
# (internal linkage), streaming (no SRAM page buffer).
|
||||
# tsb_policy - the policy floor: no inline assembly and no global register
|
||||
# variables, which is philosophy #5's own bound, and the
|
||||
# measured evidence that the 512 B fit is a property of the
|
||||
# mechanisms it bans.
|
||||
#
|
||||
# What each measures is oracle/README.md's table, which is the one place the
|
||||
# four numbers and the hand-written loader's own are compared.
|
||||
#
|
||||
# The TinySafeBoot protocol reimplemented on libavr in four tiers that trade
|
||||
# clarity for size, each with the full oracle feature set; each source's header
|
||||
# says what its tier is allowed, and oracle/README.md compares what they
|
||||
# measure. Each links into the ATmega328P boot section (BOOTSZ selects its
|
||||
# size; BOOTRST vectors a reset to its base) with -nostartfiles - a polled
|
||||
# loader has no use for the crt or the vector table - and its entry sits in
|
||||
# .vectors, laid first. The boot base is the flash size minus the section size;
|
||||
# the linker section-start and the source's boot_bytes agree. tsb_app is the
|
||||
# application's reset vector, pinned to 0 here so the loaders jump to a named
|
||||
# function; --pmem-wrap-around lets relaxation turn that absolute jump into the
|
||||
# wrapped rjmp AVR's modulo-flash PC actually executes.
|
||||
set(TSB_FLASH_KIB 32)
|
||||
|
||||
# add_tsb_variant(<name> <boot-section-bytes>)
|
||||
function(add_tsb_variant name bytes)
|
||||
math(EXPR base_dec "32768 - ${bytes}")
|
||||
math(EXPR base_dec "${TSB_FLASH_KIB} * 1024 - ${bytes}")
|
||||
math(EXPR base_hex "${base_dec}" OUTPUT_FORMAT HEXADECIMAL)
|
||||
add_executable(${name} tsb/${name}.cpp)
|
||||
target_link_libraries(${name} PRIVATE libavr)
|
||||
target_link_options(${name} PRIVATE -nostartfiles -Wl,--section-start=.text=${base_hex}
|
||||
-Wl,--defsym=tsb_app=0 -Wl,--pmem-wrap-around=32k)
|
||||
-Wl,--defsym=tsb_app=0 -Wl,--pmem-wrap-around=${TSB_FLASH_KIB}k)
|
||||
add_custom_command(TARGET ${name} POST_BUILD COMMAND ${CMAKE_SIZE} $<TARGET_FILE:${name}>)
|
||||
add_image_outputs(${name})
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
|
||||
@@ -75,12 +75,12 @@ def main():
|
||||
rendered = json.dumps(presets, indent=1) + "\n"
|
||||
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "CMakePresets.json")
|
||||
if "--check" in sys.argv[1:]:
|
||||
current = open(path).read() if os.path.exists(path) else ""
|
||||
current = open(path, encoding="utf-8").read() if os.path.exists(path) else ""
|
||||
if current != rendered:
|
||||
print("CMakePresets.json does not match its generator - run tools/make_presets.py")
|
||||
return 1
|
||||
return 0
|
||||
with open(path, "w") as f:
|
||||
with open(path, "w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(rendered)
|
||||
print(f"{len(CHIPS)} chips, {len(REFLECT_SPOT)} reflect: {os.path.normpath(path)}")
|
||||
return 0
|
||||
|
||||
Reference in new issue
Block a user