libavr 93d8b0e. The check is handed the sibling build tree now and asks its build system whether the image is current, so a comparison against a tree the run did not build skips rather than passing. Gated at the pin. Its own gate builds both modes, so the comparison still happens.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The libavr pin moves to the preset loop's own fix. `tools/check-presets.sh` -
which this repository's gate calls - parsed `cmake --list-presets` by anchoring
a preset name's closing quote to the end of the line, and a preset carrying a
`displayName` is listed as `"name" - description`. The presets here are
undescribed, so the loop found them either way; one `displayName` away it would
have found none and said the repository had no presets. The loop has a test
aimed at it now, which it did not before - libavr runs none of its own presets
through it.
`.gitattributes` gains `* text=auto eol=lf`. Naming the source extensions left
Markdown, Python, shell and CMake to whatever wrote them, and on the Windows
side of this bench that is CRLF - which turns an eighty-line edit into a rewrite
of every file it touched and buries the change in the diff. Rule 50 carries the
sentence now, so it is the repository's default rather than a habit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The pin moves to libavr's USI I2C rate fix and to the two override surfaces the
fan-controller port filed - a PWM solve that can be pinned, and a capture edge
that is a value rather than a template argument. Nothing here names any of
them; four presets green and no image moved.
`tools/check.sh` is new, and its absence was the defect: this repository had no
committed gate at all, so "run the suite" was a snippet somebody remembered -
and the order in a snippet is the one thing nobody re-derives. Every preset
built before any is tested is subtle and load-bearing, because the
mode-identity check reads the sibling mode's tree and a build-then-test-per-
preset run holds a fresh image against a stale sibling. The loop is libavr's
`tools/check-presets.sh`; nothing is written after the call, there being nothing
beyond the presets this repository knows to ask.
And `.vscode/settings.json` stops naming a toolchain prefix. It named
`D:/dev/libavr/local/toolchain/avr-gcc-16.1.0-mingw`: a path true of one machine
(libavr guidance rule 50) and, since the in-repo toolchain copies went, true of
none. `local/machine.cmake` is where a checkout says that, and it already did.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The growth is not this bump's. It entered at libavr 32f8167, where the
software master started clocking the rate it is told: the phase padding has to
cover the shortest bit of a byte, and paying for it costs `shift_out` and
`read_acked` twelve bytes each on the tiny85. Those two symbols are the whole
of the move - an avr-nm diff across the two images names them and nothing else.
So the claim went unheld through two pin bumps. 1246 B was last measured at
libavr e697920; the tiny85 preset has read 1270 since 32f8167, which both
5a042a9 and f2205a7 pinned past without re-recording it. The number is stated
in test/CMakeLists.txt and in README.md, and this is what keeps them one fact -
a check that only ever ran on one of the two chips keeps neither.
The suite also stops depending on its host: libavr's launcher and skip marker
register every check everywhere, and one this machine cannot run reads as
Skipped rather than going missing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
One commit, and it is the host check script this repo runs on every target
plus its own new test: `check-compare-debug.py` was splitting each recorded
compile command with POSIX rules, which eat a Windows compiler path, so that
check died here rather than reporting. Nothing a device image is compiled from
moved, and the comparison says so - every image this repo builds is
byte-for-byte the one it built at the previous pin.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The furthest behind of the fleet, and the least affected: the clock example is
**byte-identical at 1480 B** across all fifty-three, so nothing this driver
emits moved. Four checks green.
Built at the old pin first for the comparison, which needed the host's tool
suffix named in the working tree - that pin predates the toolchain file
learning it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1316 -> 1246. libavr took the finding this repo filed when its pin last moved:
the shared transaction ladder's cost was never the ladder but the argument
list reaching it - AVR passes eight bytes in call-clobbered registers and the
rest in call-saved ones, so twelve bytes made every forwarder save four it
never reads. A write has no read span, so the write path now passes eight.
Worth recording that the candidate this repo suggested was measured and
rejected upstream, and the numbers filed from here are why: it wins 66 B on a
driver like this one and charges a single-byte reader 20, which is a class
rather than one program.
The mega328P does not move at 1480 - its TWI backend has its own ladder and
was never charged. Net over the whole 22-commit advance the tiny85 is +8 B,
and all of it is the bit-period fix that made the wire rate stop following the
inliner.
Sixteen tests green, cross-mode identity held on both chips.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
43fc479 -> aec9955. The mega328P does not move at 1480 B - it drives the RTC
from the TWI block, which neither change touches. The tiny85 has no TWI, so
dev::i2c resolves to the bit-banged master there and takes both:
cb40a13, the bit period 1238 -> 1262 (+24)
943ffbe, one call shape over every master 1262 -> 1316 (+54)
The first is a bug being paid for. software_master delayed a fixed quarter
period and let its own instructions make up the rest of the bit, so the rate
on the wire followed the inliner; each bit now delays a low and a high phase
net of what that phase already spends. The DS3231 is a 400 kHz part and this
example asks for 100, so nothing here was out of spec - the bytes buy a rate
that no longer moves when the image does.
The second is a trade, and it is worth writing down which way it went. The
shared ladder is smaller than the two it replaced - run_transfer is 232 B
against read_regs 162 + write_regs 102 + stop 30 - but the call-site thunks
that marshal spans into it cost 116 B where the specialised ladders were
inlined, so a driver making both calls nets +54. Filed upstream with these
numbers rather than worked around here: which way the trade falls is a
property of the consumer's mix, and that is the library owner's call.
Size re-recorded in the two places that state it. Four presets green,
cross-mode identity held on both chips.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The pin advances to the commit that gives consumers the gate's own image
comparison, and the claim written into this README a few commits ago - 1480 B
and 1238 B, byte-identical across the two modes - is registered against it.
Both chips compare clean over every loadable section.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every other port in the fleet states its image size and is held to it; this
one stated none, so a library advance could move `clock` and no check would
say a word - which is exactly what the size claim was built after. The two
numbers are what the presets build today, byte-identical across generated
and reflect, and the README now says both.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The vector that inlines its handler is the one advance that could reach a
driver on the two-wire bus, and it does not reach this one: `clock` drives
the bus from the foreground, so it is byte-identical across the advance in
all four modes - 1238 B on the attiny85, 1480 B on the atmega328p.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Guidance rule 15 puts every machine-local artefact under a gitignored local/,
and this repo could only have committed one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
libavr's guidance binds this repo too, and until now nothing here checked it -
`ctest` runs `libavr_format_test()` over this tree's own sources now (rules 11
and 33), skipping rather than passing where clang-format is absent. It caught
drift on its first run: a file written this week and edited after formatting.
Where the README states a measured size, `libavr_size_claim_test()` holds it to
the image and holds the image to the prose: advancing the library pin moved
three of these across the fleet with nothing saying so, and re-recording one
now requires the sentence that quotes it to move too.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Documentation only - the guideline sweep's condensed entry, the three measured
facts about class-type constants it produced, and the port filings it left
open. No header, tool or generated input moves, so every image is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`set_alarm1/2`'s `enable_interrupt = false` did nothing at all - it skipped the
control-register write rather than clearing A1IE/A2IE - and there was no other
way to clear them, so an alarm armed once with its interrupt on drove INT/SQW
for good. It is `alarm_interrupt::off` now and it clears the bit, with
`listen_alarm1/2()` and `mute_alarm1/2()` beside it for a caller that arms once
and changes its mind later. The bare bool went with it (rule 37): `set_alarm1(at,
rate, false)` said nothing at the point of use.
`bool SetWeekday` was the same shape one level up - `device<bus, false>` names
nothing - and its two writers disagreed about what it meant: `write_date`
skipped the weekday register, `write_clock` stamped a placeholder 1 into it, so
a program that turned the maintenance off still had the register overwritten
and no way to set it. `weekday_source::external` now means the register is the
program's, in both writers.
test/consteval.cpp is the battery this driver never had, over the arithmetic
that has no bus in it: the BCD round trip across every representable value and
its nibble layout, the hours register in both formats including all four
noon/midnight cases, Sakamoto's weekday against six calendar dates (leap day,
the day after it, and 2100's missing leap), and both alarms' rate encodings
transcribed against 19-5170 Table 2 - including that alarm 2's masks sit one
place below alarm 1's, which is the property that makes one distribution loop
wrong for the other. Red-green: two assertions fire on a flipped DY bit.
Beside it, one decode rather than two: `read_clock` and `read_time` spelled the
seconds/minutes/hours triplet out separately (rule 6).
Every image byte-identical on both chips in both modes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The pin crosses libavr's phase-6 close and the guideline sweep behind it;
the example is byte-identical on both chips in both modes.
The port's own sweep found rule 36 in seven places, and the fix had to be
measured rather than applied. Sakamoto's month offsets as a `std::to_array`
local cost **+348 bytes** on a 1480-byte image - an automatic class-type
constant inside a `constexpr` function is given an address and built per
call, which outlined `weekday()` whole and pulled in `__do_copy_data` and
`__udivmodhi4`; `static constexpr` is what folds it, and emits no symbol at
all. The six register buffers cost +4 as `to_array`, which materialises its
argument array before copying where an aggregate initialiser stores each
element as it is computed - so those take CTAD, which counts the extent and
keeps the direct initialisation. Both spellings are rule 36; only one is
free.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The three files libavr's consumers carry: .vscode/settings.json names the
atmega328p-generated database and passes --query-driver, .clangd holds the
stand-ins clang needs for GCC's AVR dialect -- and no database, because this
driver is made to be vendored and the file travels with it -- and
extensions.json names the two extensions. The libavr pin advances to the
editor-audit fixes, without which every TU inherits device.hpp's
alias-shadowing errors. The preset builds green from the pin and clangd
reports zero errors on the example TU.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The register sugar now rides the bus's own master role - device<Bus>
resolves avr::i2c::device<typename Bus::master, bus_address>, so a
consumer keeps handing over its declared dev::i2c<...> unchanged - and
the DS3231's hardwired 0x68 is a named constant. The example's four
discards became the LED's own error signal (a failed seed or a failed
alarm clear holds it dark, the same word a stuck bus says), the tree is
reformatted under InsertBraces, the sources are ASCII, and the README's
stale Studio byte counts are replaced by the claim its check-flags gate
holds.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
timer::engine gains stop()/start() and a runtime TOP, adc gains
disable()/enable(), and libavr_programming_targets() stops leaving .fuse bytes
in the flash HEX. Every one of them is additive, and this port adopts none of
them yet: its 1 built image comes out byte-identical across the pin change,
which is what the advance is here to keep true.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Built and tested against it in a clean checkout of this port, through its own
submodule rather than a working-tree override, so the pin is what was proved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The de-string-2 pass upstream: every peripheral block behind generated
instance traits, the string layer gone. Nothing here changes — both
examples rebuild byte-identically across modes at their recorded sizes
(tiny85 1212 B, mega328P 1242 B).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The submodule replaces FetchContent and the unpinned forge fallback;
LIBAVR_ROOT stays as the tandem-development override, the presets take the
toolchain file from the submodule, and the Studio project's include path
anchors there — correct by construction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The presets cover both parts, so the solution should too. Studio carries
avrdevice as a project property, so a part is a project rather than a
configuration, and both build example/main.cpp to a .text byte-identical to
their CMake counterpart: 1242 B on the mega, 1212 B on the tiny, each with the
architecture its own object file says.
They need separate directories, not just separate names. Studio builds into
<project dir>/<Configuration> whatever OutputDirectory claims — setting it per
project creates the directory and then ignores it — so two projects in one
directory share example/main.o. Verified rather than assumed: with both in ide/,
the single shared object read avr:25 while the mega's ELF read avr:5, so a
build of one after the other without a rebuild links the wrong part's object.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
master opens in Studio, so this branch should too. The solution builds
example/main.cpp — the port's only executable, the driver itself being an
INTERFACE library — for the ATmega328P that solution targeted, and the
acceptance is not that it builds but that it builds the same firmware: .text
comes out byte-identical to CMake's at 1242 B.
One project, one chip. Studio carries avrdevice as a project property, so the
attiny85 half of the presets would need a second project rather than a second
configuration; CMake stays the build system and covers both.
libavr is found beside this repo, anchored to the project directory rather than
written relative to the generated makefile, which runs from the configuration's
output directory. No LIBAVR_ROOT: a variable exported in a shell is invisible to
Studio launched from the Start menu.
Both configurations verified headless with LIBAVR_ROOT unset, and the flag
mirror checked against the CMake build's own compile_commands.json.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Same driver surface as the yazoalfa version — clock and alarm get/set,
alarm interrupts, flag check/clear — plus oscillator-stop detection and
die temperature. One source for tiny85 (software I2C) and mega328P (TWI),
built against libavr in both generated and reflect mode, byte-identical
.text across modes. Errors surface as std::expected instead of being
dropped; weekday-rate alarms now really set the DY bit (legacy cleared
it); multi-register access is one coherent bus transaction. Legacy stays
on master.
Co-Authored-By: Claude <noreply@anthropic.com>