<feed xmlns='http://www.w3.org/2005/Atom'>
<title>threadx.git/ports/cortex_r52/gnu/example_build, branch master</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.</subtitle>
<id>http://cgit.235523.xyz/threadx.git/atom/ports/cortex_r52/gnu/example_build?h=master</id>
<link rel='self' href='http://cgit.235523.xyz/threadx.git/atom/ports/cortex_r52/gnu/example_build?h=master'/>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/'/>
<updated>2026-09-28T18:03:53Z</updated>
<entry>
<title>Normalized the AI disclosure comment and added a check that keeps it so (#762)</title>
<updated>2026-09-28T18:03:53Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-28T18:03:53Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=83361990cb4d03da8851e30030688ed3abb4d840'/>
<id>urn:sha1:83361990cb4d03da8851e30030688ed3abb4d840</id>
<content type='text'>
* Normalized the AI disclosure line across every tracked file type

The repository-wide pass covered source files only, so build files, CMake
toolchain files, shell scripts and the GDB and manifest files kept the older
per-edit form of the disclosure comment, which names a product and a model
version. The Cortex-R52 module manager port then merged after that pass and
brought the old form back into the sources as well.

Replaced it with the fixed text in all of them, using the comment character
each file already uses.

Comment-only. 143 files, one line each. The repository now holds 601 files
carrying exactly one disclosure line, none carrying the old form, and none
carrying more than one.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;

* Added a check that keeps the AI disclosure comment in its one accepted form

Nothing enforced the disclosure convention, so the drift it exists to prevent
returned twice: once when a port merged after the normalisation pass carrying
the older per-edit form, and once because that pass had covered source files
only, leaving build files and scripts untouched for months.

Added scripts/check_ai_disclosure.sh, which rejects the superseded per-edit
form, a doubled comment marker, more than one disclosure line in a file, and
any spelling of the line that is not exact. It runs from repo_checks.yml, a
workflow with no path filter, because a source-path filter is what hid the
build files the first time.

The check passes on this branch. Each of its four rules was confirmed to fail
on a tree with that defect reintroduced, and to pass once it was removed.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;

* Normalised the disclosure lines that landed after this branch

Thirteen files reached dev after this branch was written, each carrying the
superseded per-edit form. txm_module_manager_dispatch.h reached it with six
stacked copies, naming the same product and the same model every time -- the
accumulation the fixed text exists to prevent.

Each of those files now carries one disclosure line in the accepted form. Where
the accepted line was already present, the superseded ones are deleted rather
than converted, so no file gains a second.

check_ai_disclosure.sh reported eighteen hits across thirteen files before the
pass and passes after it.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;

* Exempted Markdown from the near-miss disclosure check

The near-miss rule flags any line carrying the phrase "AI assistance" that is
not the accepted text, which is right for source but wrong for documentation.
The contribution guide has to quote the accepted line and say when it applies,
so the check reports two paragraphs of prose as drift and fails the build.

Markdown is now exempt from that rule alone. The three rules that matter for a
documentation file -- superseded form, doubled comment marker, duplicate line
-- still scan it, so a stale disclosure in a Markdown file is still caught.

The check passes against a tree carrying the rewritten contribution guide, and
still fails when a near miss is planted in a source file.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;

* Corrected the trailer command named in the disclosure check

The header comment points a reader at git's own trailer parser to find out
which agents have touched a file. That parser reads trailers only from a block
at the very end of a message, so a squash merge -- which concatenates a
branch's messages -- buries every trailer but the last one mid-message, and an
indented trailer is skipped outright. On dev it finds 122 attributions where
163 exist.

The comment now names count_assisted_by.sh, which reads whole bodies.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Added a ThreadX module manager port for the Cortex-R52 (#639)</title>
<updated>2026-09-17T19:39:30Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-17T19:39:30Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=70a530097722665b7f3704cf5099b99f255b2e5f'/>
<id>urn:sha1:70a530097722665b7f3704cf5099b99f255b2e5f</id>
<content type='text'>
  Added the first GNU ThreadX module port for an Arm R-profile core.

  The port combines the PMSAv8-R MPU model from Cortex-M33 with the AArch32
  privilege and processor-mode handling from Cortex-R4. It provides the complete
  module path: headers, manager sources, scheduler integration, user-mode entry,
  SVC dispatch, data- and prefetch-abort capture, fault notification, relocatable
  module loading, and shared-memory regions.

  Module isolation uses eight MPU regions (8–15) with a 64-byte granule. The
  scheduler replaces those regions on each module switch and manages a separate
  privileged loading window in region 16. Assembly-visible structure offsets and
  region-layout assumptions are checked at build time.

  Added independent module demonstrations for the S32Z280-594EVB and Armv8-R AEM
  FVP. The automated FVP regressions cover:

  - Loading the same position-independent module at different addresses
  - User-mode data and instruction access violations
  - Fault capture and notification for both abort types
  - Shared-region access, alignment, exhaustion, empty-size, and overflow handling
  - Required module-property combinations
  - The GCC CLZ-based priority search

  The port requires user mode and memory protection together, at least 17 EL1 MPU
  regions, and currently validates A32 modules; Thumb module execution remains
  unvalidated.

  Validated with GNU Arm 14.3.1. The FVP suites pass 8/8 in the default
  configuration and 11/11 with hard-float, FIQ, and interrupt nesting enabled.
  The S32Z280 images build cleanly, and the module isolation and relocation paths
  were exercised on S32Z280 silicon during development.

  Matching user documentation is provided by rtos-docs-asciidoc PR #41.

  Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Normalized the AI disclosure comment to one fixed line per file (#740)</title>
<updated>2026-09-15T21:17:26Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-15T21:17:26Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=9e4c57138dfa004cd512b60259c1c5047a8b3dd1'/>
<id>urn:sha1:9e4c57138dfa004cd512b60259c1c5047a8b3dd1</id>
<content type='text'>
The per-edit disclosure named the product and model, so every agent and every
model version appended another line. 74 files carried two to four of them, and
the same five products had accumulated 13 spellings -- Copilot against GitHub
Copilot, Claude Sonnet 4.6 against claude-sonnet-4.6, four spellings of Codex.
Twenty assembly lines carried a doubled comment marker, `; //` or `@ //`.

Every file now carries exactly one line, fixed text naming no product:

    Portions of this file were generated with AI assistance.

It is written with the comment character that file already uses, so the `;`
and `@` assembly files keep theirs and the doubled markers are gone. Precise
attribution stays on the commit, where the Assisted-by trailer is per-change,
dated and attached to the diff it describes. A header line cannot hold that
record honestly, because the code it names gets rewritten and the line stays.
A file-level flag answers whether; the history answers who.

Comment-only. 455 files, 455 insertions and 574 deletions: every removed line
was a disclosure line, every added line is the fixed text, and no file is left
with zero or with more than one. `scripts/check_ports.sh` passes, including the
reproducibility check that would catch a ports_arch master and its generated
copies drifting apart. Recompiled against dev, every file that builds without a
vendor toolchain gives a byte-identical object: 19 of 19 C files under common,
100 of 100 GNU assembly files, and all 16 assemblable files whose comment
marker changed. The 10 remaining marker changes are ac5 and IAR sources where
`;` already started the comment and only the redundant `//` was removed.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Added the boot-at-EL1 option to the S32Z280 entry path (#690)</title>
<updated>2026-09-02T23:08:24Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-02T23:08:24Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=13c8c768c73b9ce10c9605f6df8b02080440f953'/>
<id>urn:sha1:13c8c768c73b9ce10c9605f6df8b02080440f953</id>
<content type='text'>
The Armv8-R AEM FVP entry path has carried TX_R52_BOOT_AT_EL1 since it
was written, for the case its own comment describes: "an earlier boot
stage or a vendor EL2 monitor has already dropped privilege to EL1".
This board's entry path did not, so a kernel could not be built as a
guest on it at all -- and it is the board where that matters most,
because it is the one with silicon behind it.

The bracket is the whole change.  Everything from the Thumb reset
trampoline to the ERET goes inside #ifndef TX_R52_BOOT_AT_EL1, and the
#else supplies a one-instruction A32 _start that branches to el1_entry.

A32 AND NOT T32, which is the one real difference from the standalone
entry.  The core resets in Thumb state here because the RTU boot
instruction NXP plants is a T32 branch, but a guest is not reached by
reset: it is reached by the monitor's ERET, and the monitor chooses the
state through SPSR.T.  Get the two out of agreement and the guest dies
on its first instruction with an undefined-instruction exception, which
looks exactly like a bad entry address and sends the reader to the
loader instead of to the ERET.

WHAT THE MONITOR INHERITS is enumerated at the #ifndef, next to the code
it replaces rather than in a document, because that is where somebody
adding a third board will be looking.  This board's EL2 block is
considerably larger than the model's, and each item on the list is
something a guest at EL1 provably cannot do rather than something it
merely does not: CNTFRQ is writable only at the highest implemented
exception level and reads zero out of reset; HCPTR.TCP10/TCP11 reset
set, trapping every EL1 floating-point access; HSCTLR.TE is an EL2
register (SCTLR.TE is EL1's, and el1_entry still clears it below);
ICC_HSRE.SRE makes every other ICC_* and ICH_* register exist at all;
the low-latency peripheral port enables reset to zero and an EL1 write
to that register traps to EL2; and the TCM enables are per-core with
ENABLEEL2 SILENTLY IGNORED from EL1 -- measured on both BTCM and CTCM,
the base took and bit 0 took while bit 1 stayed clear.

CNTHCTL.PL1PCTEN and PL1PCEN are the deliberate omission from that list,
and the note says why.  This path opens both, because a standalone
kernel owns the physical timer.  A monitor that TIME-partitions its
guests must not: a partition's physical time keeps running while it is
descheduled, so a guest reading it can observe that it was not running.
That is the monitor's decision rather than this file's, which is why the
list says what a guest cannot do rather than what a monitor should.

Verified both ways.  The three standalone images build and link
unchanged, and a kernel built with the option boots at EL1 on a
S32Z280-594EVB under an EL2 monitor, runs two threads through a queue
and a semaphore, and reports back -- with no other change to the kernel
or to its port.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Swept the stack-heavy measurement across placements, and qualified its result (#638)</title>
<updated>2026-08-18T12:51:49Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-08-18T12:51:49Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=ca62edd27ddf708f207d05a9478ca1f68203a13b'/>
<id>urn:sha1:ca62edd27ddf708f207d05a9478ca1f68203a13b</id>
<content type='text'>
#636 reported that a stack in BTCM gave a threefold tighter spread than DRAM0
for stack-heavy work. That measurement used a single code placement, which is
the methodology #631 and #633 exist to correct: the cache benchmark got an
alignment sweep and the interrupt handler got one, and this measurement never
did. It was noticed when #637 added two threads to the same image and the figure
moved -- both spreads came out near 6500 and the minima rose 15%.

The recursive body is now generated at four placements and all four are
measured, per placement, in one image.

    placement    BTCM min / spread     DRAM0 min / spread
    offset 0      41854 / 6850          42036 / 6880
    offset 16     48670 / 1946          48792 / 1978
    offset 32     42388 / 6914          42752 / 7018
    offset 48     48914 / 1860          49198 / 6786

Reproducible across runs to within a few hundred cycles.

Spread is dominated by code placement rather than by the memory holding the
stack. It ranges from 1860 to 6914 depending on where the body falls in a cache
line, and placement also moves the minimum by 17%, from 41854 to 49214. Against
that, the memory contributes a consistent but small advantage: BTCM's minimum is
lower at all four placements, by 0.4% to 0.9%.

BTCM's spread beats DRAM0's decisively at one placement of the four, offset 48,
at 1860 against 6786. At the other three the two are within 2% of each other.
So the effect #636 reported is real where it occurs and is not a property of the
part: quoting it as one invited the reader to expect it everywhere.

#636's claim should be read as qualified by this. A stack in BTCM buys a small
consistent improvement in the best case and a large improvement in spread at
some code placements and not others. Anyone building a determinism argument on
it needs the placement sweep in the loop, not a single figure.

The pad nops that displace each placement execute on every recursion level
rather than once, so each placement carries a slightly different constant cost,
about 0.6% at the widest. That cancels in the BTCM against DRAM0 comparison,
which is made at the same placement, and does not affect spread within one.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Gave each thread its own MPU window, and made a violation fault (#637)</title>
<updated>2026-08-17T21:59:12Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-08-17T21:59:12Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=1ef49338e93895e50ed4f5196a77eed9ca8a5103'/>
<id>urn:sha1:1ef49338e93895e50ed4f5196a77eed9ca8a5103</id>
<content type='text'>
First step towards a ThreadX module port for this core: establish that PMSAv8-R
regions can be switched per thread on this part, what that costs, and that a
violation actually faults. Those are the questions worth answering before
writing a module manager on top of them.

Two threads each own a 4 KB window at the top of DRAM2. The windows are carved
out of the broad data region in mpu.c, because isolation is only meaningful in
memory no other region already covers -- every other region in that map is a
wide RW window, so a private buffer inside one of them would be reachable by
every thread whatever else was programmed.

Each thread writes its own window, which must succeed, and then reaches for the
other thread's, which must fault. The second half is the part that matters: a
test that only shows a thread reaching its own memory would pass just as well
with no protection at all.

Measured on the S32Z280-594EVB, reproducible across three runs:

    thread 0 window 0x3187E000  own: reachable  other: faulted
    thread 1 window 0x3187F000  own: reachable  other: faulted
    region switch cost: 562 to 604 cycles

The cost is worth noting for the module port to come. A context switch on this
part is about 1400 cycles, so switching one region adds roughly 40% to it, and
most of that is the dsb and isb rather than the register writes. A module switch
programming several regions should therefore batch the barriers once at the end
rather than per region.

Scope, stated plainly. The window is applied by the thread calling
thread_mpu_activate, not by the scheduler. The port's scheduler does call
_tx_execution_thread_enter under TX_ENABLE_EXECUTION_CHANGE_NOTIFY, which would
make it automatic, but that macro is read by port assembly compiled into the
shared threadx library, so enabling it would oblige all nine example targets in
this port to supply the four execution hooks. A ThreadX module port carries its
own copies of the port assembly for exactly that reason, and that is where the
switch belongs. There is no user mode, no syscall boundary and no loader here.

The fault is survivable the same way the boot probes make it survivable:
fault_expected tells the data abort handler to record the violation and resume
after the faulting access. That works in thread context because the handler
returns where it came from rather than to a fixed recovery point.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Measured stack-heavy work against the memory holding the stack (#636)</title>
<updated>2026-08-17T21:26:08Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-08-17T21:26:08Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=f535a4ec67456b9ba0cd8ecda3dfbf08894c17b3'/>
<id>urn:sha1:f535a4ec67456b9ba0cd8ecda3dfbf08894c17b3</id>
<content type='text'>
#635 found BTCM worth about 7.4% on a context switch with no determinism
advantage, and said why: a switch saves sixteen registers, roughly one cache
line, so the stack's cache state has almost nothing to contribute. It named the
interesting case as work with a large stack working set, said it had not been
measured, and said it should not be assumed. This measures it, and the answer
inverts the earlier one.

deep_touch recurses 24 frames, writing a frame on the way down and reading it on
the way up, so the working set is the whole descent. The cache is cleaned and
invalidated before each sample, so every descent starts cold. Two threads, one
stack in BTCM and one in DRAM0, no partner threads and no relinquish: the timed
region is entirely within one thread.

Reproducible across runs:

                      min      mean      max     spread
    stack in BTCM   42868     43031    44890       2020
    stack in DRAM0  42982     43291    49842       6860

The mean is the same to within 0.6%. The worst case is 10% lower for BTCM and
the spread is 3.4 times tighter. No sample in either configuration exceeded
twice the minimum, so these maxima are the workload rather than a timer tick --
which is the mistake that produced a false jitter result in #635 and is why the
count of interrupted samples is printed.

Put beside #635 the two measurements say opposite things and both are true.
For a context switch, a small footprint touched every time, BTCM buys throughput
and no determinism. For stack-heavy work, a large footprint touched once, it
buys determinism and almost no throughput.

The reason is that this workload is compute bound at the optimisation level this
BSP builds at: 43000 cycles for 24 frames is dominated by call and loop overhead,
so line fills are a few percent of the total and barely move the mean. What they
do is vary, and that variance is what a bank with no cache in the path removes.

So the determinism argument for TCM holds here, but it is worth 10% of worst case
and a threefold narrowing of spread, not an order of magnitude. Anyone citing
this in a safety argument should cite those numbers and not a larger claim.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Measured context-switch cost against the memory holding the stack (#635)</title>
<updated>2026-08-17T21:08:29Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-08-17T21:08:29Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=367d91880b928a250c46c5b28486b8d932bf1e50'/>
<id>urn:sha1:367d91880b928a250c46c5b28486b8d932bf1e50</id>
<content type='text'>
#634 placed a thread stack in BTCM and deliberately claimed no timing benefit,
because none had been measured. This measures it.

Two pairs of equal-priority threads hand control back and forth with
tx_thread_relinquish. One pair has both stacks in BTCM, the other in DRAM0, and
the measuring thread of each pair times the round trip in PMU cycles. Both pairs
run in one image from one copy of the measuring code, which is what makes the
comparison safe: the alignment trap that invalidated earlier work here bites
when two builds with different layouts are compared, and a code shift moves both
pairs equally.

Reproducible to the cycle across runs:

                        min    mean    max
    BTCM stacks        1370    1379   1402
    DRAM0 stacks       1476    1480   1508

BTCM is about 7.4% faster, or 110 cycles on a round trip of two switches.

Three findings that bound the claim, and the last one deflates it.

The figure holds whether the cache is warm or cold. Cleaning and invalidating
the data cache before every timed switch costs both configurations about 40
cycles and leaves the gap at 7.4%: warm it is 1334 against 1440, cold 1370
against 1476. So the advantage comes from BTCM's zero wait states, not from
avoiding cache misses.

That is because a context switch touches almost no stack -- sixteen registers,
about one cache line -- so the stack's cache state has little to contribute
either way. TCM should matter much more for threads with deep call chains or
large locals, where the stack working set is big enough for cache state to
dominate. That is not measured here and should not be assumed.

There is no determinism benefit visible in this test. Excluding preempted
samples, jitter is 32 cycles for BTCM and 28 to 34 for DRAM0 -- comparable, not
better. A first version of this measurement appeared to show BTCM with 16 times
less jitter, and that was wrong: max was reporting whichever pair a timer tick
had landed on. Across three runs the outlier appeared in the BTCM pair once and
the DRAM0 pair twice. Samples past 2000 cycles are now counted separately and
excluded from min, mean and max alike, and the count is printed so the reader
can see how many there were.

Also tried and discarded: loading the partner thread with a cache walk to create
pressure. The timed round trip includes the partner, so the walk dominated every
sample and put all 256 past the outlier threshold. The per-sample flush replaced
it and sits outside the timestamps.

The demo also starts the PMU cycle counter, which bsp_boot.c does for the probe
image and this image never ran. Without it every reading would have been zero,
which reads as a free context switch rather than as a dead counter.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Enabled BTCM, measured it, and put a ThreadX thread stack in it (#634)</title>
<updated>2026-08-17T20:33:55Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-08-17T20:33:55Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=62e966f6bf0f4f56c7b8e40b672a0d7374aa56f5'/>
<id>urn:sha1:62e966f6bf0f4f56c7b8e40b672a0d7374aa56f5</id>
<content type='text'>
* Enabled BTCM and measured what it offers as a data store

BTCM was disabled because of a regression that turned out not to exist; the
claim was retracted in the previous commit. It is enabled now, and this
measures why that is worth doing: 16 KB at zero wait states, where ATCM has
one, and no cache in the path at all.

Enabling it needs three things, all of which existed for ATCM already: the
region register write at EL2, an MPU region, and an ECC preload before any read
(TRM 6.2.2). BTCM accepts 32-bit stores where ATCM needs 64-bit, which
tcm_preload already handles.

The cache benchmark now sweeps three memories rather than one, four loop
alignments each. At the alignments where the loop is not instruction-fetch
bound:

    memory              cold (uncached)   warm (cached)   gain
    DRAM2 half-speed            857,540         651,436   24.0%
    DRAM0 full-speed            797,824         651,297   18.3%
    BTCM  zero wait             694,689         651,369    6.2%

Three things follow.

Warm times are identical across all three memories, within 0.02%. Once the data
cache is working the backing store barely matters, because the working set fits
in it.

Cold times rank as the reference manual predicts: BTCM fastest, then DRAM0,
then DRAM2 at half the core frequency (S32Z2 RM 6.3.6).

BTCM still shows a 6.2% gain when the caches are enabled, and that cannot be
the data cache, because an enabled TCM is Non-cacheable Non-shareable Normal
memory whatever the MPU says. It is the instruction cache on the timing loop.
This probe has always measured both caches together; three memories side by
side is what makes that visible.

The number that matters for placing data in BTCM: uncached BTCM is within 6.6%
of the best cached case, where uncached DRAM0 is 22% off it. Data in BTCM runs
at close to cache-hit speed with no cache to miss, which is the determinism
argument stated as a measurement rather than an assertion.

DRAM2's sweep is unchanged with BTCM enabled, 0 and 0 and 240 and 240, which
independently confirms the retraction.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;

* Put a ThreadX thread stack in BTCM

The code side of TCM was done in #630; this is the data side. One of the demo's
three thread stacks now lives in BTCM and the other two stay in DRAM0, so a run
exercises both paths and a mistake in either shows up.

link.lds gains a BTCM region and a .btcm_bss NOLOAD section, so a stack is an
ordinary C array with a section attribute and the linker checks it fits, rather
than a hardcoded address that silently overflows the bank.

entry.S preloads the whole bank at EL2, and that is not optional. ECC is enabled
on this part, so a TCM location must be written before it can be read (TRM
6.2.2), and a stack is read before the program writes it -- the first context
restore pops what tx_thread_create built into it. The preload has to happen
before any C runs, because the demo images do not run bsp_boot.c, which is where
the ATCM preload lives. 32-bit stores suffice for BTCM where ATCM needs 64-bit.

Why BTCM for a stack: 16 KB at zero wait states where ATCM has one, and never
cached whatever the MPU says about it. Measured in the previous commit, uncached
BTCM comes within 6.6% of the best cached case while uncached DRAM0 is 22% off
it, so stack access runs at close to cache-hit speed without depending on a line
being resident. That is the property a determinism argument needs.

What this commit does not claim: no thread-level timing improvement has been
measured. The case for BTCM here rests on the memory characterisation and on
removing the cache from the path, not on a measured context-switch figure. That
measurement is worth doing and has not been done.

Verified on the S32Z280-594EVB. The demo reports its stack addresses so the
placement is visible rather than implied -- sleeper at 0x30100000 in BTCM,
spinner and judge in DRAM0 -- and passes with 100 ticks, 20 sleeper wakeups and
20 preemptions, so a real thread schedules, preempts and context-switches on a
tightly-coupled-memory stack. The boot image still passes six of six probes.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>Retracted the claim that a second TCM bank costs the data cache (#633)</title>
<updated>2026-08-17T17:46:33Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-08-17T17:46:33Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=35de56853c24fac04d15b7b99f5d3c1ec369d9f9'/>
<id>urn:sha1:35de56853c24fac04d15b7b99f5d3c1ec369d9f9</id>
<content type='text'>
entry.S and readme_s32z280.txt both stated that enabling any second TCM bank
removes all measurable data-cache benefit on this part, and gave five
configurations as evidence: ATCM alone at a 24% cache gain, four combinations
involving a second bank at none. Both concluded the cause was not a particular
bank, not its address and not the ECC preload, but enabling a second bank at
all. Both cited the Cortex-R52 and S32Z2 errata as not covering it and offered
a shared RAM pool between the LLC and the TCMs as an explanation. A defect
report went to NXP on that basis.

It was an artifact of the benchmark. That benchmark was bimodal with respect to
where its timing loop fell inside a 64-byte cache line, reporting either 24% or
nothing at all for identical silicon, and every one of those five
configurations was an edit to entry.S, so every one shifted the code that
followed and moved the loop between modes. Adding two nop instructions
reproduces the "second bank" figure exactly, to the digit. The report to NXP
has been withdrawn.

Re-measured with the alignment sweep added in #631, one bank and two are
indistinguishable:

    loop offset in line      ATCM only      ATCM + CTCM
    0                        gain 0         gain 0
    16                       gain 0         gain 0
    32                       gain 240/1000  gain 240/1000
    48                       gain 240/1000  gain 240/1000

So enabling a second bank costs nothing measurable. The banks stay disabled,
but for the ordinary reason that nothing in this example uses them, and both
texts now say that instead. Enabling one is a single line, with the ECC preload
before any read (TRM 6.2.2) and an MPU region as the only prerequisites, both
already handled for ATCM.

The readme also now states the general point, which outlasts the TCM detail: a
single-figure timing result from this example cannot be compared across builds
unless the timed loop's alignment is controlled, because almost any change
shifts code.

Comments and documentation only; no generated code changes. Verified on the
board regardless, since entry.S was touched: six of six probes pass and the
sweep is unchanged.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;</content>
</entry>
</feed>
