Uh oh!
There was an error while loading. Please reload this page.
Added generic BSP framework and PolarFire SoC Icicle Kit target - #49
Conversation
…, and port collision fix
…ration and MMUART1 interrupt routing
Addressed the outstanding review items on the PolarFire SoC target. PLIC: plic.h programmed context 2, which is the supervisor-mode context for u54_1 on PolarFire SoC; the machine-mode context for that hart is context 1. Writing the supervisor context is silently accepted by the PLIC but leaves the machine-mode enable bitmap clear, so MEIP never asserts and MMUART1 interrupts could not be delivered. Threshold/claim move to 0x0C201000/0x0C201004 and the enable word to 0x0C002088. The context and enable-word offsets are now derived from the source ID rather than hardcoded. Self-tests: run_startup_self_tests() printed "All startup verification tests PASSED!" unconditionally, and test_renode.py grepped for exactly that string, so a failing sub-test still produced a green build. Results now feed a failure counter that decides the summary line, and the harness fails on any "[-] FAIL:". Renode harness: the exit code considered only ticks and the alarm, discarding the self-test and PLIC-RX flags it computed. All four assertions now gate the result, and the harness injects a byte into MMUART1 so the PLIC path is actually exercised instead of only having its registers inspected. The timer catch-up self-test no longer writes mtime. That register is the platform-wide monotonic counter shared by every hart, and this demo is meant to be copied. Only the per-hart mtimecmp is staged into the past, with the expected result bracketed by mtime sampled either side of hwtimer_ack(). Also: - Hardened _sbrk() in templates/target, which is the copy-me template: bounds check against BSP_RAM_END, reject underflow and pointer overflow, return (void *)-1 with errno, and take ptrdiff_t so it stays correct on 64-bit. - Implemented __malloc_lock/__malloc_unlock instead of leaving them empty, so the newlib arena is genuinely serialised rather than only appearing to be. - Gave the tick source one owner: _tx_initialize_low_level calls hwtimer_init, board_init handles board peripherals, so board_init no longer runs twice. - Pinned Renode to 1.16.1 and checksum-verified both CI downloads. - Updated polarfire_demo.robot, which asserted on telemetry strings the demo no longer emits, and added an RX interrupt case. - Derived the demo sleep intervals from TX_TIMER_TICKS_PER_SECOND. - Corrected the architecture.md tree and normalised the licence URL to the form used in AGENTS.md. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous self-test staged mtimecmp eight ticks behind by subtracting from mtime. Renode starts mtime near zero, so that subtraction underflowed to 2^64-79900 and the test failed itself in CI. The production clamp was never wrong; the test fed it a value real code cannot produce. Extracted the catch-up decision into hwtimer_next_cmp(), a pure function of the current comparand and mtime, and left hwtimer_ack() as a thin wrapper. The test now covers both branches with synthetic values and touches no CLINT register at all, which also removes the last reason for the demo to write timer state. Replaced the TX_TIMER_TICKS_PER_SECOND fallback in hwtimer.h with BSP_TICK_RATE_HZ in board_config.h. The BSP does not see the ThreadX headers, so that fallback silently applied whenever the two disagreed; main.c sees both and now carries a C99 compile-time check that they match. The Renode harness no longer stops at the first failing self-test, so a single failure reports the state of every other assertion instead of hiding it. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…xercised The RX assertion added in the previous commit never fired in CI. Renode does not read its monitor from stdin (it logs "Monitor available in telnet mode on port 1234"), so the byte the harness wrote was silently discarded and the PLIC path still went untested. Added renode/polarfire_ci.resc, which steps through fixed virtual-time intervals with emulation RunFor, injects the byte itself via WriteChar, and quits. The run is reproducible and terminates on its own rather than depending on wall clock. It duplicates the machine setup instead of including polarfire_demo.resc because Renode expands $ORIGIN only in variable assignment, so an included script cannot be located relative to the file including it; both "include @$ORIGIN/..." and a bare relative include hang the process rather than reporting an error. polarfire_demo.resc is left free-running for interactive use. Verified locally against Renode 1.16.1, both directions: context 1 -> [Console RX] PLIC IRQ 91 handled: byte 'X' ... harness exit 0 context 2 -> no RX line harness exit 1 Both builds print an identical "[+] PASS: PLIC Hart 1 (IRQ 91 prio=1 en=0x08000000 thresh=0 mie=0x800)" self-test line, which is the point: register readback cannot separate a correct context from an incorrect one, and only a delivered interrupt can. Also added timeout-minutes to both CI jobs as a backstop, and corrected the target README, whose expected-output block still showed telemetry strings the demo stopped emitting. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Adds a Microchip PolarFire SoC Icicle Kit target for ThreadX, built on a new
reusable BSP framework, with a Renode-based CI pipeline that runs the demo in
emulation on every push.
What the contribution adds
Thanks to @AmmarOkla12772 for the target and the framework behind it:
source, PLIC configuration for Hart 1 (u54_1), and a ThreadX demo exercising
threads, queues, and timers.
board_init,hwtimer, and console behind aboard-agnostic interface with a
board_config.hper target, plus atemplates/targetskeleton for new ports.test_renode.pyharness and apolarfire_demo.robotsuite._sbrkbounds, timer catch-up, andqueue integrity, so the demo verifies its own platform layer at startup rather
than trusting it.
mtvecinitialisation, synchronous trap dispatchseparated from interrupt context save, deliberate timeout and trap hooks for
testing, and a port collision fix.
Review follow-ups
The remaining commits address the outstanding review items. Three of them are
correctness fixes where the code looked right and the tests agreed with it.
PLIC machine-mode context
plic.hprogrammed context 2, the supervisor-mode context for u54_1; themachine-mode context for that hart is context 1. The PLIC silently accepts a
write to the supervisor context, but the machine-mode enable bitmap stays clear,
so
MEIPnever asserts and MMUART1 interrupts were never delivered.Threshold/claim move to
0x0C201000/0x0C201004and the enable word to0x0C002088. Both the context and the enable-word offset are now derived fromthe source ID instead of hardcoded.
Self-tests could not fail the build
run_startup_self_tests()printedAll startup verification tests PASSED!unconditionally, and
test_renode.pygrepped for exactly that string — so afailing sub-test still produced a green build. Results now feed a failure counter
that decides the summary line, and the harness fails on any
[-] FAIL:.The harness exit code also considered only ticks and the alarm, discarding the
self-test and PLIC-RX flags it had already computed. All four assertions now gate
the result, and a failing self-test no longer stops the run — one failure reports
the state of every other assertion instead of hiding it.
The PLIC path was never actually exercised
Register readback cannot tell a correct PLIC context from an incorrect one; only
a delivered interrupt can. The harness wrote a byte to MMUART1 to trigger one,
but Renode does not read its monitor from stdin (it logs "Monitor available in
telnet mode on port 1234"), so the byte was discarded and the RX assertion never
fired.
renode/polarfire_ci.rescnow drives the run: fixed virtual-time steps viaemulation RunFor, the byte injected withWriteChar, thenquit. The run isreproducible and terminates on its own instead of depending on wall clock. It
duplicates the machine setup rather than including
polarfire_demo.resc, becauseRenode expands
$ORIGINonly in variable assignment — an included script cannotbe located relative to its includer, and both
include @$ORIGIN/...and a barerelative include hang the process rather than reporting an error.
polarfire_demo.rescstays free-running for interactive use.Verified locally against Renode 1.16.1, both directions:
[Console RX] PLIC IRQ 91 handled: byte 'X'Both builds print an identical
[+] PASS: PLIC Hart 1 (IRQ 91 prio=1 en=0x08000000 thresh=0 mie=0x800)line, which is the point.Timer catch-up self-test
The self-test staged
mtimecmpeight ticks behind by subtracting frommtime.Renode starts
mtimenear zero, so the subtraction underflowed to2^64-79900and the test failed itself in CI. The production clamp was never wrong; the test
fed it a value real code cannot produce.
The catch-up decision is now
hwtimer_next_cmp(), a pure function of the currentcomparand and
mtime, withhwtimer_ack()a thin wrapper. The test covers bothbranches with synthetic values and touches no CLINT register — so the demo no
longer writes
mtimeat all, which matters because that register is theplatform-wide monotonic counter shared by every hart and this code is meant to be
copied.
Also
_sbrk()intemplates/target— the copy-me template: bounds checkagainst
BSP_RAM_END, reject underflow and pointer overflow, return(void *)-1witherrno, and takeptrdiff_tso it stays correct on 64-bit.__malloc_lock/__malloc_unlockinstead of leaving them empty, sothe newlib arena is genuinely serialised rather than only appearing to be.
_tx_initialize_low_levelcallshwtimer_init,board_inithandles board peripherals — soboard_initnolonger runs twice.
TX_TIMER_TICKS_PER_SECONDfallback inhwtimer.hwithBSP_TICK_RATE_HZinboard_config.h. The BSP does not see the ThreadXheaders, so the fallback silently applied whenever the two disagreed;
main.csees both and now carries a C99 compile-time check that they match.
TX_TIMER_TICKS_PER_SECOND.timeout-minutesto both jobs as a backstop.polarfire_demo.robot, which asserted on telemetry strings the demo nolonger emits, and added an RX interrupt case; corrected the target README,
whose expected-output block showed the same stale strings.
architecture.mdtree and normalised the licence URL to the formused in
AGENTS.md.Co-authored-by: Ammar Okla ammargawkla@gmail.com
Co-authored-by: Frédéric Desbiens frederic.desbiens@eclipse-foundation.org