Release 1.0.1-beta.2: BUSL-1.1 packages (Wireless + nanoFramework TestKit) + CI publish wiring#45
Merged
Merged
Conversation
Timer INTR de-asserts NVIC lines on clear, BUSCTRL PERFSEL defaults, DMA DREQ resume, IoBank0 GPIO_COUNT-bounded input + external-input seam, PIO IRQ caching + TX/RX consume hooks, SIO OnGpioChanged, plus the CircuitPython FS helper. Enables real MicroPython/CircuitPython on the emulated Pico W. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d completions
The CDC host fabricated zero-length bulk-OUT completions on every empty
arm, a re-arm busy-loop that under load (Wi-Fi association) delivered a
completion after TinyUSB deactivated the endpoint -> hw_endpoint_xfer_continue
panic -> HardFault/lockup ('USB-deaf after associate'). Now the OUT endpoint
stays armed and is fulfilled when bytes arrive (matching the RP2350 host).
EP_ABORT also drops any deferred completion for the aborted buffer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A firmware panic() spins on BKPT; the capturing handler appended each hit unboundedly (2 GB List -> OutOfMemoryException). Cap at 1<<16; the panic is fully observable from the first entries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pin-level gSPI slave, SDPCM/WLC ioctls, firmware download, VirtualNet
(DHCP/ARP/TCP) + VirtualSwitch, and an HCI controller with BtSharedBus +
VirtualBleRadio/BleLink so real btstack runs over a virtual BLE air.
Two precision fixes so the result is independent of host time-slicing:
- GSpiSlave.SetInterrupt does not drive DATA mid-transaction (the host-wake
line, shared with the gSPI DATA bits); EndTransaction applies it when idle.
- read-response trailing fill is 0x00, not the host-wake 0xFF — an over-clocked
register read under heavy cross-device traffic otherwise returns 0xFF, which
the cyw43 driver rejects ('cyw43_kso_set: failed').
- HciController exposes a public cross-assembly bridging seam (DeliverAdvReport/
OpenExternalLink/...) so a controller can link to a peer in another assembly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pico W brings up WLAN and scans a virtual AP; BLE reaches 'BLE True' with a real HCI bring-up over the emulated CYW43439. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add EmuStrict, an opt-in sink (EMU_STRICT=1) that records the places the emulator would otherwise return 0 / no-op / fall back to a benign default for something it does not actually model. Hooked at the systematic choke points: - ApbBridge: access to an unmapped APB peripheral - BusInterconnect: read/write to an unmapped region - PioPeripheral: reserved MOV/IN instruction encodings (e.g. the WAIT `_ => true` class that silently "never waits") Off by default (zero cost) and behaviour-neutral (NoteRet returns the same fallback); writes an aggregated report to EMU_STRICT_OUT on flush. Turns the "we never noticed the PIO bug" class of silent inaccuracy into a visible list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture the guest's SoftAP SSID from the bsscfg:ssid iovar (Sdpcm.ApSsid) so the virtual air can advertise a guest-AP to other stations' scans. Mark clmload_status (0 = DLOAD_STATUS_SUCCESS) and the empty event/mcast lists as intentionally modelled, and route every other GET_VAR/SET_VAR iovar through EmuStrict so the unmodelled cyw43 surface (e.g. the ignored clmload regulatory blob) is recorded rather than silently returning bogus zeros. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
HIL comparison against a real RP2040 B2 Pico (picotool save -r 0x0 0x4000) showed the emulator
embedded only the B1 bootrom (version 2) while the chip ships B2 (version 3) — ~87.5% of bytes differ.
- Embed bootrom_b2.bin (dumped from real B2 silicon) alongside bootrom_b1.bin.
- Add RP2040BootromRevision { B1, B2 } and a RP2040Machine(bootrom:) parameter, default B1.
- LoadRealBootRom now resolves the flash-helper functions (connect_internal_flash, flash_exit_xip,
flash_flush_cache, flash_enter_cmd_xip) to patch as BX LR from each revision's ROM function table
instead of hardcoding B1 addresses — the addresses differ on B2 (0x2490 vs 0x24A0, …). Verified the
resolver reproduces the historical B1 addresses exactly, so B1 is byte-identical to before.
- BootromRevisionTests covers both revisions (version byte + patched addresses).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fk7wVMze7VKTsQqy2JkgvK
Same MicroPython firmware runs in the RP2040Sharp emulator and on a real Pico (1 / 1 W); both execute the same deterministic one-liner over the REPL and the printed result is compared bit-for-bit. Opt-in (RP2040_HIL=1); drives the board over USB-CDC (flashing from BOOTSEL via picotool when needed) and skips cleanly when the env var, firmware UF2 or board are absent. Adds System.IO.Ports for serial. Verified identical on emulator vs a real RP2040 B2 Pico 1 W. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fk7wVMze7VKTsQqy2JkgvK
Verified-against-source draft to file upstream: adc.ts activeChannel setter masks the channel with CS_AINSEL_SHIFT (12) instead of CS_AINSEL_MASK (0x7), corrupting AINSEL and breaking round-robin. README documents the verification method and the ~19 other candidates that were investigated and dismissed (rp2040js is correct; they were the port's own fixes or convention differences). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fk7wVMze7VKTsQqy2JkgvK
The behavioral HIL differential (HilDifferentialTests) talks to a real Pico over USB-CDC; that hardware-checking code is private and must not live in the repo. Removed from the tree and the System.IO.Ports dependency it needed. The emulator features it informed (B2 bootrom support and its unit tests) stay. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fk7wVMze7VKTsQqy2JkgvK
Adds OnTxPush/OnRxPull events to PioPeripheral (fired on firmware TXF write / RXF read), a PioProbe + FifoCapture in RP2040.TestKit, and AddPioProbe on RP2040TestSimulation — mirroring RP2350Sharp so the RP2040 emulator tier has PIO FIFO-capture parity.
…orks The SSI only enqueued an RX byte when a flash transaction was CS-asserted, and tracked the command via a CS-delimited buffer that was cleared on CS-assert. Firmware that drives the SSI the way the RP2040 bootrom / a nanoFramework CLR does — clocking dummy bytes with the flash deselected (rp_flash_exit_xip), and issuing the command byte just before the IO_QSPI/SER chip-select edge — never advanced its RXFLR-polling loops and spun forever. Now the RX FIFO fills on every DR0 write while the SSI is enabled (independent of chip-select), a separate RX frame tracks the command across read/deassert boundaries (so the command byte is preserved even when clocked before the CS edge), the RX FIFO is flushed at CS deassert, and the 0xEB Quad-I/O read returns real flash data. The CS-delimited write/erase path is unchanged. No regressions (full RP2040Sharp suite green); enables booting a nanoCLR + running a deployed C# app end-to-end on the emulator.
…apps A focused test kit (mirroring STM32.TestKit.NanoFramework) to run a deployed nanoFramework app on the RP2040Sharp emulator without hand-rolling the plumbing in every test: - NanoApp: assembles a deployment from a directory of .pe (mscorlib first, app last, libs between), reading each assembly's native-methods checksum from the NFMRK1 header (offset 20). - NanoFirmware: discovers nanoBooter*/nanoCLR* + an optional firmware.manifest.json by convention, and boots booter + nanoCLR + deployment at the RP2040 flash layout (0x14000 / 0xFC000). - Checksum guard: AssertCompatible() fails fast with NanoChecksumMismatchException when a .pe's native checksum drifts from what the firmware provides (the classic silent nanoFramework footgun).
…ymbol Adds a harness over the deployed-app boot that drives the emulator to points inside the running CLR, not just wall-clock slices: - NanoFirmware gains a symbols map (from the manifest) with ResolveSymbol/SymbolizePc. - NanoClrHarness.RunUntilNativeCall(symbol) runs the hook-aware execution path and watches every executed instruction's PC via the profiling observer, detecting the exact crossing into a native InternalCall (records LastReachedSymbol/Cycle). RunUntil(predicate) covers generic observable state. Crucially this uses the hook-aware path (RunProfiled), not per-instruction Cpu.Step() — Step bypasses the bootrom/flash native hooks the firmware needs to boot, so it diverges. All nanoFramework-specific; the pure RP2040.TestKit is untouched.
Adds a ClrLayout (in-RAM struct offsets of the nanoCLR build, from its DWARF) and a ClrInspector that walks the running CLR's memory to resolve a managed static field by name and read its value: g_CLR_RT_TypeSystem.m_assemblies -> match m_szName -> the .pe TypeDef/FieldDef metadata tables -> the FieldDef cross-reference slot -> the CLR_RT_HeapBlock that holds the value. NanoClrHarness gains ReadStaticInt32(asm,type,field) and RunUntilStatic(...,predicate) — drive the emulator until a managed variable reaches a value (resolving fresh each check, since the CLR may relocate the assembly/statics during load). The offsets are build-specific; ClrLayout.Default matches the vendored RP_PICO firmware (extract with gdb 'ptype /o' for another build).
- RP2040.NanoFramework.TestKit.SourceGen: a Roslyn generator that reads the app's built managed assembly (.exe) via System.Reflection.Metadata and emits a strongly-typed <App>Symbols class (Assembly + Methods.X + Fields.Y), so tests use generated constants instead of raw strings (typo => compile error). Ported from STM32Sharp's NanoSymbolsGenerator. - ClrInspector: resolve a static field by name across all types (optional type qualifier), and ReadStatic returns a HeapValue (dataType + raw) with AsInt32/AsUInt32/AsBoolean. - NanoClrHarness: ReadStatic/RunUntilStatic now take (assembly, field) and a HeapValue predicate.
Rounds out the STM32-style CLR inspection (same nanoCLR, so the same ClrLayout offsets):
- RunUntilManagedMethod("Assembly!Method"): watches CLR_RT_Thread::Execute_IL and matches the
running frame's method via MethodAt (m_call.m_assm.m_szName + m_call.m_target name) — the stack
frame is the call arg, checked in R0/R1. Pairs with the generated AppSymbols.Methods.X.
- ClrInspector.MethodAt(stackFrame), plus instance heap-object reads: ReadArrayLength /
ReadArrayInt32 over a managed array's CLR_RT_HeapBlock_Array header.
- NanoClrHarness.StaticArrayLength / ReadStaticArrayInt32 (a static int[] = a heap array reference).
- ClrLayout gains the MethodDef/StackFrame/array offsets (TBL_MethodDef=6, MD_Size=16, SF_CallAssm=44,
SF_CallTarget=48, OBJ_FieldsOff=12, ARR_NumElems=12, ARR_DataOff=20) — identical to the STM32 build.
…s structure - ReadStaticInt64: reads the cell's full 8 data bytes (low | high<<32). - Instance fields by name: TryResolveInstanceSlot (the type's iFields + the FieldDef cross-reference m_offset), and ReadInstance at obj + m_offset*HB_Size — m_offset already counts past the object header (the nanoCLR does res = Dereference(); res += m_offset), so NO extra OBJ_FieldsOff (that was an off-by-one). Harness ReadStaticInt64 / ReadInstance(Int32) (object held by a static ref field). - NanoSymbols generator now also emits a Types.<Type>.Name/.Fields.<Field> structure extracted from the project (all non-const fields per type), so instance fields are addressed by generated symbols.
Mirror of the RP2350Sharp change. On real RP2040 a PIO powers up clock-gated until firmware clears its RESETS bit (PIO0=10, PIO1=11); the emulator started everything out of reset, so PIO writes were no-ops on silicon yet 'worked' here. ResetsPeripheral now starts the PIO bits in reset + fires OnUnreset/OnReset, PioPeripheral gates Read/WriteWord on InReset, and the machine releases the block on the RESETS transition. Isolated unit tests keep InReset=false.
…mework TestKit) The MIT core (RP2040Sharp, RP2040Sharp.TestKit) was the only thing the publish workflow packed. Add the two specialized BUSL-1.1 packages to the release: - RP2040.Wireless — CYW43439 Wi-Fi + BLE virtualization (already BUSL-1.1). - RP2040Sharp.TestKit.NanoFramework — boot/assert deployed nanoFramework apps. Relicensed BUSL-1.1 (overrides the MIT default) and now bundles the NanoSymbols source generator as an analyzer plus a buildTransitive .targets that wires it up for NuGet consumers, mirroring the established STM32Sharp packaging pattern. Both pack with --no-build off the Release solution build, so the analyzer DLL and targets are present. CHANGELOG updated for 1.0.1-beta.2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cuts the
1.0.1-beta.2line. Brings the accumulated work sincev1.0.1-beta.1tomasterand, as the focus of this PR, packages and publishes the two specialized BUSL-1.1 packages alongside the MIT core.Packaging (focus of this PR)
RP2040Sharp.TestKit.NanoFramework→ BUSL-1.1. Overrides the MIT default fromDirectory.Build.props, adds package metadata, and now bundles the NanoSymbols source generator as an analyzer (analyzers/dotnet/cs) plus abuildTransitive.targetsfile that wires it up for NuGet consumers — mirroring the established STM32Sharp pattern.RP2040.Wireless(already BUSL-1.1) is now packed and published too.publish.ymlgains pack steps for both BUSL packages. They pack with--no-buildoff the Release solution build, so the analyzer DLL and targets are present in the.nupkg.Verified locally — both
.nupkgs carry<license type="expression">BUSL-1.1</license>, and the nanoFramework package contains:Also included since beta.1
CYW43439 Wi-Fi + BLE virtualization, B2 bootrom + revision selection, the nanoFramework CLR test harness (boot deployed apps, managed static/instance reads, run-until-managed-method, NanoSymbols generator), PIO FIFO probe + PIO RESET gating, SSI direct-command flash RX fix, push-model USB CDC OUT delivery, and emulator strict mode.
The MIT core (
RP2040Sharp,RP2040Sharp.TestKit) stays MIT. No breaking API changes.🤖 Generated with Claude Code