Match the Go runtime by terminating for deadlocks, stack overflows,
runtime and GC invariants, invalid lock operations, and platform
initialization failures instead of routing them through panic/recover.
Keep language-level runtime errors and unsupported user operations
recoverable. Add crash coverage that verifies fatal errors bypass deferred
recover calls.
Match the Go runtime by terminating instead of unwinding when an
allocator exhausts the heap. Recovering an OOM can leave allocator locks
held and cannot safely continue when the panic path itself needs memory.
- Fix SetInterrupt error capture: use a package-level variable instead
of a named return captured by the sync.Once closure, avoiding a
closure allocation on every call.
- Extract GPIO interrupt handler from inline closure to named function
(handleGPIOInterrupt), matching the UART handler pattern.
- Unexport ESP32-specific UART fields (txrxSignal, rtsctsSignal,
parityErrorDetected, dataErrorDetected, dataOverflowDetected).
- Change UART.Configure to return error, consistent with ESP32C3/C6.
- Clarify why UART0 does not return early when pins are already wired.
Signed-off-by: deadprogram <ron@hybridgroup.com>
Remove unused cpuIntUsed and cpuIntToPeripheral variables from
interrupt_esp32.go because these were declared but never read.
Fix _globals_end in the linker script to cover .data in addition to
.bss and .wifi_bss. Previously the GC scan range ended at
_wifi_bss_end, missing any heap pointers stored in initialized
globals (.data section). Extend to _edata so the conservative
collector sees all global root pointers.
Signed-off-by: deadprogram <ron@hybridgroup.com>
Work around an lld (LLVM 22) bug where l32r PC-relative offsets are
miscalculated when auto-generated .literal.* sections are prepended to
.text.* sections by the linker script. The assembler emits .literal
entries for movi instructions whose constants exceed the 12-bit signed
range; lld then resolves the l32r relocations with incorrect offsets,
causing every l32r in the boot code to load from the wrong literal
pool entry.
The symptom was a TG0WDT_SYS_RESET boot loop: the watchdog disable
code loaded wrong register addresses via l32r and silently wrote to
the wrong peripheral registers, leaving the watchdog running.
Fix by constructing PS_WOE_MASK (0x40000) with movi+slli instead of a
single large-constant movi, eliminating all auto-generated .literal
section entries. This is compatible with both LLVM 20 and LLVM 22.
Also revert DRAM origin to 0x3FFAE000 (200K) and remove rom_phyFuns
symbols that belong in a separate WiFi commit.
Signed-off-by: deadprogram <ron@hybridgroup.com>
Add full flash XIP support for ESP32, enabling code and read-only data to
execute/load directly from flash via the MMU cache rather than consuming
precious SRAM. This increases available RAM from ~328KB to effectively
unlimited for code/rodata, while keeping ~121KB for the Go heap.
Changes:
- src/device/esp/esp32.S: Add MMU initialization in call_start_cpu0
- Call ROM bootloader mmu_init() and cache_flash_mmu_set() to map DROM/IROM
- Enable flash cache via ROM Cache_Read_Enable()
- Fix tinygo_scanCurrentStack to spill all register windows for GC
- targets/esp32-interrupts.S: Add exception diagnostics
- targets/esp32.ld: Major linker script restructure for XIP
- Add DROM (4MB @ 0x3F400000) and IROM (4MB @ 0x400D0000) regions
- Move .rodata to DROM, main .text to IROM (both flash-mapped)
- Keep boot code, vectors, and WiFi blob IRAM sections in SRAM0
- Create WiFi arena in SRAM1 pool 7/6 (64KB @ 0x3FFF0000)
- Move .bss and heap to SRAM2 (200KB @ 0x3FFAE000), avoiding ROM/MAC regions
- Add _drom_flash_addr variable (patched by builder with flash offset)
- targets/esp32.json: Add linker wrap flags for malloc/free and WiFi functions
Signed-off-by: deadprogram <ron@hybridgroup.com>
Goexit cannot run deferred functions on architectures without panic
unwinding. Query runtime.supportsRecover before calling it so unsupported
targets report an error instead of leaving the test runner blocked forever.
The shared timekeeping code assumes the TIMG0 timer counts at 40MHz,
but on the ESP32-C6 the timer clock defaults to the 40MHz XTAL, giving
a 20MHz tick with the /2 prescaler and making all delays run twice as
long. Select PLL_F80M (80MHz) and enable the timer group clock so the
25ns/tick assumption holds.
Signed-off-by: deadprogram <ron@hybridgroup.com>
Currently, calling any sync.Map method from inside the sync.Map.Range
callback f deadlocks. Moreover, Go's sync.Map explicitly permits the
Range callback to call other methods on the map ("Range does not
block other methods on the receiver; even f itself may call any
method on m").
This commit prevents the deadlock by changing sync.Map.Range to:
- copy the map's keys under the lock
- release the lock
- iterate over the key snapshot
A snapshot satisfies Go's sync.Map.Range contract, which only
requires that no key is visited more than once and may reflect any
mapping from any point during the call.
Using a snapshot keeps the implementation simple, in line with this
file's stated scope ("no more efficient than a map with a lock").
Also added TestMapRangeAndDelete regression test, which deletes map
entries from inside the map's Range callback.
Replace movi instructions with constants outside the 12-bit signed
range (-2048..2047) with movi+slli sequences. Large constants cause
the assembler to emit auto-generated .literal section entries, which
triggers an lld bug where l32r PC-relative offsets are miscalculated
when .literal.* sections are merged with .text.* sections.
Signed-off-by: deadprogram <ron@hybridgroup.com>
Define the board's external crystal (HSE) frequency `xtalHz` in the
respective `board_*.go` files. Per-topology PLL tables (F1, F4, F7)
will compute the register dividers from it.
Moving this parameter to the board definition level cleanly isolates
board hardware characteristics from general MCU chip configurations,
eliminating the need for custom target build tags. Targets using
HSE-clocked STM32 chips must define `xtalHz` or fail to build.
* feat(machine): add UART line inversion support.
Add InvertTX and InvertRX to UARTConfig to allow enabling hardware
line inversion on supported targets. Added hardware implementation for
RP2 (RP2040, RP2350), STM32 (newer families), SAM (SAMD51, SAME5x),
and ESP (ESP32, ESP32-C3, ESP32-C6).
* refactor(machine): Refactor UART inversion with pin setter helpers.
RP2: Extract setOutOver/setInOver methods on Pin, removing inline
IO control register manipulation from UART configure.
SAM: Switch to SetCTRLA_TXINV/SetCTRLA_RXINV methods, dropping
the unused device/sam import and raw SetBits/ClearBits calls.
---------
Co-authored-by: Konstantin Sharlaimov <ksharlaimov@inavflight.com>
STM32F4 and F7 share the same OTG FS IP but have no USB driver in
TinyGo. This adds a full device-mode driver covering CDC, HID, and
MSC with working examples.
- OTG FS has 4 physical EPs (0–3); virtual indices 4–7 fold onto
them via physEP() so the existing machine/usb API is unchanged
- F4 bypasses VBUS sensing via GCCFG.NOVBUSSENS; F7 uses the USB
voltage regulator + GOTGCTL B-valid override instead
- STM32F7 PLL_Q changed 2→9 to produce the 48 MHz clock required
by USB/RNG/SDMMC; CK48MSEL cleared to select main PLL as source
- HID and MSC descriptors remapped at init() to physical endpoint
addresses (EP2/EP1 for HID, EP2/EP3 for MSC)
- usb-storage example replaced machine.Flash with a FAT12 RAM disk
so the host mounts without reformatting
- MSC sendCSW sets queuedBytes before state transition to fix a
missed byte-count on the status phase
Treat panicState as a bitmask so a recovered panic during Goexit
can clear the panic bit while preserving the pending Goexit bit.
This removes the separate deferFrame Goexit field and restores the
previous defer frame size.
The threads scheduler handled runtime.Goexit using the generic deadlock
path, which parked the current pthread forever. Add a scheduler-specific
goexit hook so it can remove the current task and exit the pthread while
ordinary blocking deadlocks still block.
Track main goroutine Goexit so the last remaining goroutine reports the
expected deadlock instead of letting the process exit successfully.
Expand the crash coverage with the Goexit cases covered by Big Go's
runtime tests.
Keep a pending Goexit separate from the active panic state so recovered
deferred panics do not cancel the original Goexit unwind. Goexit should
also ignore -panic=trap, since it is not a panic.
Wire testing.FailNow and SkipNow through runtime.Goexit, and run tests
and benchmarks in goroutines. This lets Goexit terminate the user
function without skipping test bookkeeping. Add Goexit/recover coverage
and enable crypto/ecdh in the Linux stdlib test list.
* adding support for SeeedStudio XIAO BLE Plus and Sense Plus boards;
* adjusting definitions for UARTs on XIAO BLE Plus;
* fixed buid tag on XIAO BLE Plus;
* tested by building some examples; fixed UART nomenclature;
* added xiao-ble-plus to GNUmakefile smoketests;
* upgrade net
* add some missing crypto and os API (#5488)
* add missing crypto API
* gofmt crypto/tls/common.go
* pull new net with unixsock formatted
* update net to latest main
* runtime: fix ticker not stopping when Stop races with its callback
On the threads and cores schedulers, timer callbacks run concurrently
with user goroutines.
If Stop (or Reset) was called in the window after the node was popped
but before its callback re-added it, removeTimer would not find the
timer in the queue, so it would be re-added to timer anyway.
Track timers whose callback is currently running in a firing list, and
have removeTimer mark a firing timer as stopped so its callback does not
re-add it.
Also make the timers test drain robust: allow a possible in-flight tick
delivered concurrently with Stop to settle before draining the channel.
Signed-off-by: deadprogram <ron@hybridgroup.com>
* runtime: fix Stop/Reset semantics when racing a firing timer callback
Address review feedback on the ticker Stop-race fix. On the threads and
cores schedulers a timer callback runs concurrently with user goroutines,
which left several problems:
- removeTimer reported a firing timer as successfully removed, so
Stop/Reset could return true even though the callback had already
started (wrong semantics, notably for AfterFunc). firingTimerStop now
returns a bool and removeTimer no longer hands the still-firing node
back to resetTimer.
- The periodic advance (when += period) ran in timerCallback outside the
scheduler timer lock. Move it into each scheduler's reAddTimer, under
the lock and after the stopped check, so a concurrent Reset can't have
its freshly-queued deadline corrupted.
- resetTimer now sets when/period after removeTimer for the same reason.
Add testdata/timer_stop_reset_race.go and TestTimerStopResetRace, which
reproduce the stop-while-firing and reset-while-firing races via the
runtime timer linkname hooks.
Signed-off-by: deadprogram <ron@hybridgroup.com>
* runtime: fix timer Stop/Reset race with firing periodic timers
Signed-off-by: deadprogram <ron@hybridgroup.com>
---------
Signed-off-by: deadprogram <ron@hybridgroup.com>
Adds machine_esp32c6_adc.go implementing the machine.ADC interface for
ESP32-C6 (ADC1 only, GPIO0–GPIO6, channels 0–6; there is no ADC2).
Signed-off-by: deadprogram <ron@hybridgroup.com>
* all: clean up code with Go 1.24+ in mind
* all: more old go cleanup
* all: even remove rand_fastrand64
* runtime: revert rand changes
* runtime: re-drop rand_fastrand64
Having them as methods on reflectlite.Value makes them
visible to the user.
Also move new functions out of all_test.go so it can stay
closer to upstream (except for comments).