build: the libavr pin advances over the drain and delay contracts

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 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 17:31:22 +02:00
parent a743ea64a3
commit 5d1b4497d4
2 changed files with 15 additions and 4 deletions

2
libavr

Submodule libavr updated: 56337f37de...c21ed3171e

View File

@@ -10,6 +10,8 @@
// is what makes a copy one slot below able to rewrite the resident one, and // 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). // every change here has to keep it (test/check_pi.py).
#include <chrono>
#include <libavr/libavr.hpp> #include <libavr/libavr.hpp>
using namespace avr::literals; using namespace avr::literals;
@@ -209,7 +211,10 @@ struct hardware_link {
static void drain() 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() 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. // cost stays wide, so the choice cannot oscillate on the boundary.
consteval std::uint32_t polls_at(std::uint32_t per_poll) 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<std::uint32_t>(dev::cycles_for<std::chrono::seconds{timeout_seconds}>() / per_poll);
} }
consteval bool narrow_window() consteval bool narrow_window()