Line 269... |
Line 269... |
return cycles.uint64;
|
return cycles.uint64;
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Simple delay function using busy wait.
|
* Simple delay function using busy wait (simple loop).
|
*
|
*
|
* @warning This function requires the cycle CSR(s). Hence, the Zicsr extension is mandatory.
|
* @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.
|
*
|
*
|
* @param[in] time_ms Time in ms to wait.
|
* @param[in] time_ms Time in ms to wait (max 32767ms).
|
**************************************************************************/
|
**************************************************************************/
|
void neorv32_cpu_delay_ms(uint32_t time_ms) {
|
void neorv32_cpu_delay_ms(int16_t time_ms) {
|
|
|
uint64_t time_resume = neorv32_cpu_get_cycle();
|
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 = 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);
|
time_resume += wait_cycles;
|
uint32_t ticks = (uint32_t)(wait_cycles / loop_cycles_c);
|
|
|
while(1) {
|
asm volatile (" .balign 4 \n" // make sure this is 32-bit aligned
|
if (neorv32_cpu_get_cycle() >= time_resume) {
|
" __neorv32_cpu_delay_ms_start: \n"
|
break;
|
" 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)
|
}
|
" addi %[cnt_w], %[cnt_r], -1 \n" // 2 cycles
|
|
" nop \n" // 2 cycles
|
|
" j __neorv32_cpu_delay_ms_start \n" // 6 cycles
|
|
" __neorv32_cpu_delay_ms_end: "
|
|
: [cnt_w] "=r" (ticks) : [cnt_r] "r" (ticks));
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Switch from privilege mode MACHINE to privilege mode USER.
|
* Switch from privilege mode MACHINE to privilege mode USER.
|
Line 302... |
Line 311... |
**************************************************************************/
|
**************************************************************************/
|
void __attribute__((naked)) neorv32_cpu_goto_user_mode(void) {
|
void __attribute__((naked)) neorv32_cpu_goto_user_mode(void) {
|
|
|
// make sure to use NO registers in here! -> naked
|
// make sure to use NO registers in here! -> naked
|
|
|
asm volatile ("csrw mepc, ra \n\t" // move return address to mepc so we can return using "mret". also, we can now use ra as general purpose register in here
|
asm volatile ("csrw mepc, ra \n" // move return address to mepc so we can return using "mret". also, we can now use ra as general purpose register in here
|
"li ra, %[input_imm] \n\t" // bit mask to clear the two MPP bits
|
"li ra, %[input_imm] \n" // bit mask to clear the two MPP bits
|
"csrrc zero, mstatus, ra \n\t" // clear MPP bits -> MPP=u-mode
|
"csrrc zero, mstatus, ra \n" // clear MPP bits -> MPP=u-mode
|
"mret \n\t" // return and switch to user mode
|
"mret \n" // return and switch to user mode
|
: : [input_imm] "i" ((1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L)));
|
: : [input_imm] "i" ((1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L)));
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
Line 619... |
Line 628... |
*
|
*
|
* @return Returns number of available HPM counters (..29).
|
* @return Returns number of available HPM counters (..29).
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t neorv32_cpu_hpm_get_counters(void) {
|
uint32_t neorv32_cpu_hpm_get_counters(void) {
|
|
|
|
// inhibit all HPM counters
|
|
uint32_t tmp = neorv32_cpu_csr_read(CSR_MCOUNTINHIBIT);
|
|
tmp |= 0xfffffff8;
|
|
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, tmp);
|
|
|
// try setting all mhpmcounter* CSRs to 1
|
// try setting all mhpmcounter* CSRs to 1
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER3, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER3, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER4, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER4, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER5, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER5, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER6, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER6, 1);
|
Line 648... |
Line 662... |
neorv32_cpu_csr_write(CSR_MHPMCOUNTER26, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER26, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER27, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER27, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER28, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER28, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER29, 1);
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER29, 1);
|
|
|
// sum up all written ones (only available PMPCFG* CSRs/entries will return =! 0)
|
// sum up all written ones (only available HPM counter CSRs will return =! 0)
|
uint32_t num_hpm_cnts = 0;
|
uint32_t num_hpm_cnts = 0;
|
|
|
num_hpm_cnts += neorv32_cpu_csr_read(CSR_MHPMCOUNTER3);
|
num_hpm_cnts += neorv32_cpu_csr_read(CSR_MHPMCOUNTER3);
|
num_hpm_cnts += neorv32_cpu_csr_read(CSR_MHPMCOUNTER4);
|
num_hpm_cnts += neorv32_cpu_csr_read(CSR_MHPMCOUNTER4);
|
num_hpm_cnts += neorv32_cpu_csr_read(CSR_MHPMCOUNTER5);
|
num_hpm_cnts += neorv32_cpu_csr_read(CSR_MHPMCOUNTER5);
|
Line 684... |
Line 698... |
return num_hpm_cnts;
|
return num_hpm_cnts;
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
|
* Hardware performance monitors (HPM): Get total counter width
|
|
*
|
|
* @warning This function overrides mhpmcounter3[h] CSRs.
|
|
*
|
|
* @return Size of HPM counter bits (1-64).
|
|
**************************************************************************/
|
|
uint32_t neorv32_cpu_hpm_get_size(void) {
|
|
|
|
// inhibt auto-update
|
|
asm volatile ("csrwi %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTEREN_HPM3));
|
|
|
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER3, 0xffffffff);
|
|
neorv32_cpu_csr_write(CSR_MHPMCOUNTER3H, 0xffffffff);
|
|
|
|
uint32_t tmp, size, i;
|
|
|
|
if (neorv32_cpu_csr_read(CSR_MHPMCOUNTER3H) == 0) {
|
|
size = 0;
|
|
tmp = neorv32_cpu_csr_read(CSR_MHPMCOUNTER3);
|
|
}
|
|
else {
|
|
size = 32;
|
|
tmp = neorv32_cpu_csr_read(CSR_MHPMCOUNTER3H);
|
|
}
|
|
|
|
for (i=0; i<32; i++) {
|
|
if (tmp & (1<<i)) {
|
|
size++;
|
|
}
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
* Check if certain Z* extension is available
|
* Check if certain Z* extension is available
|
*
|
*
|
* @param[in] flag Index of the Z-extension to check from #NEORV32_CSR_MZEXT_enum
|
* @param[in] flag Index of the Z-extension to check from #NEORV32_CSR_MZEXT_enum
|
* @return 0 if extension is NOT available, != 0 if extension is available.
|
* @return 0 if extension is NOT available, != 0 if extension is available.
|
**************************************************************************/
|
**************************************************************************/
|