added [m]instret[h] and [m]cycle[h] access functions; make mtime read access roll-over safe

This commit is contained in:
stnolting 2020-07-11 13:07:30 +02:00
parent 16fd74de3f
commit b3655e5afb
3 changed files with 138 additions and 4 deletions

View file

@ -45,6 +45,10 @@
// prototypes
int neorv32_cpu_irq_enable(uint8_t irq_sel);
int neorv32_cpu_irq_disable(uint8_t irq_sel);
uint64_t neorv32_cpu_get_cycle(void);
void neorv32_cpu_set_mcycle(uint32_t value);
uint64_t neorv32_cpu_get_instret(void);
void neorv32_cpu_set_minstret(uint32_t value);
void neorv32_cpu_delay_ms(uint32_t time_ms);

View file

@ -49,7 +49,7 @@
* @note Interrupts have to be globally enabled via neorv32_cpu_eint(void), too.
*
* @param[in] irq_sel CPU interrupt select. See #NEORV32_CPU_MIE_enum.
* return 0 if success, 1 if error (invalid irq_sel).
* @return 0 if success, 1 if error (invalid irq_sel).
**************************************************************************/
int neorv32_cpu_irq_enable(uint8_t irq_sel) {
@ -67,7 +67,7 @@ int neorv32_cpu_irq_enable(uint8_t irq_sel) {
* Disable specific CPU interrupt.
*
* @param[in] irq_sel CPU interrupt select. See #NEORV32_CPU_MIE_enum.
* return 0 if success, 1 if error (invalid irq_sel).
* @return 0 if success, 1 if error (invalid irq_sel).
**************************************************************************/
int neorv32_cpu_irq_disable(uint8_t irq_sel) {
@ -81,6 +81,108 @@ int neorv32_cpu_irq_disable(uint8_t irq_sel) {
}
/**********************************************************************//**
* Get cycle count from cycle[h].
*
* @note The cycle[h] CSR is shadowed copy of the mcycle[h] CSR.
*
* @return Current cycle counter (64 bit).
**************************************************************************/
uint64_t neorv32_cpu_get_cycle(void) {
union {
uint64_t uint64;
uint32_t uint32[sizeof(uint64_t)/2];
} cycles;
uint32_t tmp1, tmp2, tmp3;
while(1) {
tmp1 = neorv32_cpu_csr_read(CSR_CYCLEH);
tmp2 = neorv32_cpu_csr_read(CSR_CYCLE);
tmp3 = neorv32_cpu_csr_read(CSR_CYCLEH);
if (tmp1 == tmp3) {
break;
}
}
cycles.uint32[0] = tmp2;
cycles.uint32[1] = tmp3;
return cycles.uint64;
}
/**********************************************************************//**
* Set mcycle[h] counter.
*
* @param[in] value New value for mcycle[h] CSR (64-bit).
**************************************************************************/
void neorv32_cpu_set_mcycle(uint32_t value) {
union {
uint64_t uint64;
uint32_t uint32[sizeof(uint64_t)/2];
} cycles;
cycles.uint64 = value;
neorv32_cpu_csr_write(CSR_MCYCLE, 0);
neorv32_cpu_csr_write(CSR_MCYCLEH, cycles.uint32[1]);
neorv32_cpu_csr_write(CSR_MCYCLE, cycles.uint32[0]);
}
/**********************************************************************//**
* Get retired instructions counter from instret[h].
*
* @note The instret[h] CSR is shadowed copy of the instret[h] CSR.
*
* @return Current instructions counter (64 bit).
**************************************************************************/
uint64_t neorv32_cpu_get_instret(void) {
union {
uint64_t uint64;
uint32_t uint32[sizeof(uint64_t)/2];
} cycles;
uint32_t tmp1, tmp2, tmp3;
while(1) {
tmp1 = neorv32_cpu_csr_read(CSR_INSTRETH);
tmp2 = neorv32_cpu_csr_read(CSR_INSTRET);
tmp3 = neorv32_cpu_csr_read(CSR_INSTRETH);
if (tmp1 == tmp3) {
break;
}
}
cycles.uint32[0] = tmp2;
cycles.uint32[1] = tmp3;
return cycles.uint64;
}
/**********************************************************************//**
* Set retired instructions counter minstret[h].
*
* @param[in] value New value for mcycle[h] CSR (64-bit).
**************************************************************************/
void neorv32_cpu_set_minstret(uint32_t value) {
union {
uint64_t uint64;
uint32_t uint32[sizeof(uint64_t)/2];
} cycles;
cycles.uint64 = value;
neorv32_cpu_csr_write(CSR_MINSTRET, 0);
neorv32_cpu_csr_write(CSR_MINSTRETH, cycles.uint32[1]);
neorv32_cpu_csr_write(CSR_MINSTRET, cycles.uint32[0]);
}
/**********************************************************************//**
* Simple delay function (not very precise) using busy wait.
*

View file

@ -70,7 +70,17 @@ int neorv32_mtime_available(void) {
**************************************************************************/
void neorv32_mtime_set_time(uint64_t time) {
MTIME = time;
union {
uint64_t uint64;
uint32_t uint32[sizeof(uint64_t)/2];
} cycles;
cycles.uint64 = time;
MTIME_LO = 0;
MTIME_HI = cycles.uint32[1];
MTIME_LO = cycles.uint32[0];
}
@ -83,7 +93,25 @@ void neorv32_mtime_set_time(uint64_t time) {
**************************************************************************/
uint64_t neorv32_mtime_get_time(void) {
return MTIME;
union {
uint64_t uint64;
uint32_t uint32[sizeof(uint64_t)/2];
} cycles;
uint32_t tmp1, tmp2, tmp3;
while(1) {
tmp1 = MTIME_HI;
tmp2 = MTIME_LO;
tmp3 = MTIME_HI;
if (tmp1 == tmp3) {
break;
}
}
cycles.uint32[0] = tmp2;
cycles.uint32[1] = tmp3;
return cycles.uint64;
}