text: /* See LICENSE file for license and copyright information */
  
  #ifndef ARM_V8_TIMING_H
  #define ARM_V8_TIMING_H
  
  #include <stdint.h>
  
  #define ARMV8_PMCR_E            (1 << 0) /* Enable all counters */
  #define ARMV8_PMCR_P            (1 << 1) /* Reset all counters */
  #define ARMV8_PMCR_C            (1 << 2) /* Cycle counter reset */
  
  #define ARMV8_PMUSERENR_EN      (1 << 0) /* EL0 access enable */
  #define ARMV8_PMUSERENR_CR      (1 << 2) /* Cycle counter read enable */
  #define ARMV8_PMUSERENR_ER      (1 << 3) /* Event counter read enable */
  
  #define ARMV8_PMCNTENSET_EL0_EN (1 << 31) /* Performance Monitors Count Enable Set register */
  
  uint64_t time_start;
  float t;
  
  #define START_TIMING time_start = arm_v8_get_timing();
  
  #define STOP_TIMING                       \
      t  = (float)arm_v8_get_timing();      \
      t -= (float)time_start;               \
      t /=  1200000;                        \
      printf("TIMING: %f ms \n\r", t);
  
  // #define STOP_TIMING  printf("TIMING: %lu cycles %f ms \n\r", (uint64_t)(arm_v8_get_timing()-time_start), (float)((arm_v8_get_timing()-time_start)/1200000));
  
  
  static inline uint64_t arm_v8_get_timing(void)
  {
    uint64_t result = 0;
  
    asm volatile("MRS %0, PMCCNTR_EL0" : "=r" (result));
  
    return result;
  }
  
  static inline void arm_v8_timing_init(void)
  {
    uint32_t value = 0;
  
    /* Enable Performance Counter */
    asm volatile("MRS %0, PMCR_EL0" : "=r" (value));
    value |= ARMV8_PMCR_E; /* Enable */
    value |= ARMV8_PMCR_C; /* Cycle counter reset */
    value |= ARMV8_PMCR_P; /* Reset all counters */
    asm volatile("MSR PMCR_EL0, %0" : : "r" (value));
  
    /* Enable cycle counter register */
    asm volatile("MRS %0, PMCNTENSET_EL0" : "=r" (value));
    value |= ARMV8_PMCNTENSET_EL0_EN;
    asm volatile("MSR PMCNTENSET_EL0, %0" : : "r" (value));
  }
  
  static inline void arm_v8_timing_terminate(void)
  {
    uint32_t value = 0;
    uint32_t mask = 0;
  
    /* Disable Performance Counter */
    asm volatile("MRS %0, PMCR_EL0" : "=r" (value));
    mask = 0;
    mask |= ARMV8_PMCR_E; /* Enable */
    mask |= ARMV8_PMCR_C; /* Cycle counter reset */
    mask |= ARMV8_PMCR_P; /* Reset all counters */
    asm volatile("MSR PMCR_EL0, %0" : : "r" (value & ~mask));
  
    /* Disable cycle counter register */
    asm volatile("MRS %0, PMCNTENSET_EL0" : "=r" (value));
    mask = 0;
    mask |= ARMV8_PMCNTENSET_EL0_EN;
    asm volatile("MSR PMCNTENSET_EL0, %0" : : "r" (value & ~mask));
  }
  
  static inline void arm_v8_reset_timing(void)
  {
    uint32_t value = 0;
    asm volatile("MRS %0, PMCR_EL0" : "=r" (value));
    value |= ARMV8_PMCR_C; /* Cycle counter reset */
    asm volatile("MSR PMCR_EL0, %0" : : "r" (value));
  }
  
  #endif  /*ARM_V8_TIMING_H*/
  