Line 42... |
Line 42... |
#include "neorv32.h"
|
#include "neorv32.h"
|
#include "neorv32_cpu.h"
|
#include "neorv32_cpu.h"
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Put CPU into "sleep" mode.
|
* Enable/disable CPU extension during runtime via the 'misa' CSR.
|
*
|
*
|
* @note This function executes the WFI insstruction.
|
* @warning This is still highly experimental! This function requires the Zicsr + Zifencei CPU extensions.
|
* The WFI (wait for interrupt) instruction will make the CPU stall until
|
*
|
* an interupt request is detected. Interrupts have to be globally enabled
|
* @param[in] sel Bit to be set in misa CSR / extension to be enabled. See #NEORV32_CPU_MISA_enum.
|
* and at least one external source must be enabled (e.g., the CLIC or the machine
|
* @param[in] state Set 1 to enable the selected extension, set 0 to disable it;
|
* timer) to allow the CPU to wake up again. If 'Zicsr' CPU extension is disabled,
|
* return 0 if success, 1 if error (invalid sel or extension cannot be enabled).
|
* this will permanently stall the CPU.
|
**************************************************************************/
|
**************************************************************************/
|
int neorv32_cpu_switch_extension(int sel, int state) {
|
void neorv32_cpu_sleep(void) {
|
|
|
// get current misa setting
|
|
uint32_t misa_curr = neorv32_cpu_csr_read(CSR_MISA);
|
|
uint32_t misa_prev = misa_curr;
|
|
|
asm volatile ("wfi");
|
// abort if misa.z is cleared
|
|
if ((misa_curr & (1 << CPU_MISA_Z_EXT)) == 0) {
|
|
return 1;
|
}
|
}
|
|
|
|
// out of range?
|
/**********************************************************************//**
|
if (sel > 25) {
|
* Enable global CPU interrupts (via MIE flag in mstatus CSR).
|
return 1;
|
**************************************************************************/
|
|
void neorv32_cpu_eint(void) {
|
|
|
|
const int mask = 1 << CPU_MSTATUS_MIE;
|
|
asm volatile ("csrrsi zero, mstatus, %0" : : "i" (mask));
|
|
}
|
}
|
|
|
|
// enable/disable selected extension
|
|
if (state & 1) {
|
|
misa_curr |= (1 << sel);
|
|
}
|
|
else {
|
|
misa_curr &= ~(1 << sel);
|
|
}
|
|
|
/**********************************************************************//**
|
// try updating misa
|
* Disable global CPU interrupts (via MIE flag in mstatus CSR).
|
neorv32_cpu_csr_write(CSR_MISA, misa_curr);
|
**************************************************************************/
|
asm volatile("fence.i"); // required to flush prefetch buffers
|
void neorv32_cpu_dint(void) {
|
asm volatile("nop");
|
|
|
const int mask = 1 << CPU_MSTATUS_MIE;
|
// dit it work?
|
asm volatile ("csrrci zero, mstatus, %0" : : "i" (mask));
|
if (neorv32_cpu_csr_read(CSR_MISA) == misa_prev) {
|
|
return 1; // nope
|
|
}
|
|
else {
|
|
return 0; // fine
|
|
}
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Enable specific CPU interrupt.
|
* Enable specific CPU interrupt.
|
Line 116... |
Line 128... |
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Trigger machine software interrupt.
|
|
*
|
|
* @note The according IRQ has to be enabled via neorv32_cpu_irq_enable(uint8_t irq_sel) and
|
|
* global interrupts must be enabled via neorv32_cpu_eint(void) to trigger an IRQ via software.
|
|
**************************************************************************/
|
|
void neorv32_cpu_sw_irq(void) {
|
|
|
|
register uint32_t mask = (uint32_t)(1 << CPU_MIP_MSIP);
|
|
asm volatile ("csrrs zero, mip, %0" : : "r" (mask));
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Trigger breakpoint exception (via EBREAK instruction).
|
|
**************************************************************************/
|
|
void neorv32_cpu_breakpoint(void) {
|
|
|
|
asm volatile ("ebreak");
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Trigger "environment call" exception (via ECALL instruction).
|
|
**************************************************************************/
|
|
void neorv32_cpu_env_call(void) {
|
|
|
|
asm volatile ("ecall");
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Simple delay function (not very precise) using busy wait.
|
* Simple delay function (not very precise) using busy wait.
|
*
|
*
|
* @param[in] time_ms Time in ms to wait.
|
* @param[in] time_ms Time in ms to wait.
|
**************************************************************************/
|
**************************************************************************/
|
void neorv32_cpu_delay_ms(uint32_t time_ms) {
|
void neorv32_cpu_delay_ms(uint32_t time_ms) {
|