Skip to content

Conversation

@kuba2k2
Copy link

@kuba2k2 kuba2k2 commented Aug 13, 2025

Consider this simple PIO program:

.program prog

.wrap_target
	set x, 0
	wait 1 gpio 0
	in x, 32
	push
end:
	jmp end
.wrap

This program stalls in wait as long as GPIO0 value is 0. If a forced instruction is executed while it stalls, it should return to that wait instruction after the forced one.

Testing on real hardware

  1. As expected, when GPIO0 is 1, the program continues and pushes 0x0 to the FIFO:
I [      0.000] Loaded PIO program, enabled SM
I [      0.000] FIFO level: 0
I [      0.000] GPIO0 is now 1
I [      0.000] GPIO0 is now 0
I [      0.000] FIFO level: 1
I [      0.000] FIFO value: 00000000
I [      0.000] FIFO level: 0
  1. When using a forced instruction, however, the wait continues after the set x, 8 completes. When the GPIO0 value is 1, the modified value of X=8 is pushed instead:
I [      0.000] Loaded PIO program, enabled SM
I [      0.000] FIFO level: 0
D [      0.000] Executing 'set x, 8'...
I [      0.000] Execute completed
I [      0.000] FIFO level: 0
I [      0.000] GPIO0 is now 1
I [      0.000] GPIO0 is now 0
I [      0.000] FIFO level: 1
I [      0.000] FIFO value: 00000008

Testing in the emulator

> reset
> assemble -i exec.pio -o exec.hex +l
pioasm exited with code 0
parsed program "prog" with 5 PIO SM instructions
[...]
> sm --enable=true
> trace -c 2
2 clock cycles executed.
> reg
(pio0:sm0) X=00000000, Y=00000000, PC=01
> exec -f 0xe028
forced instruction written for pending execution:
(pio0:sm0) last executed: set x, 08
> trace -c 1
1 clock cycle executed.
> reg
(pio0:sm0) X=00000008, Y=00000000, PC=02
> fifo
(pio0:sm0) TX0       TX1       TX2       TX3       RX0       RX1       RX2       RX3
           00000000? 00000000  00000000  00000000  00000000? 00000000  00000000  00000000
           (TX_LEVEL=0, RX_LEVEL=0)
[...]
> trace -c 2
2 clock cycles executed.
> fifo
(pio0:sm0) TX0       TX1       TX2       TX3       RX0       RX1       RX2       RX3
           00000000? 00000000  00000000  00000000  00000008? 00000000  00000000  00000000
           (TX_LEVEL=0, RX_LEVEL=1)
[...]

Notice that, instead of waiting for the GPIO value, the program just continued from PC=2 and pushed the modified value of X=8.

Fixed output

This PR fixes that behavior. Output after applying the fix:

> reset
> assemble -i exec.pio -o exec.hex +l
> sm --enable=true
> trace -c 2
> reg
(pio0:sm0) X=00000000, Y=00000000, PC=01
> exec -f 0xe028
forced instruction written for pending execution:
(pio0:sm0) last executed: set x, 08
> trace -c 1
> reg
(pio0:sm0) X=00000008, Y=00000000, PC=01
> trace -c 3
> reg
(pio0:sm0) X=00000008, Y=00000000, PC=01
> fifo
(pio0:sm0) TX0       TX1       TX2       TX3       RX0       RX1       RX2       RX3
           00000000? 00000000  00000000  00000000  00000000? 00000000  00000000  00000000
           (TX_LEVEL=0, RX_LEVEL=0)
> gpio --gpio 0 --set
(pio*:sm*) set GPIO external input 00 to 1
> trace -c 3
> reg
(pio0:sm0) X=00000008, Y=00000000, PC=04
> fifo
(pio0:sm0) TX0       TX1       TX2       TX3       RX0       RX1       RX2       RX3
           00000000? 00000000  00000000  00000000  00000008? 00000000  00000000  00000000
           (TX_LEVEL=0, RX_LEVEL=1)

@kuba2k2
Copy link
Author

kuba2k2 commented Aug 13, 2025

From the datasheet (page 343):

When an instruction is written to the INSTR register, the state machine immediately decodes and executes that
instruction, rather than the instruction it would have fetched from the PIO’s instruction memory. The program counter
does not advance, so on the next cycle
(assuming the instruction forced into the INSTR interface did not stall) the state
machine continues to execute its current program from the point where it left off
, unless the written instruction itself manipulated PC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant