Comment 5 for bug 1379250

Revision history for this message
demiurg_spb (demiurg-spb-h) wrote :

Thank you very much!
Allow me to share the results!
The function delay_cycles generates a delay with an accuracy of 1 clock cycle:

delay.h:
...
//=============================================================================
static __is_always_inline void delay_4cycles(uint32_t cy) // +1 cycle
{
 #if ARCH_PIPELINE_RELOAD_CYCLES<2
 # define EXTRA_NOP_CYCLES "nop"
 #else
 # define EXTRA_NOP_CYCLES ""
 #endif

 __asm__ __volatile__
 (
  ".syntax unified" "\n\t" // is to prevent CM0,CM1 non-unified sintax
  "loop%=:" "\n\t"
  " subs %[cnt],#1" "\n\t"
          EXTRA_NOP_CYCLES "\n\t"
  " bne loop%=" "\n\t"
  : [cnt]"+r"(cy) // output: +r means input+output http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
  : // input:
  : "cc" // clobbers:
 );
}

//=============================================================================
static __is_always_inline void delay_cycles(uint32_t x)
{
 #define MAXNOPS 4 // delay_4cycles
 if (x<=MAXNOPS)
 {
  if (x==1) {nop();}
  else if (x==2) {nop(); nop();}
  else if (x==3) {nop(); nop(); nop();}
  else if (x==4) {nop(); nop(); nop(); nop();}
 }
 else // because of +1 cycle inside delay_4cycles
 {
   uint32_t rem = (x-1)%MAXNOPS;
   if (rem==1) {nop();}
   else if (rem==2) {nop(); nop();}
   else if (rem==3) {nop(); nop(); nop();}
   if ((x=(x-1)/MAXNOPS)) delay_4cycles(x); // if need more then 4 nop loop is more optimal
 }
}