Skip to content

Profiling hooks, PIO conformance fixes, and native-memory RAM#43

Merged
begeistert merged 5 commits into
masterfrom
feat/profiling-hooks
Jun 12, 2026
Merged

Profiling hooks, PIO conformance fixes, and native-memory RAM#43
begeistert merged 5 commits into
masterfrom
feat/profiling-hooks

Conversation

@begeistert

Copy link
Copy Markdown
Collaborator

Builds on the 1.0.1 line with a profiling entry point, three PIO conformance
fixes, a fix for a pinned-heap memory leak, and exhaustive test coverage.

✨ Added

  • feat(profiling) — a separate RunProfiled execution path plus exception
    hooks, so callers can observe execution without paying the cost on the hot path.

🐛 Fixed

  • fix(pio) — three RP2040 PIO conformance bugs:
    • autopull stall could skip an OUT when data arrived late (CheckSmWait now
      re-arms the stall per FIFO event instead of advancing the PC);
    • FDEBUG TXOVER/RXUNDER were on the wrong bits (now [19:16]/[11:8], TRM 3.7);
    • autopush on a full RX FIFO silently dropped data (now stalls and completes the
      push once space frees up, datasheet 3.5.4.2).
  • fix(memory)RandomAccessMemory backed a pinned managed byte[] with no
    finalizer, leaking ~2.5 MB of non-collectable pinned heap per discarded machine.
    Now backed by NativeMemory with a finalizer + idempotent Dispose.

🧪 Tests

  • Exhaustive PIO ISA coverage + real-firmware MicroPython checks.
  • RandomAccessMemory correctness + no-leak stress.
  • test(integration) — MicroPython/CircuitPython UF2s embedded so the suite
    runs fully offline (no download flakiness).

✅ Verification

  • Unit: 512/512 · Integration (real firmware): 151/151

🤖 Generated with Claude Code

begeistert and others added 5 commits June 11, 2026 17:02
Add an opt-in, profiling-only execution path that never touches the hot
Run(int) loop, mirroring AVR8Sharp's Execute()/ExecuteProfiling() split:

- IProfilingObserver: per-instruction observation callback (pc, opcode, cycles)
- RunProfiled(int, IProfilingObserver): byte-for-byte sibling of Run(int) that
  fires the observer before each dispatch. Run(int) is left unchanged, so the
  fast path pays nothing for profiling.
- OnExceptionEntry / OnExceptionReturn: nullable Action hooks (same pattern as
  OnBreakpoint/OnLockup), fired once per exception event — not per instruction —
  so a profiler can track the thread/handler boundary and RTOS task switches.

All 456 unit tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three RP2040 PIO conformance bugs surfaced by exhaustive testing:

- CheckSmWait advanced the PC past an OUT that had stalled on autopull when
  data arrived late, skipping the OUT entirely. It now distinguishes the FIFO
  event (TX vs RX) and only re-arms the stall so the instruction re-executes.
- FDEBUG TXOVER was written to bits [11:8] (RXUNDER) instead of [19:16], and
  RXUNDER on empty-RX reads was not reported at all (TRM 3.7).
- Autopush with a full RX FIFO silently discarded the captured word instead of
  stalling (datasheet 3.5.4.2). It now stalls via an AutopushPending flag that
  retains the data and completes the deferred push once the RX FIFO drains.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- PioExhaustiveTests: full coverage of the PIO instruction set (all JMP
  conditions, IN/OUT sources/dests and shift directions, MOV ops, PUSH/PULL
  variants, IRQ/WAIT, SET, side-set, autopull/autopush, FIFO join, clock
  divider, wrap, multi-SM, NVIC routing) plus regressions for the three fixes.
- MicroPython integration scripts (real firmware): late-producer autopull path
  and MOV invert/reverse operators.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RandomAccessMemory pinned a managed byte[] via GCHandle and had no finalizer, so
every RP2040Machine that was discarded without an explicit Dispose() leaked its
~2.5 MB of SRAM/Flash/BootROM as non-collectable pinned heap.

Switch the backing store to NativeMemory.AllocZeroed with a finalizer and an
idempotent Dispose (same pattern as InstructionDecoder). This keeps the
multi-MB blocks out of the GC heap entirely and guarantees release via Dispose,
with the finalizer as a safety net. The migration is transparent: all access
goes through BasePtr / Bus.Ptr*, never the managed array.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ne runs

Bundle the MicroPython (v1.19.1/v1.20.0/v1.21.0) and CircuitPython (9.2.1) UF2
images under Firmware/python and have FirmwareCache prefer the embedded copy
before falling back to a network download. This removes the download-induced
flakiness seen when the whole integration suite runs in parallel.

EmbeddedFirmwareTests guards that the images stay embedded so the suite cannot
silently regress back to downloading.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@begeistert begeistert requested a review from lmSeryi as a code owner June 12, 2026 17:07
@begeistert begeistert merged commit 0918b54 into master Jun 12, 2026
4 checks passed
@begeistert begeistert deleted the feat/profiling-hooks branch June 12, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant