Skip to content

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]) → map

program 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:

KeyDescription
:instructionsA little-endian bytevector of 16-bit instruction words
:lengthNumber of instructions
:wrap-target, :wrapThe 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.

sema
;; 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 dest

in 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.

sema
(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