Line 149... |
Line 149... |
union {
|
union {
|
uint64_t uint64;
|
uint64_t uint64;
|
uint32_t uint32[sizeof(uint64_t)/2];
|
uint32_t uint32[sizeof(uint64_t)/2];
|
} cycles;
|
} cycles;
|
|
|
uint32_t tmp1, tmp2, tmp3;
|
register uint32_t tmp1, tmp2, tmp3;
|
while(1) {
|
while(1) {
|
tmp1 = neorv32_cpu_csr_read(CSR_CYCLEH);
|
tmp1 = neorv32_cpu_csr_read(CSR_CYCLEH);
|
tmp2 = neorv32_cpu_csr_read(CSR_CYCLE);
|
tmp2 = neorv32_cpu_csr_read(CSR_CYCLE);
|
tmp3 = neorv32_cpu_csr_read(CSR_CYCLEH);
|
tmp3 = neorv32_cpu_csr_read(CSR_CYCLEH);
|
if (tmp1 == tmp3) {
|
if (tmp1 == tmp3) {
|
Line 200... |
Line 200... |
union {
|
union {
|
uint64_t uint64;
|
uint64_t uint64;
|
uint32_t uint32[sizeof(uint64_t)/2];
|
uint32_t uint32[sizeof(uint64_t)/2];
|
} cycles;
|
} cycles;
|
|
|
uint32_t tmp1, tmp2, tmp3;
|
register uint32_t tmp1, tmp2, tmp3;
|
while(1) {
|
while(1) {
|
tmp1 = neorv32_cpu_csr_read(CSR_INSTRETH);
|
tmp1 = neorv32_cpu_csr_read(CSR_INSTRETH);
|
tmp2 = neorv32_cpu_csr_read(CSR_INSTRET);
|
tmp2 = neorv32_cpu_csr_read(CSR_INSTRET);
|
tmp3 = neorv32_cpu_csr_read(CSR_INSTRETH);
|
tmp3 = neorv32_cpu_csr_read(CSR_INSTRETH);
|
if (tmp1 == tmp3) {
|
if (tmp1 == tmp3) {
|
Line 251... |
Line 251... |
union {
|
union {
|
uint64_t uint64;
|
uint64_t uint64;
|
uint32_t uint32[sizeof(uint64_t)/2];
|
uint32_t uint32[sizeof(uint64_t)/2];
|
} cycles;
|
} cycles;
|
|
|
uint32_t tmp1, tmp2, tmp3;
|
register uint32_t tmp1, tmp2, tmp3;
|
while(1) {
|
while(1) {
|
tmp1 = neorv32_cpu_csr_read(CSR_TIMEH);
|
tmp1 = neorv32_cpu_csr_read(CSR_TIMEH);
|
tmp2 = neorv32_cpu_csr_read(CSR_TIME);
|
tmp2 = neorv32_cpu_csr_read(CSR_TIME);
|
tmp3 = neorv32_cpu_csr_read(CSR_TIMEH);
|
tmp3 = neorv32_cpu_csr_read(CSR_TIMEH);
|
if (tmp1 == tmp3) {
|
if (tmp1 == tmp3) {
|
Line 269... |
Line 269... |
return cycles.uint64;
|
return cycles.uint64;
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Simple delay function using busy wait (simple loop).
|
* Delay function using busy wait.
|
*
|
*
|
* @warning This function is not really precise (especially if there is no M extension available)! Use a timer-based approach (using cycle or time CSRs) for precise timings.
|
* @note This function uses the time CSRs (from int./ext. MTIME). A simple ASM loop
|
|
* is used as fall back if system timer is not advancing (no MTIME available).
|
*
|
*
|
* @param[in] time_ms Time in ms to wait (max 32767ms).
|
* @warning Delay time might be less precise if M extensions is not available
|
|
* (especially if MTIME unit is not available).
|
|
*
|
|
* @param[in] time_ms Time in ms to wait (unsigned 32-bit).
|
**************************************************************************/
|
**************************************************************************/
|
void neorv32_cpu_delay_ms(int16_t time_ms) {
|
void neorv32_cpu_delay_ms(uint32_t time_ms) {
|
|
|
const uint32_t loop_cycles_c = 16; // clock cycles per iteration of the ASM loop
|
|
|
|
// check input
|
|
if (time_ms < 0) {
|
|
time_ms = -time_ms;
|
|
}
|
|
|
|
uint32_t clock = SYSINFO_CLK; // clock ticks per second
|
uint32_t clock = NEORV32_SYSINFO.CLK; // clock ticks per second
|
clock = clock / 1000; // clock ticks per ms
|
clock = clock / 1000; // clock ticks per ms
|
|
|
uint64_t wait_cycles = ((uint64_t)clock) * ((uint64_t)time_ms);
|
uint64_t wait_cycles = ((uint64_t)clock) * ((uint64_t)time_ms);
|
uint32_t ticks = (uint32_t)(wait_cycles / loop_cycles_c);
|
|
|
register uint64_t tmp = neorv32_cpu_get_systime();
|
|
if (neorv32_cpu_get_systime() > tmp) { // system time advancing (MTIME available and running)?
|
|
|
|
// use MTIME machine timer
|
|
tmp += wait_cycles;
|
|
while(1) {
|
|
if (neorv32_cpu_get_systime() >= tmp) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// use ASM loop
|
|
// warning! not really precise (especially if M extensions is not available)!
|
|
|
|
const uint32_t loop_cycles_c = 16; // clock cycles per iteration of the ASM loop
|
|
uint32_t iterations = (uint32_t)(wait_cycles / loop_cycles_c);
|
|
|
asm volatile (" .balign 4 \n" // make sure this is 32-bit aligned
|
asm volatile (" .balign 4 \n" // make sure this is 32-bit aligned
|
" __neorv32_cpu_delay_ms_start: \n"
|
" __neorv32_cpu_delay_ms_start: \n"
|
" beq %[cnt_r], zero, __neorv32_cpu_delay_ms_end \n" // 3 cycles (not taken)
|
" beq %[cnt_r], zero, __neorv32_cpu_delay_ms_end \n" // 3 cycles (not taken)
|
" beq %[cnt_r], zero, __neorv32_cpu_delay_ms_end \n" // 3 cycles (never taken)
|
" beq %[cnt_r], zero, __neorv32_cpu_delay_ms_end \n" // 3 cycles (never taken)
|
" addi %[cnt_w], %[cnt_r], -1 \n" // 2 cycles
|
" addi %[cnt_w], %[cnt_r], -1 \n" // 2 cycles
|
" nop \n" // 2 cycles
|
" nop \n" // 2 cycles
|
" j __neorv32_cpu_delay_ms_start \n" // 6 cycles
|
" j __neorv32_cpu_delay_ms_start \n" // 6 cycles
|
" __neorv32_cpu_delay_ms_end: "
|
" __neorv32_cpu_delay_ms_end: "
|
: [cnt_w] "=r" (ticks) : [cnt_r] "r" (ticks));
|
: [cnt_w] "=r" (iterations) : [cnt_r] "r" (iterations));
|
|
}
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Switch from privilege mode MACHINE to privilege mode USER.
|
* Switch from privilege mode MACHINE to privilege mode USER.
|
Line 330... |
Line 345... |
* @return Returns number of available PMP regions.
|
* @return Returns number of available PMP regions.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t neorv32_cpu_pmp_get_num_regions(void) {
|
uint32_t neorv32_cpu_pmp_get_num_regions(void) {
|
|
|
// PMP implemented at all?
|
// PMP implemented at all?
|
if ((SYSINFO_CPU & (1<<SYSINFO_CPU_PMP)) == 0) {
|
if ((NEORV32_SYSINFO.CPU & (1<<SYSINFO_CPU_PMP)) == 0) {
|
return 0;
|
return 0;
|
}
|
}
|
|
|
uint32_t i = 0;
|
uint32_t i = 0;
|
|
|
Line 595... |
Line 610... |
* @return Returns number of available HPM counters (0..29).
|
* @return Returns number of available HPM counters (0..29).
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t neorv32_cpu_hpm_get_counters(void) {
|
uint32_t neorv32_cpu_hpm_get_counters(void) {
|
|
|
// HPMs implemented at all?
|
// HPMs implemented at all?
|
if ((SYSINFO_CPU & (1<<SYSINFO_CPU_HPM)) == 0) {
|
if ((NEORV32_SYSINFO.CPU & (1<<SYSINFO_CPU_HPM)) == 0) {
|
return 0;
|
return 0;
|
}
|
}
|
|
|
// inhibit all HPM counters
|
// inhibit all HPM counters
|
uint32_t tmp = neorv32_cpu_csr_read(CSR_MCOUNTINHIBIT);
|
uint32_t tmp = neorv32_cpu_csr_read(CSR_MCOUNTINHIBIT);
|
Line 678... |
Line 693... |
* @return Size of HPM counter bits (1-64, 0 if not implemented at all).
|
* @return Size of HPM counter bits (1-64, 0 if not implemented at all).
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t neorv32_cpu_hpm_get_size(void) {
|
uint32_t neorv32_cpu_hpm_get_size(void) {
|
|
|
// HPMs implemented at all?
|
// HPMs implemented at all?
|
if ((SYSINFO_CPU & (1<<SYSINFO_CPU_HPM)) == 0) {
|
if ((NEORV32_SYSINFO.CPU & (1<<SYSINFO_CPU_HPM)) == 0) {
|
return 0;
|
return 0;
|
}
|
}
|
|
|
// inhibt auto-update
|
// inhibt auto-update
|
asm volatile ("csrwi %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_HPM3));
|
asm volatile ("csrwi %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_HPM3));
|