Nested loops with the PRU LOOP instruction?

Hi all,

The PRU LOOP instruction (p48 of the assembly instruction guide) describes a “hardware-assisted loop” instruction. If you use a register, your loop counter can be 16-bits wide, so with

LDI r10.w0, 0xffff

LOOP Exit, r10.w0
… (stuff in here runs 65535 times) …
Exit:
… (Now we’re outside the loop) …

you have a maximum of 65535 repetitions. Very good. What happens though if you want three times that? Can you do

LOOP Exit, 3

LDI r10.w0, 0xffff

LOOP Exit, r10.w0
… (stuff in here runs how many times?) …
Exit:
… (Now we’re outside the loop) …

Based on the documentation, I could see this loop iterating 3 times, 65535 times, or 3*65535 times. Does anyone know what the truth is?

There must be a limit somewhere, right? Otherwise I could loop 2^100 times by doing this:

LOOP Exit, 2

LOOP Exit, 2

LOOP Exit, 2

; now repeat the line above 97 more times

… (stuff in here runs how many times?) …
Exit:
… (Now we’re outside the loop) …

and there’s no way that works, right? There would need to be a hundred hidden loop counter registers somewhere inside the PRU…

Bonus question: the manual tells us that “The loop is non-interruptible(LOOP).” What does non-interruptible mean—do interrupt bits in r31 never get set inside a loop?

–Tom

you have a maximum of 65535 repetitions. Very good. What happens though if
you want three times that? Can you do

LOOP Exit, 3
LDI r10.w0, 0xffff
LOOP Exit, r10.w0

  Off hand, I'd suspect one can NOT nest LOOP instructions. However, a
literal reading of the "operation" section could imply that each LOOP
instruction expands into two data items (counter and top) which may be
allocated/inlined in the code.

  Seems like it would be faster to just write a test program nesting two
LOOP instructions, the outer with a small immediate count, and the inner
reading from a register preset with a similar small count. Maybe have the
inner loop simply increment some counter, and check if the counter has the
result of multiple loops, or just one (and which one, inner or outer).

Bonus question: the manual tells us that "The loop is
non-interruptible(LOOP)." What does non-interruptible mean---do interrupt
bits in r31 never get set inside a loop?

  Since the PRU doesn't have asynchronous interrupts by default I'm not
sure what "interruptible" would mean... However, SPRUHF8A indicates that
there is an "interruptible loop" variant.

On the Z80, the counter register B was only 8 bits, you could loop 1 to 256 times with DJNZ.

The outer loop was often unrolled, that is the inner loop was repeated, say, 3 times…

Say you wanted to loop 700 times = 256 + 256 +188; load the B register with 188 and jump to the first inner loop, at the end of the first inner loop the B reg is zero, the second inner loop is performed 256 times, and finally the third inner loop is performed 256 times.

The same unrolled outer loops can be reused to loop just 200 times, load the B reg with 200 and jump straight to the third inner loop.

There was a trade off between RAM data/stack space and ROM code space and execution time. If the inner loop was long, then make it into a subroutine and call it 3 times in a row.

It is not clear from the PRU instruction set, but it does not look like you can have a LOOP within a LOOP as the inner LOOP instruction would just overwrite the end address and loop counter of the outer LOOP.

You could use the high 16 bits of the register, as an outer loop counter (I’ve not done PRU assembly before, so could be mistakes)

mov r2.w2, 3+1
mov r2..w0, 65535

OuterLoop:
loop EndLoop, r2 // inner loop 65535 times

...
EndLoop:
sub r2.w2, 1
qbne OuterLoop, r2.w2, 0

Non interrupable can mean atomic. Did you see the disclaimer about PRU version and instruction set?
I agree with Dennis
Code it up educate us.

Unless your offering prizes​:grinning::grin::rofl::joy: