From 5d1b4497d4930cd87537821982882da3837d3132 Mon Sep 17 00:00:00 2001 From: BlackMark Date: Thu, 30 Jul 2026 17:31:22 +0200 Subject: [PATCH] build: the libavr pin advances over the drain and delay contracts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hand-over drains move to the explicit drain_unbounded() — both link adapters drain only after their own write, so the frame is in flight by construction and the bounded default's countdown would be dead bytes; the images stay byte-identical. window_polls() states its arithmetic through dev::cycles_for with the whole window converted before the per-poll division — one truncation instead of one per second, same instructions, only the countdown's immediate moves. Every size in the matrix is unchanged; the full gate is green on all 37 chips. Co-Authored-By: Claude Fable 5 --- libavr | 2 +- pureboot/pureboot.cpp | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libavr b/libavr index 56337f3..c21ed31 160000 --- a/libavr +++ b/libavr @@ -1 +1 @@ -Subproject commit 56337f37de2f369a6196f8bfdf0b7165b8ea61bf +Subproject commit c21ed3171efd9081a77194a1f3c96d0e62202984 diff --git a/pureboot/pureboot.cpp b/pureboot/pureboot.cpp index c2f154c..76905de 100644 --- a/pureboot/pureboot.cpp +++ b/pureboot/pureboot.cpp @@ -10,6 +10,8 @@ // is what makes a copy one slot below able to rewrite the resident one, and // every change here has to keep it (test/check_pi.py). +#include + #include using namespace avr::literals; @@ -209,7 +211,10 @@ struct hardware_link { static void drain() { - uart::drain(); + // A drain here always follows this link's own write — the frame is + // in flight by construction, so the completion the wait needs is + // guaranteed and the bounded default's countdown would be dead bytes. + uart::drain_unbounded(); } }; @@ -277,7 +282,10 @@ struct autobaud_link { static void drain() { - uart::drain(); + // A drain here always follows this link's own write — the frame is + // in flight by construction, so the completion the wait needs is + // guaranteed and the bounded default's countdown would be dead bytes. + uart::drain_unbounded(); } }; @@ -340,7 +348,10 @@ void await_host() // cost stays wide, so the choice cannot oscillate on the boundary. consteval std::uint32_t polls_at(std::uint32_t per_poll) { - return timeout_seconds * (dev::clock.hz / per_poll); + // Whole-window cycles first, then the per-poll division: one truncation + // instead of one per second. Same instructions either way — only the + // countdown's immediate moves. + return static_cast(dev::cycles_for() / per_poll); } consteval bool narrow_window()