PIO Assembler
Build and assemble programs for the RP2040 / RP2350 Programmable I/O state machines from Sema. Each pio/* instruction function returns an instruction map; pio/assemble resolves labels and packs the program into the 16-bit words the hardware loads. The examples/pico-*.sema programs use this module with the serial port bindings to drive a Raspberry Pi Pico.
TIP
Instruction builders are pure functions: they only build data. Nothing talks to hardware until you send the assembled words over serial/* or another transport.
Assembling a program
pio/assemble
(pio/assemble program [config]) → mapprogram is a list of instruction maps interspersed with label symbols and the :wrap-target / :wrap keyword markers. Labels are resolved, the 32-instruction limit is enforced, and the result is a map with:
| Key | Description |
|---|---|
:instructions | A little-endian bytevector of 16-bit instruction words |
:length | Number of instructions |
:wrap-target, :wrap | The hardware auto-loop bounds |
config accepts :side-set-bits (0..5) and :side-set-opt (bool), which reserve delay/side-set bits in every instruction.
;; A blink loop: drive a pin high, then low, then jump back to 'loop
(pio/assemble
(list 'loop
(pio/set :pins 1)
(pio/set :pins 0)
(pio/jmp :always 'loop))
{:side-set-bits 0})
; => {:instructions #u8(1 224 0 224 0 0) :length 3 :wrap 2 :wrap-target 0}Instructions
Every builder returns an instruction map for pio/assemble.
pio/jmp
(pio/jmp target) ; unconditional
(pio/jmp cond target)Conditions: :always, :!x, :x--, :!y, :y--, :x!=y, :pin, :!osre. target is a label symbol.
pio/wait
(pio/wait polarity source index [:rel])Stall until source (:gpio, :pin, :irq) at index (0..31) matches polarity (0 or 1). :rel makes an IRQ index relative to the state machine.
pio/in / pio/out
(pio/in source bits) ; shift bits (1..32) from source into the ISR
(pio/out dest bits) ; shift bits (1..32) from the OSR into destin sources: :pins, :x, :y, :null, :isr, :osr. out destinations: :pins, :x, :y, :null, :pindirs, :pc, :isr, :exec.
pio/push / pio/pull
(pio/push [:block | :no-block] [:iffull])
(pio/pull [:block | :no-block] [:ifempty])push moves the ISR into the RX FIFO; pull moves a TX FIFO word into the OSR. :block (the default) stalls when the FIFO is full/empty; :iffull / :ifempty only transfer once the shift threshold is reached.
pio/mov
(pio/mov dest source [op])Destinations: :pins, :x, :y, :exec, :pc. Sources: :pins, :x, :y, :null, :status, :isr, :osr. op is :invert or :reverse.
pio/irq
(pio/irq mode index [:rel])mode is :set, :wait (set and stall until cleared), or :clear; index is an IRQ flag 0..7.
pio/set
(pio/set dest value)Write an immediate value (0..31) to :pins, :x, :y, or :pindirs.
pio/nop
(pio/nop)Encoded as mov y, y.
Modifiers
pio/delay
(pio/delay cycles instr)Return a copy of instr that stalls for cycles (0..31) after it runs. The available range shrinks as more side-set bits are configured.
pio/side
(pio/side value instr)Return a copy of instr that drives the side-set pins to value (0..31) in the same cycle. Requires :side-set-bits in the pio/assemble config.
(pio/assemble
(list 'loop
(pio/side 1 (pio/delay 7 (pio/nop)))
(pio/side 0 (pio/delay 7 (pio/nop)))
(pio/jmp 'loop))
{:side-set-bits 1})See also
- Serial Ports — send the assembled program to a board
examples/pico-blink.sema,examples/pico-piano.sema— complete programs