feat: rp2040js parity — GDB stub, dual-core fixes, I2C slave mode; remove unused USB MSC/HID#31
Merged
Merged
Conversation
Add all missing Thumb/Thumb-2 instructions required for general C/C++ program execution: Memory: - STR/STRB/STRH (imm5, SP-relative, register variants) - LDRB/LDRH (imm5, register variants) - LDRSB/LDRSH (sign-extend, register only) - STMIA with unconditional write-back Bit operations: - ROR (register), CLZ (Thumb-2 32-bit) - SXTB, SXTH, UXTB, UXTH (sign/zero extend) Control flow: - CBZ / CBNZ (compare-and-branch, mask 0xFB00) System: - CPSID/CPSIE (interrupt enable/disable) - WFI/WFE/SEV (wait/event hints) - BKPT (configurable OnBreakpoint callback) - SVC (triggers pending SVCall exception) Infrastructure: - Add interrupt state fields to Registers struct (VTOR, pending bitmaps, priority registers, WFI waiting flag) - Fix VTOR TODO in ExceptionEntry (read from Registers.VTOR) - Add CheckForInterrupts() with NoInlining (cold path) - Add interrupt check in Run() loop (predictable branch) - Add SetInterrupt/TriggerNmi/TriggerSysTick/TriggerPendSv helpers - Add exception number constants to CortexM0Plus Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add encoding helpers for ROR, SXTH, SXTB, UXTH, UXTB, CLZ (Thumb-2), CBZ, CBNZ, STR/STRB/STRH (imm/SP/reg), LDRB/LDRH/LDRSB/LDRSH, STMIA, BKPT, SVC, CPSIE, CPSID, WFI, WFE, SEV.
Cover BitOps (ROR, SXTH, SXTB, UXTH, UXTB, CLZ), FlowOps (CBZ, CBNZ), MemoryOps stores/loads (STR/STRB/STRH, LDRB/LDRH/LDRSB/LDRSH, STMIA, round-trips) and SystemOps (CPSID/CPSIE, WFI, WFE, SEV, BKPT, SVC). 256 tests passing.
Add ITickable interface and PpbPeripheral covering: - SysTick (CSR/RVR/CVR), fires TriggerSysTick() on rollover when TICKINT=1 - NVIC ISER/ICER/ISPR/ICPR and IPR0-IPR7 priority registers - SCB CPUID (0x410CC601), ICSR, VTOR, AIRCR, SHPR2/SHPR3 Update RP2040.Peripherals.csproj to reference RP2040.Core with AOT/unsafe.
GPIO OUT/OE with atomic SET/CLR/XOR, hardware divider (8-cycle latency, division-by-zero handling for signed/unsigned), and 32 spinlocks.
ApbBridge routes region 0x4 by 16 KiB slots (bits [21:14]). UartPeripheral: PL011 with OnByteTransmit callback and 32-byte RX FIFO. TimerPeripheral: 64-bit microsecond counter with 4 alarms, ITickable. IoBank0Peripheral: GPIO_STATUS/CTRL with FUNCSEL. GpioPin: typed view into SIO GPIO state for tests/assertions. RP2040Machine: assembles all peripherals, exposes Run()/LoadFlash()/Reset().
RP2040TestSimulation: WithBinary/WithFrequency/AddUart/AddGpio, Run*, RunUntil, RunToBreak, Step, Reset — all chainable. UartProbe: capture TX bytes, inject RX, Text/Lines/ByteCount. Assertions: CortexM0Assertions (HaveRegister/PC/SP/Cycles/flags), UartProbeAssertions (Contain/StartWith/ContainLine/HaveByteCount), GpioAssertions (BeHigh/BeLow/BeOutput/BeInput). PicoSimulation: pre-configured 125 MHz Pico board with UART0/1 probed.
- DmaPeripheral: 12 channels, synchronous transfer on CTRL_TRIG, chaining, MULTI_CHAN_TRIGGER, IRQ0/1 routing; mapped to bus region 0x5 - PwmPeripheral: 8 slices with 8.4 fixed-point clock divisor, wrap interrupt per slice (ITickable), CC A/B readout helpers - AdcPeripheral: 5 channels with injectable ReadChannel callback, START_ONCE trigger, 12-bit result, READY flag - RP2040Machine: wire DMA (Bus.MapDevice 0x5), PWM and ADC via ApbBridge, add PwmPeripheral to _tickables list
- SpiPeripheral: PL022 registers (SSPCR0/1, SSPDR, SSPSR, SSPCPSR, SSPIMSC), 8-entry TX/RX FIFOs, synchronous transfer via OnTransfer callback, InjectByte - I2cPeripheral: DesignWare DW_apb_i2c registers (IC_CON, IC_TAR, IC_DATA_CMD, IC_STATUS, FIFO levels), write/read callbacks, InjectByte for RX simulation - RP2040Machine: register SPI0/1 @ 0x4003C000/0x40040000, I2C0/1 @ 0x40044000/0x40048000 via ApbBridge
- PioStateMachine: ISR/OSR shift registers, TX/RX FIFOs, CLKDIV with 8.8 fixed-point fractional accumulator, EXECCTRL wrap/jmp-pin, SHIFTCTRL autopush/autopull thresholds - PioPeripheral: 2 PIO blocks (PIO0 @ 0x50200000, PIO1 @ 0x50300000), 32-word instruction memory, 4 state machines each; full instruction set: JMP (all 8 conditions), WAIT, IN, OUT, PUSH/PULL (block/non-block, autopush/autopull), MOV (with invert/bit-reverse), IRQ, SET - AhbBridge: 1 MB granularity sub-router for region 0x5 (index by address bits [27:20]); hosts DMA @ 0x50000000, PIO0/1 @ 0x50200000/0x50300000 - RP2040Machine: wire PIO0/1 via AhbBridge, add to _tickables list
Wrap NativeMemory.AllocZeroed and NativeMemory.Free with #if !BROWSER so the library compiles for net10.0-browser targets. On WASM, _pageTable and _maskTable fall back to pinned managed arrays (byte*[] / uint[]), which are supported by Blazor AOT since .NET 6. All pointer indexing and read/write paths are identical between targets.
- Add Directory.Build.props with Authors, RepositoryUrl, license, tags, README.md inclusion, and MinVer PackageReference (PrivateAssets=all) - Add PackageId + Description to RP2040.Core, RP2040.Peripherals, RP2040.TestKit
- New publish.yml: triggers on v* tags, runs tests then publishes to nuget.org using NUGET_API_KEY secret; --skip-duplicate prevents re-publish errors - test.yml: add Pack step at the end to verify packability on every PR/push
Eliminates vtable dispatch overhead on interface calls to these types, allowing the JIT to devirtualize IMemoryMappedDevice calls in the hot path.
… AhbBridge All RP2040 peripherals expose atomic-alias windows: +0x1000 = XOR, +0x2000 = SET, +0x3000 = CLR ApbBridge detects atomicType = (address >> 12) & 0x3 and performs the read-modify-write before passing the stripped offset to the device. AhbBridge does the same, stripping bits [13:12] before forwarding. Applies to WriteWord, WriteHalfWord, and WriteByte.
New peripherals (all IMemoryMappedDevice): - SysInfo (0x40000000): CHIP_ID=0x10029927, PLATFORM=ASIC - SysCfg (0x40004000): NMI masks, PROC_CONFIG, PROC_IN_SYNC_BYPASS - RESETS (0x4000C000): RESET/WDSEL/RESET_DONE — DONE = ~RESET & 0x1FFFFFF - Clocks (0x40008000): 8 clock domains; SELECTED always returns 1, FC0 returns 125 MHz - XOSC (0x40024000): always STABLE+ENABLED; dormancy is a no-op in simulation - PSM (0x40010000): DONE always returns ALL_BITS (all subsystems on) - Watchdog (0x40058000): SCRATCH0-7, TICK (RUNNING), CTRL; timer never fires - RTC (0x4005C000): full register set; time injected via SetDateTime() - PADS_BANK0/QSPI (0x4001C000/0x40020000): IE/OD/DRIVE/PUE/PDE pad control - BUSCTRL (0x40030000): BUS_PRIORITY, PERFSEL0-3 (counters return 0) - TBMAN (0x4006C000): PLATFORM=ASIC (allows firmware to detect ASIC vs FPGA) Firmware init sequences that busy-wait on RESET_DONE, Clocks SELECTED, XOSC STABLE, or PSM DONE will now complete without spinning forever.
…K_ST - CPUID (0x000): returns 0 (always Core0 in single-core simulation) - INTERP0/1 (0x080/0x0C0): complete RP2040 interpolator implementation — SHIFT, MASK_LSB/MSB, SIGNED, CROSS_INPUT/RESULT, ADD_RAW — PEEK_LANE0/1/FULL: read-only result computation — POP_LANE0/1/FULL: result + accumulator feedback — ACCUM0/1_ADD, BASE_1AND0 write operations - Multicore FIFO (0x050–0x058): FIFO_ST returns RDY=1 always; FIFO_WR discards silently (Core1 absent); FIFO_RD returns 0 - SPINLOCK_ST (0x05C): returns bitmask of currently claimed spinlocks - GPIO_HI_IN/OUT/OE with SET/CLR/XOR aliases for QSPI GPIO pads - Size extended to 0x10000 to cover spinlocks at 0x100–0x17C
Added to APB bus: SysInfo@0x40000000, SysCfg@0x40004000, Clocks@0x40008000, Resets@0x4000C000, Psm@0x40010000, PadsBank0@0x4001C000, PadsQspi@0x40020000, Xosc@0x40024000, Busctrl@0x40030000, Watchdog@0x40058000, Rtc@0x4005C000, Tbman@0x4006C000 All peripherals are exposed as public properties for test access. Existing peripherals (UART, SPI, I2C, ADC, PWM, Timer, DMA, PIO, IO_BANK0, PPB, SIO) retain their addresses unchanged.
- PioStateMachine: add SidesetCount/Base, InBase, SideEn, SidePinDir, StatusSel/N helpers - PioPeripheral: sideset application, FDEBUG tracking (TXOVER), dynamic FLEVEL, dynamic INTR (RX not empty / TX not full per SM + IRQ flags), CheckInterrupts→NVIC (PIO0_IRQ0=7..PIO1_IRQ1=10), MOV STATUS source=5 using EXECCTRL STATUS_SEL/N, WAIT PIN source=1 relative to IN_BASE - DmaPeripheral: ring buffer (RING_SIZE/RING_SEL), alias registers AL1/AL2/AL3 with _TRIG variants, TIMER0-3 storage, fix IRQ number (DMA_IRQ0=11, DMA_IRQ1=12) - AdcPeripheral: FCS/FIFO 4-deep, SHIFT, OVER/UNDER (write-clear), THRESH, dynamic INTR - New stubs: PllPeripheral (CS.LOCK=1), RoscPeripheral (STATUS.STABLE+ENABLED), VregPeripheral (1.1V default), SsiPeripheral (SR always ready), IoQspiPeripheral (6 QSPI pins) - RP2040Machine: register PLL_SYS@0x40028000, PLL_USB@0x4002C000, IO_QSPI@0x40018000, ROSC@0x40060000, VREG@0x40064000; expose Ssi property (0x18000000 in XIP region, not bus-mapped)
- PIO: delay cycles de instrucción (campo bits[12:8] menos sideset bits), DelayCounter en PioStateMachine; se descuenta antes de ejecutar siguiente instr - DMA: EN no se borra al completar transfer (hardware real lo mantiene), BSWAP (bit 22 CTRL), CHAN_ABORT (0x444), SNIFF_CTRL/DATA (0x434/0x438), N_CHANNELS (0x448), FIFO_LEVELS (0x440) - Timer: fix INTF force (almacena _intf, dispara NVIC), fix INTS incluye INTF, eliminadas constantes duplicadas LOCKED/SOURCE que solapaban INTR/INTE - SIO FIFO: TX FIFO depth-8 con WOF en overflow, RX FIFO con ROE en underflow, FIFO_ST retorna VLD/RDY/WOF/ROE correctos, InjectFifoRx()/TryDequeueTx() públicos
- IO_BANK0: IRQ edge/level detection por pin (LEVEL_LOW/HIGH, EDGE_LOW/HIGH), INTR0-3 (raw, write-1-to-clear edge), PROC0_INTE/INTF/INTS0-3, PROC1_INTE/INTF (single-core: almacena pero no dispara), IO_IRQ_BANK0=IRQ13 via NVIC, UpdatePinInput() para notificar cambios de pin externo, SIZE ampliado a 0x160 - RP2040Machine: pasa Cpu a IoBank0Peripheral - PWM: CSR_PH_CORRECT (modo phase-correct zigzag), CSR_A_INV/B_INV (inversión de salida aplicada en GetDutyA/B), CSR_DIVMODE almacenado, CSR_PH_ADV/PH_RET como strobe bits (no se almacenan), IsCountingUp() expuesto como helper
- UartPeripheral: add UARTIFLS, UARTDMACR, PL011 ID registers (0xFE0-0xFFC), CortexM0Plus+IRQ constructor params, CheckInterrupts() NVIC routing - SpiPeripheral: add PL022 ID registers (0xFE0-0xFFC), loopback mode (LBM bit), SSPDMACR, CortexM0Plus+IRQ constructor params, CheckInterrupts() - I2cPeripheral: add IC_SAR, full CLR register set (IC_CLR_RX_UNDER/OVER/TX_OVER/ RX_DONE/ACTIVITY/GEN_CALL/RESTART_DET), IC_SLV_DATA_NACK_ONLY, IC_DMA_CR/TDLR/RDLR, IC_SDA_SETUP, IC_ACK_GENERAL_CALL, IC_FS_SPKLEN, stored SCL HCNT/LCNT, CortexM0Plus+IRQ params, CheckInterrupts() - RP2040Machine: wire CPU+IRQ to Uart0(20), Uart1(21), Spi0(18), Spi1(19), I2c0(23), I2c1(24)
…G (Fase 4) New test project with 71 tests covering: - SIO hardware divider (unsigned/signed/div-by-zero/save/dirty), spinlocks - Timer alarms (arm/fire/disarm/clear), interrupt routing (INTS/INTF force) - UART baud rate, LCR_H, TX/RX FIFO, interrupt masking, PL011 ID registers, UARTDMACR - DMA single/multi-word transfer, half-word, chaining, INTR clear - PIO SET/JMP/PULL/PUSH/FLEVEL/INSTR EXEC instruction tests - PWM counter advance/wrap, interrupts, duty readback, PH_ADV/PH_RET strobes Bug fixes discovered via tests: - PioPeripheral: JMP was off-by-one (added PcJumped flag to skip auto-increment) - PioPeripheral: MOV PC destination now sets PcJumped - PioPeripheral: FDEBUG TXSTALL (bits [3:0]) now set on blocking PULL stall - PioPeripheral: FDEBUG TXOVER corrected to bits [11:8] (was [19:16])
- UsbPeripheral covers 0x50100000 (DPRAM 4KB) and 0x50110000 (REGS) in AHB slot 1 - Implements ADDR_ENDP0-15, MAIN_CTRL, SIE_CTRL/STATUS, BUFF_STATUS, USB_MUXING/PWR, USBPHY_DIRECT/TRIM, INTR/INTE/INTF/INTS with W1C semantics - SignalBusReset() and SignalSetupPacket() helpers for test/simulation - WriteDpram()/ReadDpram() byte-block helpers - Wired into RP2040Machine at AHB 0x50100000 with Cpu IRQ 5 - 17 new USB tests (DPRAM, registers, interrupts); total 344 tests all passing
…se 6) - Add TxDepth/RxDepth properties to PioStateMachine (SHIFTCTRL bits 31/30) FJOIN_TX: TX depth=8, RX disabled; FJOIN_RX: RX depth=8, TX disabled - Replace all hardcoded depth=4 checks in PioPeripheral with dynamic depth: TXF write guard, InjectRxData, BuildFstat (full detection), BuildIntr, DoPush - All existing stubs (XOSC, Clocks, Resets, Watchdog, SysInfo, SysCfg, PSM) verified complete - 3 new FJOIN tests; total 347 tests all passing
- DmaPeripheral.RegisterDreq(index, Func<bool>) registers a DREQ source (indexes 0-62) - ExecuteChannel extracts TREQ_SEL from CTRL[20:15]; beats gated by DREQ when source registered - If DREQ stalls mid-transfer: remaining count saved, channel stays BUSY until next trigger - TREQ=63 (PERMANENT) always ready without source lookup (zero overhead) - Add UartPeripheral.RxDataAvailable, SpiPeripheral.RxDataAvailable, PioPeripheral.TxFifoNotFull - Wire PIO0/1 TX/RX (DREQ 0-15), SPI0/1 TX/RX (16-19), UART0/1 TX/RX (20-23) in RP2040Machine - 3 new DREQ tests; total 350 tests all passing
…n, PIO GPIO routing (Fase 8) - RTC: full ITickable implementation — 1 second per 125M cycles, calendar carry with DateTime.DaysInMonth, alarm IRQ 25 with selective field matching (YEAR/MONTH/DAY/DOTW/HOUR/MIN/SEC), MATCH_ACTIVE W1C; fix ENA bit positions to avoid overlap with value fields (DAY@5, MONTH@12, HOUR@21, MIN@14, SEC@6) - PWM: fix IRQ number — all 8 slices share IRQ 4 (PWM_IRQ_WRAP), not per-slice IRQs 4-11 - SIO: InjectFifoRx now fires IRQ 15 (SIO_IRQ_PROC0) when data available - IoBank0: PROC1_INTS registers now return correct masked value - ADC: add HasFifoData property for DMA DREQ integration - GpioPin: ForceInput notifies IoBank0.UpdatePinInput for edge/level interrupts - PIO: wire ReadGpioIn/WriteGpioPins/WriteGpioDirs callbacks to SIO+IoBank0 in RP2040Machine; fix ExecIrq REL flag (smIdx-relative); fix ExecIn/ExecOut/ExecSet/ExecMov to use PINCTRL fields and invoke GPIO callbacks; add OutCount/SetCount PINCTRL properties; FIFO depth now uses dynamic TxDepth/RxDepth (FJOIN support) - Tests: 12 new RTC tests covering tick, CTRL LOAD latch, CTRL ACTIVE, alarm match, MATCH_ACTIVE W1C
…tests (Fase 9) PIO ApplySideset (Fix A+B): - SideEn enable gate is always bit 4 (0x10) of 5-bit field — not 1<<sidesetCount - PINCTRL.SIDESET_COUNT is inclusive of enable bit, remove erroneous +1 - Sideset fires only on completing cycle (moved inside !sm.Stalled block) - ApplySideset is now an instance method to invoke WriteGpioPins/WriteGpioDirs callbacks Watchdog ITickable (Fix C): - Full countdown in µs: 1µs = 125 CPU cycles at CLK_SYS=125 MHz - CTRL_TRIGGER as write-only strobe sets REASON_FORCE and invokes OnReset - Timer expiry sets REASON_TIMER, clears CTRL_ENABLE, invokes OnReset - Writing LOAD reloads countdown and resets accumulator - WatchdogPeripheral added to _tickables[] in RP2040Machine SIO Interpolators (formula fix): - ComputeLane: RESULT = (shifted & mask) + BASE per TRM §2.3.1.7 (was bitwise merge) - PopLane/PopFull: update both ACCUM0=RESULT0 and ACCUM1=RESULT1 per TRM New tests (37): - PIO Sideset: drives pins, nonzero base, delay counter, stall no-fire, SideEn gate=0, SideEn gate=1 - Watchdog: SCRATCH0-7, TICK register, CTRL_TRIGGER, countdown, REASON_TIMER, disable-after-fire, LOAD reload - Bus/AtomicAlias: XOR/SET/CLR aliases via APBBridge (11 tests) - SIO INTERP: ACCUM/BASE rw, BASE_1AND0, PEEK lane0, POP advances ACCUM, signed sign-extend, ACCUM_ADD, INTERP1 independent, CROSS_INPUT
…tion (Fase 10) Flash size configurable (A): - BusInterconnect: constructor param flashSizeBytes=2MB (default), exposes FlashSize/MaskFlash - RP2040Machine: constructor param flashSize=2MB propagated to BusInterconnect - CortexM0Plus: _fetchMask uses Bus.MaskFlash (instance) instead of static const - LoadFlash: validates against Bus.FlashSize with dynamic error message - Enables boards with >2 MB Flash (e.g. RP2040-Zero 16 MB): new RP2040Machine(16*1024*1024) Directory.Build.props consolidation (B): - Add AllowUnsafeBlocks, LangVersion=latest, Nullable=enable, MinVerDefaultPreReleaseIdentifiers - Remove AllowUnsafeBlocks and Nullable from each individual .csproj (covered by props) - NuGet pipeline already in place: publish.yml + MinVer produces versioned packages on git tag v*
MicroPythonBootTests: replace raw banner capture with sys.version query
to avoid races where the banner is emitted before USB-CDC enumeration.
MicroPythonReplTests: use ExecuteCompound for 'def' statement so the
continuation prompt ('... ') is handled correctly.
MicroPythonUartTests: use ExecuteCompound for 'for' loop.
MicroPythonScriptTests (new): three tests that write Python files to
the LittleFS filesystem via WriteFile and verify auto-execution after
SoftReset:
- Script_MainPy_RunsAutomaticallyOnBoot
- Script_MainPy_ComputesAndPrintsArithmetic
- Script_BootPy_RunsBeforeMainPy
…n tests CircuitPythonBootTests: 6 tests covering no-hard-fault startup, REPL prompt, USB-CDC enumeration, version header, sys.platform, and Hello World output for CircuitPython 9.2.1. CircuitPythonReplTests: 8 tests covering arithmetic, sys.version, function definition, multi-command sequences, for-loop, board.LED pin access, and GPIO LED control (set high / set low). CircuitPythonScriptTests: 4 tests using the read-side FAT filesystem (no write persistence required, as CircuitPython FAT flushes via SSI which is not yet fully emulated): - Script_DefaultCodePy_RunsOnSoftReset - Script_Filesystem_ListdirShowsCodePy - Script_DefaultCodePy_ContentIsReadable - Script_DefaultCodePy_ExecRunsInSession
Add pre-compiled pico-examples UF2 binaries as embedded resources and update the project file to include Firmware/**/*.uf2. PicoExamplesFirmware: helper class to load embedded UF2 firmware by name. New integration test suites covering pico-examples firmware: - AdcTests : ADC reads, temperature sensor, UART output - BlinkTests : GPIO 25 blink timing, toggle count - ClocksTests : 48 MHz clock switch, UART frequency output - DividerTests : hardware divider results, no stack overflow - DmaTests : DMA transfer, channel IRQ, CPU health - GpioTests : blink-simple output, GPIO IRQ edge injection - InterpTests : interpolator results, numeric UART output - MulticoreTests : multicore hello, FIFO IRQ (skipped until core1 ready) - PioTests : PIO state machine, UART-TX PIO, blink via PIO - PwmTests : PWM init, LED fade duty-cycle variation - ResetTests : peripheral reset/release, UART output - RtcTests : RTC tick, alarm firing, multi-tick capture - SystemTests : unique_board_id hex output, CPU health - TimerTests : timer fired output, multiple firings, 3 s survival - UartTests : hello_uart and hello_serial output - UsbTests : CDC enumeration, hello_usb repeated transmission - WatchdogTests : watchdog scratch, reboot reason, CPU survival
Agent-Logs-Url: https://github.com/begeistert/RP2040Sharp/sessions/3fa0c2da-2059-4732-9cd4-7570ec859887 Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
…PL demo Agent-Logs-Url: https://github.com/begeistert/RP2040Sharp/sessions/3fa0c2da-2059-4732-9cd4-7570ec859887 Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
…roPython PIO Agent-Logs-Url: https://github.com/begeistert/RP2040Sharp/sessions/d53aa4e1-1886-48d8-bd53-54788a75d61b Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
Agent-Logs-Url: https://github.com/begeistert/RP2040Sharp/sessions/d53aa4e1-1886-48d8-bd53-54788a75d61b Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
Agent-Logs-Url: https://github.com/begeistert/RP2040Sharp/sessions/a3e0100f-e289-41ec-b414-4340349bb6e1 Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
Agent-Logs-Url: https://github.com/begeistert/RP2040Sharp/sessions/a3e0100f-e289-41ec-b414-4340349bb6e1 Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
Agent-Logs-Url: https://github.com/begeistert/RP2040Sharp/sessions/89541b3d-0f3d-4a3e-bf53-2d7182a0469e Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
Agent-Logs-Url: https://github.com/begeistert/RP2040Sharp/sessions/89541b3d-0f3d-4a3e-bf53-2d7182a0469e Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
Add full W25Q command set to SsiPeripheral: - WRITE_ENABLE (0x06), WRITE_DISABLE (0x04) - SECTOR_ERASE 4KB (0x20), BLOCK_ERASE 32KB (0x52), BLOCK_ERASE 64KB (0xD8), CHIP_ERASE (0xC7/0x60) - PAGE_PROGRAM (0x02) - READ_DATA (0x03), FAST_READ (0x0B) - READ_STATUS_REGISTER1/2 (0x05/0x35) Wire IoQspiPeripheral to monitor SS OUTOVER transitions and forward CS assert/deassert signals to the SSI. Attach flash pointer to SSI in RP2040Machine constructor.
…jection Implement CircuitPythonRunner.CreateWithWritableFsAsync(): - Phase 1: boot CircuitPython once so it initialises the FAT filesystem. - Phase 2: snapshot the full 2 MB flash image, inject boot.py directly into the FAT12 partition (using fixed BPB parameters discovered empirically: BPS=512 SPC=1 RSVD=1 NFAT=1 SPF=7 RDE=512). boot.py contains 'storage.disable_usb_drive()' which suppresses the USB-MSC descriptor so the CIRCUITPY drive is writable from Python. - Phase 3: restart with the modified flash image; boot.py runs on the hard reset, before TinyUSB initialises, enabling FS writes. Add FAT12 helpers Fat12Get/Fat12Set for reading/writing 12-bit cluster entries packed across byte boundaries. PicoSimulation gains an optional withUsbCdc parameter for future use. New integration tests (all pass): - Script_Filesystem_IsWritableFromPython - Script_WriteCodePy_RunsAfterSoftReset - Script_WriteCodePy_ComputesAndPrintsArithmetic
…mprove-performance # Conflicts: # src/RP2040.TestKit/Boards/PicoSimulation.cs Co-authored-by: begeistert <36460223+begeistert@users.noreply.github.com>
UsbHidHost subscribed to OnEndpointRead and replied with an empty EndpointReadDone() every time the device armed its HID OUT endpoint. On CircuitPython that endpoint is sparse (host only writes when SendReport() is called), so the empty-completion arm/re-arm cycle became a tight loop that starved the firmware of CPU and prevented the REPL prompt from ever appearing. Drop the OnEndpointRead subscription entirely; outgoing reports are delivered explicitly via SendReport(), which queues the data through EndpointReadDone() and lets the firmware consume it on the next arm. Restores 17 CircuitPython integration tests that depend on WaitForPrompt().
The autopull check ran AFTER bit extraction and only when OsrCount==0, which ignored the configured PULL_THRESH and let the first OUT after RESTART extract garbage from a stale OSR. With autopull enabled and a threshold below 32 (e.g. 8 bits), this meant programs that relied on autopull to pre-fill the OSR would emit zeros until OsrCount eventually hit zero. - Move the autopull check to the start of ExecOut, gated on shifts-so-far ≥ PULL_THRESH (RP2040 datasheet §3.5.4.4). When the TX FIFO is empty, stall the SM and set FDEBUG.TXSTALL. - Initialise OsrCount=0 on RESTART (shift count = 32) so the first OUT after restart triggers autopull (datasheet §3.5.4.2.1), instead of running on the post-reset OSR=0 placeholder. - Drop the redundant post-OUT non-blocking pull, which would have refilled the OSR on threshold-exact extractions even when no further OUT was pending.
The test asserted that rp2.PIO.OUT_LOW prints "0", but in MicroPython's rp2 module on RP2040 the pin-init enum is IN_LOW=0, IN_HIGH=1, OUT_LOW=2, OUT_HIGH=3 (see ports/rp2/modrp2.c). Update the expectation to "2" and add a comment pointing at the upstream definition so the constant is no longer ambiguous.
@rp2.asm_pio() defaults out_shiftdir to SHIFT_LEFT, so out(pins, 8) extracts the high byte of OSR first. With sm.put(0xA5) the OSR is 0x000000A5 and the high byte is 0x00, which is what the loopback was actually writing to GPIO. Adding out_shiftdir=PIO.SHIFT_RIGHT extracts the low byte first so the 0xA5 sentinel reaches the pins (and SM1's in_(pins, 8) reads it back) as the test expects.
New executable RP2040Sharp.Demo.CircuitPython.Blink that boots CircuitPython 9.2.1 on the emulated Pico, pastes the Adafruit blink example into the REPL via paste mode (Ctrl-E … Ctrl-D), and monitors GPIO 25 (board.LED) while the script toggles it for ≥ 20 s of simulated time. The demo prints a real-time, time-stamped log of every LED state change and a final summary (transition count, simulated runtime, wall-clock time). Firmware is downloaded once from downloads.circuitpython.org and cached under the system temp dir, mirroring the existing MicroPython demo's pattern. Run with: dotnet run --project src/RP2040Sharp.Demo.CircuitPython.Blink
Lets external circuit simulators drive an I2C0/1 instance as a slave: - SimulateIncomingAddress/Data/Stop and SlaveAddressChanged expose the slave side to host code. - Slave-transmit now queues every byte firmware writes to IC_DATA_CMD until STOP, so multi-byte master reads are captured in order (was a single overwritten byte). - Raises RD_REQ / RX_FULL / TX_EMPTY / STOP_DET to match DW_apb_i2c. Adds I2cTests covering slave address, receive, and transmit flows. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two dual-core defects that left Core1 effectively dead: - The SIO launch handshake was gated on `_cpu1 == null`, but RP2040Machine always wires Cpu1 at construction, so the §2.8.3 handshake never ran and Core1 never started (Core0 spun forever waiting for the FIFO echo). Gate on a dedicated `_core1Launched` flag instead, cleared on Reset(). - Run() advanced time-aware peripherals by Core0's cycles alone; with both cores live, wall-clock elapsed is max(core0, core1). Expose it via LastElapsedCycles and Core1Launched. Adds DualCore_ElapsedTime_IsMaxNotSum, which now actually exercises a running Core1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings RP2040Sharp to parity with rp2040js's GDB stub, the last major feature gap. Debug Core 0 with arm-none-eabi-gdb via `target remote :3333`. - GdbUtils, GdbServer, GdbConnection, IGdbTarget, GdbTcpServer under RP2040.Gdb (AOT/trim-clean — TcpListener verified to add no warnings). - Supports ?, qSupported/qXfer:target.xml/qRegisterInfo/qHostInfo, g, p/P (incl. xPSR + MSP/PSP/PRIMASK/CONTROL), m/M, c, D (detach), vCont;c/s, and BKPT-driven stop replies with PC rewind. - Registers.SetxPsr lets a debugger write the flags/IPSR. - Demo gains a --gdb flag that serves Core 0 alongside the MicroPython REPL. Verified end-to-end against arm-none-eabi-gdb (registers, memory, stepi, detach) plus 13 in-process GdbServerTests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Roadmap now reflects reality: dual-core and GDB done; XOSC/ROSC/PLL/ PSM/VREG honestly marked as register stubs (no frequency model). - Features/usage cover I2C slave mode, USB HID/MSC host, and the --gdb flag with an arm-none-eabi-gdb quick-start. - IsPackable=false on both demo projects so `dotnet pack` publishes only RP2040Sharp and RP2040Sharp.TestKit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The only consumer (iCircuit's RP2040Elm) uses UsbCdcHost alone for the MicroPython REPL; nothing uses the MSC or HID host drivers. They also never worked end-to-end: delivering a CBW to the MSC OUT endpoint during boot spun CircuitPython's USB ISR, leaving the 5 CircuitPython MSC/HID integration tests permanently red (a deep USB-device emulation bug). Removing the dead feature deletes that liability and turns the integration suite fully green. - Delete UsbMscHost, UsbHidHost, UsbMscProbe, UsbHidProbe and their tests. - Strip MSC/HID endpoint discovery from UsbCdcHost; ExtractAllInterfaces collapses back to a CDC-only ExtractEndpointNumbers. - Drop UsbMsc/UsbHid from the TestKit (RP2040TestSimulation, PicoSimulation) and WriteFileViaMsc from CircuitPythonRunner. FatVolume stays (CDC-agnostic). Integration suite: 149/149 green. Unit: 445 green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the SonarQube/SonarCloud analysis from the Unit Tests job: the JDK setup, scanner install, begin/end steps, and the opencover coverage collection that only fed Sonar. Tests now run as a plain dotnet test. Also removes the Quality Gate badge from the README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restructure the NuGet publish workflow: - Runs only on `v*` tags or a manual workflow_dispatch (not on every push). - Pack each package explicitly (RP2040Sharp, RP2040Sharp.TestKit) instead of packing the whole solution, so output is deterministic. - Run unit tests only (the old workflow ran the full suite, pulling in the firmware-downloading integration tests). - Push to nuget.org is guarded: only for `v*` tags or a manual run with push_public=true, and only on github.com with an API key present — so Gitea mirror runs don't publish. - Always upload the packed .nupkgs as an artifact. Versioning stays with MinVer (fetch-depth: 0): `v*` tags release a stable version, a manual run produces a preview. Co-Authored-By: Claude Opus 4.8 <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.
Description
Brings RP2040Sharp to functional parity with the upstream
rp2040jsemulator andfixes a dormant dual-core defect, then trims dead code so the full test suite is green.
Highlights
GDB Remote Serial Protocol server (
feat(gdb)) — the last major parity gap withrp2040js. Debug Core 0 with
arm-none-eabi-gdbviatarget remote :3333: registers(
g/p/P, incl. xPSR + MSP/PSP/PRIMASK/CONTROL), memory (m/M),c,s/vCont,D(detach), and BKPT-driven stop replies with PC rewind. AOT/trim-clean. The demogains a
--gdbflag. Verified end-to-end againstarm-none-eabi-gdb(registers,memory,
stepi, detach).Dual-core now actually runs (
fix(multicore)) — the SIO launch handshake was gatedon
_cpu1 == null, butCpu1is always wired at construction, so the §2.8.3 handshakenever fired and Core 1 never started. Gated on a real launch flag instead. Also:
Run()now advances time-aware peripherals by
max(core0, core1)cycles, not Core 0 alone.I2C slave-mode simulation (
feat(i2c)) — lets external circuit simulators drive anI2C0/1 instance as a slave (RD_REQ / RX_FULL / TX_EMPTY / STOP_DET, multi-byte
slave-transmit), per the DW_apb_i2c datasheet.
Remove unused USB MSC/HID host drivers (
refactor(usb)) — the only consumer(iCircuit's
RP2040Elm) usesUsbCdcHostalone. The MSC/HID drivers were dead codethat never worked end-to-end (delivering a CBW during boot spun CircuitPython's USB
ISR), which kept 5 integration tests permanently red. Removing them deletes the
liability and turns the integration suite fully green.
UsbCdcHostandFatVolumeare untouched.
Release prep (
docs(release)) — honest roadmap (dual-core & GDB done; PLL/XOSC/etc.marked as register stubs), GDB usage docs, and
IsPackable=falseon the demo projectsso
dotnet packpublishes onlyRP2040SharpandRP2040Sharp.TestKit.Test results: Unit 445/445 ✅ · Integration 149/149 ✅
Type of change
Checklist
dotnet test)Screenshots / Hex Dumps (Optional)
GDB session against the running demo (
--gdb):(gdb) target remote :3333
(gdb) info registers r0
r0 0x11223344 287454020
(gdb) x/2xh 0x20000000
0x20000000: 0xbf00 0xbf00
(gdb) stepi
0x20000002 in ?? ()
(gdb) detach
[Inferior 1 (Remote target) detached]