here is an example of assembly code embedded in a XC function which is optimized to store a port-input into a circular buffer. it take 4 core cycles only to read, store, increment, compare, reset and loop.
Code: Select all
[[dual_issue]] void circularbuff(buffered in port:4 p, unsigned &ptr, unsigned max){
unsigned idx,val,test;
asm volatile("#allocate reg %0 %1 %2":"=r"(idx),"=r"(val),"=r"(test));
asm volatile(
".Looop_%=:"
"\n { in %4,res[%0] ; and %3,%3,%5 }"
"\n stw %4,%1[%3]"
"\n { lsu %5,%3,%2 ; add %3,%3,1 }"
"\n { neg %5,%5 ; bu .Looop_%= }"
// %0 %1 %2 %3 %4 %5
::"r"(p),"r"(ptr),"r"(max),"r"(idx),"r"(val),"r"(test));
}
if this is a 4 bits ports configured in buffered mode (as in this example) then the theoretical sampling frequency could be 240mhz (30 x 32/4).
if it is 8 bits port, the routine should be ok up to 120mhz (default reference clock here).
fyi some tips here:
the first asm volatile is used to fool the compiler and to effectively allocate 3 temporary registers, used in the next asm statement.
the lsu instruction returns 1 as long as the idx is below max, then the neg instruction provides FFFFFFFF
when idx==max, lsu return 0 and then neg will return 0 as well, which will reset idx with the and instruction bundled with in.
max should be size of buffer - 1
remark : the only way to stop this loop is to use an event from a timer or a channel.
if this is needed, then this routine can be called in the default case of a select statement.
but then it is required to add
Code: Select all
asm volatile("setsr 1");
hope this helps