tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/delay/sleep.c (about)

     1  #include <stdint.h>
     2  #include <stdbool.h>
     3  
     4  // Loop the given times, where one loop takes four CPU cycles.
     5  bool tinygo_drivers_sleep(uint32_t cycles) {
     6      // In this function, a [n] comment indicates the number of cycles an
     7      // instruction or a set of instructions take. This is typically 1 for most
     8      // arithmetic instructions, and a bit more for branches.
     9  #if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__
    10      // Inline assembly for Cortex-M0/M0+/M3/M4/M7.
    11      // The Cortex-M0 (but not M0+) takes one more cycle, so is off by 12.5%.
    12      // Others should be basically cycle-accurate (with a slight overhead to
    13      // calculate the number of cycles). Unfortunately, there doesn't appear to
    14      // be a preprocessor macro to detect the Cortex-M0 specifically (although we
    15      // could rely on macros like NRF51).
    16  
    17      // Each loop takes 8 cycles (5 nops, 1 sub, and 2 for the branch).
    18      uint32_t loops = (cycles + 7) / 8;
    19      __asm__ __volatile__(
    20          "1:\n\t"
    21          "nop\n\t"               // [5] nops
    22          "nop\n\t"
    23          "nop\n\t"
    24          "nop\n\t"
    25          "nop\n\t"
    26          "subs %[loops], #1\n\t" // [1]
    27          "bne 1b"                // [1-4], at least 2 cycles if taken
    28          : [loops]"+r"(loops)
    29      );
    30      return true;
    31  #elif __XTENSA__
    32      // Inline assembly for Xtensa.
    33      // I don't know exactly how many cycles a branch takes, so I've taken a
    34      // conservative guess and assume it takes only one cycle. In practice, it's
    35      // probably more than that.
    36      uint32_t loops = (cycles + 7) / 8;
    37      __asm__ __volatile__(
    38          "1:\n\t"
    39          "nop\n\t"                         // [6] nops
    40          "nop\n\t"
    41          "nop\n\t"
    42          "nop\n\t"
    43          "nop\n\t"
    44          "nop\n\t"
    45          "addi %[loops], %[loops], -1\n\t" // [1]
    46          "bnez %[loops], 1b"               // [1?]
    47          : [loops]"+r"(loops)
    48      );
    49      return true;
    50  #else
    51      // Unknown architecture, so fall back to time.Sleep.
    52      return false;
    53  #endif
    54  }