mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-23 21:57:33 -04:00
added function for enabling/disabling CPU extensions (experimental!); optimized some functions to be always inlined
This commit is contained in:
parent
5e8b242911
commit
e643751244
2 changed files with 107 additions and 61 deletions
|
@ -43,14 +43,9 @@
|
|||
#define neorv32_cpu_h
|
||||
|
||||
// prototypes
|
||||
void neorv32_cpu_sleep(void);
|
||||
void neorv32_cpu_eint(void);
|
||||
void neorv32_cpu_dint(void);
|
||||
int neorv32_cpu_switch_extension(int sel, int state);
|
||||
int neorv32_cpu_irq_enable(uint8_t irq_sel);
|
||||
int neorv32_cpu_irq_disable(uint8_t irq_sel);
|
||||
void neorv32_cpu_sw_irq(void);
|
||||
void neorv32_cpu_breakpoint(void);
|
||||
void neorv32_cpu_env_call(void);
|
||||
void neorv32_cpu_delay_ms(uint32_t time_ms);
|
||||
|
||||
|
||||
|
@ -83,4 +78,74 @@ inline void __attribute__ ((always_inline)) neorv32_cpu_csr_write(const int csr_
|
|||
asm volatile ("csrw %[input_i], %[input_j]" : : [input_i] "i" (csr_id), [input_j] "r" (csr_data));
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Put CPU into "sleep" mode.
|
||||
*
|
||||
* @note This function executes the WFI insstruction.
|
||||
* The WFI (wait for interrupt) instruction will make the CPU stall until
|
||||
* an interupt request is detected. Interrupts have to be globally enabled
|
||||
* and at least one external source must be enabled (e.g., the CLIC or the machine
|
||||
* timer) to allow the CPU to wake up again. If 'Zicsr' CPU extension is disabled,
|
||||
* this will permanently stall the CPU.
|
||||
**************************************************************************/
|
||||
inline void __attribute__ ((always_inline)) neorv32_cpu_sleep(void) {
|
||||
|
||||
asm volatile ("wfi");
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Enable global CPU interrupts (via MIE flag in mstatus CSR).
|
||||
**************************************************************************/
|
||||
inline void __attribute__ ((always_inline)) neorv32_cpu_eint(void) {
|
||||
|
||||
asm volatile ("csrrsi zero, mstatus, %0" : : "i" (1 << CPU_MSTATUS_MIE));
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Disable global CPU interrupts (via MIE flag in mstatus CSR).
|
||||
**************************************************************************/
|
||||
inline void __attribute__ ((always_inline)) neorv32_cpu_dint(void) {
|
||||
|
||||
asm volatile ("csrrci zero, mstatus, %0" : : "i" (1 << CPU_MSTATUS_MIE));
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* 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.
|
||||
* The MSI becomes active after 3 clock cycles.
|
||||
**************************************************************************/
|
||||
inline void __attribute__ ((always_inline)) neorv32_cpu_sw_irq(void) {
|
||||
|
||||
asm volatile ("csrrsi zero, mip, %0" : : "i" (1 << CPU_MIP_MSIP));
|
||||
|
||||
// the MSI becomes active 3 clock cycles afters issueing
|
||||
asm volatile ("nop"); // these nops are not required, they just make sure the MSI becomes active
|
||||
asm volatile ("nop"); // before the "real" next operation is executed
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Trigger breakpoint exception (via EBREAK instruction).
|
||||
**************************************************************************/
|
||||
inline void __attribute__ ((always_inline)) neorv32_cpu_breakpoint(void) {
|
||||
|
||||
asm volatile ("ebreak");
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Trigger "environment call" exception (via ECALL instruction).
|
||||
**************************************************************************/
|
||||
inline void __attribute__ ((always_inline)) neorv32_cpu_env_call(void) {
|
||||
|
||||
asm volatile ("ecall");
|
||||
}
|
||||
|
||||
|
||||
#endif // neorv32_cpu_h
|
||||
|
|
|
@ -44,38 +44,50 @@
|
|||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Put CPU into "sleep" mode.
|
||||
* Enable/disable CPU extension during runtime via the 'misa' CSR.
|
||||
*
|
||||
* @note This function executes the WFI insstruction.
|
||||
* The WFI (wait for interrupt) instruction will make the CPU stall until
|
||||
* an interupt request is detected. Interrupts have to be globally enabled
|
||||
* and at least one external source must be enabled (e.g., the CLIC or the machine
|
||||
* timer) to allow the CPU to wake up again. If 'Zicsr' CPU extension is disabled,
|
||||
* this will permanently stall the CPU.
|
||||
* @warning This is still highly experimental! This function requires the Zicsr + Zifencei CPU extensions.
|
||||
*
|
||||
* @param[in] sel Bit to be set in misa CSR / extension to be enabled. See #NEORV32_CPU_MISA_enum.
|
||||
* @param[in] state Set 1 to enable the selected extension, set 0 to disable it;
|
||||
* return 0 if success, 1 if error (invalid sel or extension cannot be enabled).
|
||||
**************************************************************************/
|
||||
void neorv32_cpu_sleep(void) {
|
||||
int neorv32_cpu_switch_extension(int sel, int state) {
|
||||
|
||||
asm volatile ("wfi");
|
||||
}
|
||||
// get current misa setting
|
||||
uint32_t misa_curr = neorv32_cpu_csr_read(CSR_MISA);
|
||||
uint32_t misa_prev = misa_curr;
|
||||
|
||||
// abort if misa.z is cleared
|
||||
if ((misa_curr & (1 << CPU_MISA_Z_EXT)) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
* Enable global CPU interrupts (via MIE flag in mstatus CSR).
|
||||
**************************************************************************/
|
||||
void neorv32_cpu_eint(void) {
|
||||
// out of range?
|
||||
if (sel > 25) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
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
|
||||
neorv32_cpu_csr_write(CSR_MISA, misa_curr);
|
||||
asm volatile("fence.i"); // required to flush prefetch buffers
|
||||
asm volatile("nop");
|
||||
|
||||
/**********************************************************************//**
|
||||
* Disable global CPU interrupts (via MIE flag in mstatus CSR).
|
||||
**************************************************************************/
|
||||
void neorv32_cpu_dint(void) {
|
||||
|
||||
const int mask = 1 << CPU_MSTATUS_MIE;
|
||||
asm volatile ("csrrci zero, mstatus, %0" : : "i" (mask));
|
||||
// dit it work?
|
||||
if (neorv32_cpu_csr_read(CSR_MISA) == misa_prev) {
|
||||
return 1; // nope
|
||||
}
|
||||
else {
|
||||
return 0; // fine
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -117,37 +129,6 @@ int neorv32_cpu_irq_disable(uint8_t irq_sel) {
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* 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.
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue