summaryrefslogtreecommitdiff
path: root/libcpu
diff options
context:
space:
mode:
Diffstat (limited to 'libcpu')
-rw-r--r--libcpu/risc-v/SConscript3
-rw-r--r--libcpu/risc-v/nuclei/SConscript14
-rw-r--r--libcpu/risc-v/nuclei/context_gcc.S188
-rw-r--r--libcpu/risc-v/nuclei/cpuport.c259
-rw-r--r--libcpu/risc-v/nuclei/cpuport.h40
-rw-r--r--libcpu/risc-v/nuclei/interrupt_gcc.S218
6 files changed, 721 insertions, 1 deletions
diff --git a/libcpu/risc-v/SConscript b/libcpu/risc-v/SConscript
index 640e46a4fb..024cc5ba44 100644
--- a/libcpu/risc-v/SConscript
+++ b/libcpu/risc-v/SConscript
@@ -10,7 +10,8 @@ group = []
list = os.listdir(cwd)
# add common code files
-group = group + SConscript(os.path.join('common', 'SConscript'))
+if rtconfig.CPU != "nuclei":
+ group = group + SConscript(os.path.join('common', 'SConscript'))
# cpu porting code files
group = group + SConscript(os.path.join(rtconfig.CPU, 'SConscript'))
diff --git a/libcpu/risc-v/nuclei/SConscript b/libcpu/risc-v/nuclei/SConscript
new file mode 100644
index 0000000000..b0ae20ba02
--- /dev/null
+++ b/libcpu/risc-v/nuclei/SConscript
@@ -0,0 +1,14 @@
+# RT-Thread building script for component
+
+from building import *
+
+Import('rtconfig')
+
+cwd = GetCurrentDir()
+src = Glob('*.c') + Glob('*.cpp') + Glob('*_gcc.S')
+CPPPATH = [cwd]
+ASFLAGS = ''
+
+group = DefineGroup('cpu', src, depend = [''], CPPPATH = CPPPATH, ASFLAGS = ASFLAGS)
+
+Return('group')
diff --git a/libcpu/risc-v/nuclei/context_gcc.S b/libcpu/risc-v/nuclei/context_gcc.S
new file mode 100644
index 0000000000..fda453940d
--- /dev/null
+++ b/libcpu/risc-v/nuclei/context_gcc.S
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2019-Present Nuclei Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020/03/26 Huaqi First Nuclei RISC-V porting implementation
+ */
+
+#include "riscv_encoding.h"
+
+#ifndef __riscv_32e
+#define RT_SAVED_REGNUM 30
+#else
+#define RT_SAVED_REGNUM 14
+#endif
+
+#define RT_CONTEXT_SIZE (RT_SAVED_REGNUM * REGBYTES)
+
+ .extern rt_interrupt_from_thread
+ .extern rt_interrupt_to_thread
+
+
+.section .text
+
+
+/*
+ * void rt_hw_context_switch_to(rt_ubase_t to);
+ * a0 --> to_thread
+ */
+ .globl rt_hw_context_switch_to
+
+/* Start the first task. This also clears the bit that indicates the FPU is
+ in use in case the FPU was used before the scheduler was started - which
+ would otherwise result in the unnecessary leaving of space in the stack
+ for lazy saving of FPU registers. */
+.align 3
+rt_hw_context_switch_to:
+ /* Setup Interrupt Stack using
+ The stack that was used by main()
+ before the scheduler is started is
+ no longer required after the scheduler is started.
+ Interrupt stack pointer is stored in CSR_MSCRATCH */
+ la t0, _sp
+ csrw CSR_MSCRATCH, t0
+ LOAD sp, 0x0(a0) /* Read sp from first TCB member(a0) */
+
+ /* Pop PC from stack and set MEPC */
+ LOAD t0, 0 * REGBYTES(sp)
+ csrw CSR_MEPC, t0
+ /* Pop mstatus from stack and set it */
+ LOAD t0, (RT_SAVED_REGNUM - 1) * REGBYTES(sp)
+ csrw CSR_MSTATUS, t0
+ /* Interrupt still disable here */
+ /* Restore Registers from Stack */
+ LOAD x1, 1 * REGBYTES(sp) /* RA */
+ LOAD x5, 2 * REGBYTES(sp)
+ LOAD x6, 3 * REGBYTES(sp)
+ LOAD x7, 4 * REGBYTES(sp)
+ LOAD x8, 5 * REGBYTES(sp)
+ LOAD x9, 6 * REGBYTES(sp)
+ LOAD x10, 7 * REGBYTES(sp)
+ LOAD x11, 8 * REGBYTES(sp)
+ LOAD x12, 9 * REGBYTES(sp)
+ LOAD x13, 10 * REGBYTES(sp)
+ LOAD x14, 11 * REGBYTES(sp)
+ LOAD x15, 12 * REGBYTES(sp)
+#ifndef __riscv_32e
+ LOAD x16, 13 * REGBYTES(sp)
+ LOAD x17, 14 * REGBYTES(sp)
+ LOAD x18, 15 * REGBYTES(sp)
+ LOAD x19, 16 * REGBYTES(sp)
+ LOAD x20, 17 * REGBYTES(sp)
+ LOAD x21, 18 * REGBYTES(sp)
+ LOAD x22, 19 * REGBYTES(sp)
+ LOAD x23, 20 * REGBYTES(sp)
+ LOAD x24, 21 * REGBYTES(sp)
+ LOAD x25, 22 * REGBYTES(sp)
+ LOAD x26, 23 * REGBYTES(sp)
+ LOAD x27, 24 * REGBYTES(sp)
+ LOAD x28, 25 * REGBYTES(sp)
+ LOAD x29, 26 * REGBYTES(sp)
+ LOAD x30, 27 * REGBYTES(sp)
+ LOAD x31, 28 * REGBYTES(sp)
+#endif
+
+ addi sp, sp, RT_CONTEXT_SIZE
+
+ mret
+
+.align 2
+.global eclic_msip_handler
+eclic_msip_handler:
+ addi sp, sp, -RT_CONTEXT_SIZE
+ STORE x1, 1 * REGBYTES(sp) /* RA */
+ STORE x5, 2 * REGBYTES(sp)
+ STORE x6, 3 * REGBYTES(sp)
+ STORE x7, 4 * REGBYTES(sp)
+ STORE x8, 5 * REGBYTES(sp)
+ STORE x9, 6 * REGBYTES(sp)
+ STORE x10, 7 * REGBYTES(sp)
+ STORE x11, 8 * REGBYTES(sp)
+ STORE x12, 9 * REGBYTES(sp)
+ STORE x13, 10 * REGBYTES(sp)
+ STORE x14, 11 * REGBYTES(sp)
+ STORE x15, 12 * REGBYTES(sp)
+#ifndef __riscv_32e
+ STORE x16, 13 * REGBYTES(sp)
+ STORE x17, 14 * REGBYTES(sp)
+ STORE x18, 15 * REGBYTES(sp)
+ STORE x19, 16 * REGBYTES(sp)
+ STORE x20, 17 * REGBYTES(sp)
+ STORE x21, 18 * REGBYTES(sp)
+ STORE x22, 19 * REGBYTES(sp)
+ STORE x23, 20 * REGBYTES(sp)
+ STORE x24, 21 * REGBYTES(sp)
+ STORE x25, 22 * REGBYTES(sp)
+ STORE x26, 23 * REGBYTES(sp)
+ STORE x27, 24 * REGBYTES(sp)
+ STORE x28, 25 * REGBYTES(sp)
+ STORE x29, 26 * REGBYTES(sp)
+ STORE x30, 27 * REGBYTES(sp)
+ STORE x31, 28 * REGBYTES(sp)
+#endif
+ /* Push mstatus to stack */
+ csrr t0, CSR_MSTATUS
+ STORE t0, (RT_SAVED_REGNUM - 1) * REGBYTES(sp)
+
+ /* Push additional registers */
+
+ /* Store sp to task stack */
+ LOAD t0, rt_interrupt_from_thread
+ STORE sp, 0(t0)
+
+ csrr t0, CSR_MEPC
+ STORE t0, 0(sp)
+
+ jal rt_hw_taskswitch
+
+ /* Switch task context */
+ LOAD t0, rt_interrupt_to_thread
+ LOAD sp, 0x0(t0)
+
+ /* Pop PC from stack and set MEPC */
+ LOAD t0, 0 * REGBYTES(sp)
+ csrw CSR_MEPC, t0
+
+ /* Pop additional registers */
+
+ /* Pop mstatus from stack and set it */
+ LOAD t0, (RT_SAVED_REGNUM - 1) * REGBYTES(sp)
+ csrw CSR_MSTATUS, t0
+ /* Interrupt still disable here */
+ /* Restore Registers from Stack */
+ LOAD x1, 1 * REGBYTES(sp) /* RA */
+ LOAD x5, 2 * REGBYTES(sp)
+ LOAD x6, 3 * REGBYTES(sp)
+ LOAD x7, 4 * REGBYTES(sp)
+ LOAD x8, 5 * REGBYTES(sp)
+ LOAD x9, 6 * REGBYTES(sp)
+ LOAD x10, 7 * REGBYTES(sp)
+ LOAD x11, 8 * REGBYTES(sp)
+ LOAD x12, 9 * REGBYTES(sp)
+ LOAD x13, 10 * REGBYTES(sp)
+ LOAD x14, 11 * REGBYTES(sp)
+ LOAD x15, 12 * REGBYTES(sp)
+#ifndef __riscv_32e
+ LOAD x16, 13 * REGBYTES(sp)
+ LOAD x17, 14 * REGBYTES(sp)
+ LOAD x18, 15 * REGBYTES(sp)
+ LOAD x19, 16 * REGBYTES(sp)
+ LOAD x20, 17 * REGBYTES(sp)
+ LOAD x21, 18 * REGBYTES(sp)
+ LOAD x22, 19 * REGBYTES(sp)
+ LOAD x23, 20 * REGBYTES(sp)
+ LOAD x24, 21 * REGBYTES(sp)
+ LOAD x25, 22 * REGBYTES(sp)
+ LOAD x26, 23 * REGBYTES(sp)
+ LOAD x27, 24 * REGBYTES(sp)
+ LOAD x28, 25 * REGBYTES(sp)
+ LOAD x29, 26 * REGBYTES(sp)
+ LOAD x30, 27 * REGBYTES(sp)
+ LOAD x31, 28 * REGBYTES(sp)
+#endif
+
+ addi sp, sp, RT_CONTEXT_SIZE
+ mret
diff --git a/libcpu/risc-v/nuclei/cpuport.c b/libcpu/risc-v/nuclei/cpuport.c
new file mode 100644
index 0000000000..fad9afdf4c
--- /dev/null
+++ b/libcpu/risc-v/nuclei/cpuport.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ * Copyright (c) 2019-Present Nuclei Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020/03/26 Huaqi Nuclei RISC-V Core porting code.
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cpuport.h"
+
+#define SYSTICK_TICK_CONST (SOC_TIMER_FREQ / RT_TICK_PER_SECOND)
+
+/* Interrupt level for kernel systimer interrupt and software timer interrupt */
+#define RT_KERNEL_INTERRUPT_LEVEL 1
+
+/* Initial CSR MSTATUS value when thread created */
+#define RT_INITIAL_MSTATUS (MSTATUS_MPP | MSTATUS_MPIE | MSTATUS_FS_INITIAL)
+
+/**
+ * @brief from thread used interrupt context switch
+ *
+ */
+volatile rt_ubase_t rt_interrupt_from_thread = 0;
+/**
+ * @brief to thread used interrupt context switch
+ *
+ */
+volatile rt_ubase_t rt_interrupt_to_thread = 0;
+/**
+ * @brief flag to indicate context switch in interrupt or not
+ *
+ */
+volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0;
+
+/**
+ * @brief thread stack frame of saved context
+ *
+ */
+struct rt_hw_stack_frame
+{
+ rt_ubase_t epc; /*!< epc - epc - program counter */
+ rt_ubase_t ra; /*!< x1 - ra - return address for jumps */
+ rt_ubase_t t0; /*!< x5 - t0 - temporary register 0 */
+ rt_ubase_t t1; /*!< x6 - t1 - temporary register 1 */
+ rt_ubase_t t2; /*!< x7 - t2 - temporary register 2 */
+ rt_ubase_t s0_fp; /*!< x8 - s0/fp - saved register 0 or frame pointer */
+ rt_ubase_t s1; /*!< x9 - s1 - saved register 1 */
+ rt_ubase_t a0; /*!< x10 - a0 - return value or function argument 0 */
+ rt_ubase_t a1; /*!< x11 - a1 - return value or function argument 1 */
+ rt_ubase_t a2; /*!< x12 - a2 - function argument 2 */
+ rt_ubase_t a3; /*!< x13 - a3 - function argument 3 */
+ rt_ubase_t a4; /*!< x14 - a4 - function argument 4 */
+ rt_ubase_t a5; /*!< x15 - a5 - function argument 5 */
+#ifndef __riscv_32e
+ rt_ubase_t a6; /*!< x16 - a6 - function argument 6 */
+ rt_ubase_t a7; /*!< x17 - s7 - function argument 7 */
+ rt_ubase_t s2; /*!< x18 - s2 - saved register 2 */
+ rt_ubase_t s3; /*!< x19 - s3 - saved register 3 */
+ rt_ubase_t s4; /*!< x20 - s4 - saved register 4 */
+ rt_ubase_t s5; /*!< x21 - s5 - saved register 5 */
+ rt_ubase_t s6; /*!< x22 - s6 - saved register 6 */
+ rt_ubase_t s7; /*!< x23 - s7 - saved register 7 */
+ rt_ubase_t s8; /*!< x24 - s8 - saved register 8 */
+ rt_ubase_t s9; /*!< x25 - s9 - saved register 9 */
+ rt_ubase_t s10; /*!< x26 - s10 - saved register 10 */
+ rt_ubase_t s11; /*!< x27 - s11 - saved register 11 */
+ rt_ubase_t t3; /*!< x28 - t3 - temporary register 3 */
+ rt_ubase_t t4; /*!< x29 - t4 - temporary register 4 */
+ rt_ubase_t t5; /*!< x30 - t5 - temporary register 5 */
+ rt_ubase_t t6; /*!< x31 - t6 - temporary register 6 */
+#endif
+ rt_ubase_t mstatus; /*!< - machine status register */
+};
+
+/**
+ * This function will initialize thread stack
+ *
+ * @param tentry the entry of thread
+ * @param parameter the parameter of entry
+ * @param stack_addr the beginning stack address
+ * @param texit the function will be called when thread exit
+ *
+ * @return stack address
+ */
+rt_uint8_t *rt_hw_stack_init(void *tentry,
+ void *parameter,
+ rt_uint8_t *stack_addr,
+ void *texit)
+{
+ struct rt_hw_stack_frame *frame;
+ rt_uint8_t *stk;
+ int i;
+
+ stk = stack_addr + sizeof(rt_ubase_t);
+ stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_ubase_t)stk, REGBYTES);
+ stk -= sizeof(struct rt_hw_stack_frame);
+
+ frame = (struct rt_hw_stack_frame *)stk;
+
+ for (i = 0; i < sizeof(struct rt_hw_stack_frame) / sizeof(rt_ubase_t); i++)
+ {
+ ((rt_ubase_t *)frame)[i] = 0xdeadbeef;
+ }
+
+ frame->ra = (rt_ubase_t)texit;
+ frame->a0 = (rt_ubase_t)parameter;
+ frame->epc = (rt_ubase_t)tentry;
+
+ frame->mstatus = RT_INITIAL_MSTATUS;
+
+ return stk;
+}
+
+/**
+ * @brief Do rt-thread context switch in interrupt context
+ *
+ * @param from thread sp of from thread
+ * @param to thread sp of to thread
+ */
+void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to)
+{
+ if (rt_thread_switch_interrupt_flag == 0)
+ rt_interrupt_from_thread = from;
+
+ rt_interrupt_to_thread = to;
+ rt_thread_switch_interrupt_flag = 1;
+ RT_YIELD();
+}
+
+/**
+ * @brief Do rt-thread context switch in task context
+ *
+ * @param from thread sp of from thread
+ * @param to thread sp of to thread
+ */
+void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to)
+{
+ rt_interrupt_from_thread = from;
+ rt_interrupt_to_thread = to;
+ RT_YIELD();
+}
+
+/**
+ * @brief shutdown CPU
+ *
+ */
+void rt_hw_cpu_shutdown()
+{
+ rt_uint32_t level;
+ rt_kprintf("shutdown...\n");
+
+ level = rt_hw_interrupt_disable();
+ while (level)
+ {
+ RT_ASSERT(0);
+ }
+}
+
+/**
+ * @brief Do extra task switch code
+ *
+ * @details
+ *
+ * - Clear software timer interrupt request flag
+ * - clear rt_thread_switch_interrupt_flag to 0
+ */
+void rt_hw_taskswitch(void)
+{
+ /* Clear Software IRQ, A MUST */
+ SysTimer_ClearSWIRQ();
+ rt_thread_switch_interrupt_flag = 0;
+}
+
+/**
+ * @brief Setup systimer and software timer interrupt
+ *
+ * @details
+ *
+ * - Set Systimer interrupt as NON-VECTOR interrupt with lowest interrupt level
+ * - Set software timer interrupt as VECTOR interrupt with lowest interrupt level
+ * - Enable these two interrupts
+ */
+void rt_hw_ticksetup(void)
+{
+ uint64_t ticks = SYSTICK_TICK_CONST;
+
+ /* Make SWI and SysTick the lowest priority interrupts. */
+ /* Stop and clear the SysTimer. SysTimer as Non-Vector Interrupt */
+ SysTick_Config(ticks);
+ ECLIC_DisableIRQ(SysTimer_IRQn);
+ ECLIC_SetLevelIRQ(SysTimer_IRQn, RT_KERNEL_INTERRUPT_LEVEL);
+ ECLIC_SetShvIRQ(SysTimer_IRQn, ECLIC_NON_VECTOR_INTERRUPT);
+ ECLIC_EnableIRQ(SysTimer_IRQn);
+
+ /* Set SWI interrupt level to lowest level/priority, SysTimerSW as Vector Interrupt */
+ ECLIC_SetShvIRQ(SysTimerSW_IRQn, ECLIC_VECTOR_INTERRUPT);
+ ECLIC_SetLevelIRQ(SysTimerSW_IRQn, RT_KERNEL_INTERRUPT_LEVEL);
+ ECLIC_EnableIRQ(SysTimerSW_IRQn);
+}
+
+/**
+ * systimer interrupt handler eclic_mtip_handler
+ * is hard coded in startup_<Device>.S
+ * We define SysTick_Handler as eclic_mtip_handler
+ * for easy understanding
+ */
+#define SysTick_Handler eclic_mtip_handler
+
+/**
+ * @brief This is the timer interrupt service routine.
+ *
+ */
+void SysTick_Handler(void)
+{
+ /* Reload systimer */
+ SysTick_Reload(SYSTICK_TICK_CONST);
+
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ /* tick increase */
+ rt_tick_increase();
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
+
+/**
+ * @brief Disable cpu interrupt
+ *
+ * @details
+ *
+ * - Disable cpu interrupt by clear MIE bit in MSTATUS
+ * - Return the previous value in MSTATUS before clear MIE bit
+ *
+ * @return the previous value in MSTATUS before clear MIE bit
+ */
+rt_base_t rt_hw_interrupt_disable(void)
+{
+ return __RV_CSR_READ_CLEAR(CSR_MSTATUS, MSTATUS_MIE);
+}
+
+/**
+ * @brief Restore previous saved interrupt status
+ *
+ * @param level previous saved MSTATUS value
+ */
+void rt_hw_interrupt_enable(rt_base_t level)
+{
+ __RV_CSR_WRITE(CSR_MSTATUS, level);
+}
diff --git a/libcpu/risc-v/nuclei/cpuport.h b/libcpu/risc-v/nuclei/cpuport.h
new file mode 100644
index 0000000000..3736f0078a
--- /dev/null
+++ b/libcpu/risc-v/nuclei/cpuport.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ * Copyright (c) 2019-Present Nuclei Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020/03/26 hqfang Nuclei RISC-V Core porting code.
+ */
+
+#ifndef __CPUPORT_H__
+#define __CPUPORT_H__
+
+#include <rtconfig.h>
+#include <nuclei_sdk_soc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Scheduler utilities. */
+#define RT_YIELD() \
+{ \
+ /* Set a software interrupt(SWI) request to request a context switch. */ \
+ SysTimer_SetSWIRQ(); \
+ /* Barriers are normally not required but do ensure the code is completely \
+ within the specified behaviour for the architecture. */ \
+ __RWMB(); \
+ __FENCE_I(); \
+}
+
+extern void rt_hw_ticksetup(void);
+extern void rt_hw_taskswitch(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libcpu/risc-v/nuclei/interrupt_gcc.S b/libcpu/risc-v/nuclei/interrupt_gcc.S
new file mode 100644
index 0000000000..02a3e3e760
--- /dev/null
+++ b/libcpu/risc-v/nuclei/interrupt_gcc.S
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2019-Present Nuclei Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020/03/26 hqfang First Nuclei RISC-V porting implementation
+ */
+
+#include "riscv_encoding.h"
+
+.section .text.entry
+.align 8
+
+/**
+ * \brief Global interrupt disabled
+ * \details
+ * This function disable global interrupt.
+ * \remarks
+ * - All the interrupt requests will be ignored by CPU.
+ */
+.macro DISABLE_MIE
+ csrc CSR_MSTATUS, MSTATUS_MIE
+.endm
+
+/**
+ * \brief Macro for context save
+ * \details
+ * This macro save ABI defined caller saved registers in the stack.
+ * \remarks
+ * - This Macro could use to save context when you enter to interrupt
+ * or exception
+*/
+/* Save caller registers */
+.macro SAVE_CONTEXT
+ csrrw sp, CSR_MSCRATCHCSWL, sp
+ /* Allocate stack space for context saving */
+#ifndef __riscv_32e
+ addi sp, sp, -20*REGBYTES
+#else
+ addi sp, sp, -14*REGBYTES
+#endif /* __riscv_32e */
+
+ STORE x1, 0*REGBYTES(sp)
+ STORE x4, 1*REGBYTES(sp)
+ STORE x5, 2*REGBYTES(sp)
+ STORE x6, 3*REGBYTES(sp)
+ STORE x7, 4*REGBYTES(sp)
+ STORE x10, 5*REGBYTES(sp)
+ STORE x11, 6*REGBYTES(sp)
+ STORE x12, 7*REGBYTES(sp)
+ STORE x13, 8*REGBYTES(sp)
+ STORE x14, 9*REGBYTES(sp)
+ STORE x15, 10*REGBYTES(sp)
+#ifndef __riscv_32e
+ STORE x16, 14*REGBYTES(sp)
+ STORE x17, 15*REGBYTES(sp)
+ STORE x28, 16*REGBYTES(sp)
+ STORE x29, 17*REGBYTES(sp)
+ STORE x30, 18*REGBYTES(sp)
+ STORE x31, 19*REGBYTES(sp)
+#endif /* __riscv_32e */
+.endm
+
+/**
+ * \brief Macro for restore caller registers
+ * \details
+ * This macro restore ABI defined caller saved registers from stack.
+ * \remarks
+ * - You could use this macro to restore context before you want return
+ * from interrupt or exeception
+ */
+/* Restore caller registers */
+.macro RESTORE_CONTEXT
+ LOAD x1, 0*REGBYTES(sp)
+ LOAD x4, 1*REGBYTES(sp)
+ LOAD x5, 2*REGBYTES(sp)
+ LOAD x6, 3*REGBYTES(sp)
+ LOAD x7, 4*REGBYTES(sp)
+ LOAD x10, 5*REGBYTES(sp)
+ LOAD x11, 6*REGBYTES(sp)
+ LOAD x12, 7*REGBYTES(sp)
+ LOAD x13, 8*REGBYTES(sp)
+ LOAD x14, 9*REGBYTES(sp)
+ LOAD x15, 10*REGBYTES(sp)
+#ifndef __riscv_32e
+ LOAD x16, 14*REGBYTES(sp)
+ LOAD x17, 15*REGBYTES(sp)
+ LOAD x28, 16*REGBYTES(sp)
+ LOAD x29, 17*REGBYTES(sp)
+ LOAD x30, 18*REGBYTES(sp)
+ LOAD x31, 19*REGBYTES(sp)
+
+ /* De-allocate the stack space */
+ addi sp, sp, 20*REGBYTES
+#else
+ /* De-allocate the stack space */
+ addi sp, sp, 14*REGBYTES
+#endif /* __riscv_32e */
+ csrrw sp, CSR_MSCRATCHCSWL, sp
+.endm
+
+/**
+ * \brief Macro for save necessary CSRs to stack
+ * \details
+ * This macro store MCAUSE, MEPC, MSUBM to stack.
+ */
+.macro SAVE_CSR_CONTEXT
+ /* Store CSR mcause to stack using pushmcause */
+ csrrwi x0, CSR_PUSHMCAUSE, 11
+ /* Store CSR mepc to stack using pushmepc */
+ csrrwi x0, CSR_PUSHMEPC, 12
+ /* Store CSR msub to stack using pushmsub */
+ csrrwi x0, CSR_PUSHMSUBM, 13
+.endm
+
+/**
+ * \brief Macro for restore necessary CSRs from stack
+ * \details
+ * This macro restore MSUBM, MEPC, MCAUSE from stack.
+ */
+.macro RESTORE_CSR_CONTEXT
+ LOAD x5, 13*REGBYTES(sp)
+ csrw CSR_MSUBM, x5
+ LOAD x5, 12*REGBYTES(sp)
+ csrw CSR_MEPC, x5
+ LOAD x5, 11*REGBYTES(sp)
+ csrw CSR_MCAUSE, x5
+.endm
+
+/**
+ * \brief Exception/NMI Entry
+ * \details
+ * This function provide common entry functions for exception/nmi.
+ * \remarks
+ * This function provide a default exception/nmi entry.
+ * ABI defined caller save register and some CSR registers
+ * to be saved before enter interrupt handler and be restored before return.
+ */
+.section .text.trap
+/* In CLIC mode, the exeception entry must be 64bytes aligned */
+.align 6
+.global exc_entry
+exc_entry:
+ /* Save the caller saving registers (context) */
+ SAVE_CONTEXT
+ /* Save the necessary CSR registers */
+ SAVE_CSR_CONTEXT
+
+ /*
+ * Set the exception handler function arguments
+ * argument 1: mcause value
+ * argument 2: current stack point(SP) value
+ */
+ csrr a0, mcause
+ mv a1, sp
+ /*
+ * TODO: Call the exception handler function
+ * By default, the function template is provided in
+ * system_Device.c, you can adjust it as you want
+ */
+ call core_exception_handler
+
+ /* Restore the necessary CSR registers */
+ RESTORE_CSR_CONTEXT
+ /* Restore the caller saving registers (context) */
+ RESTORE_CONTEXT
+
+ /* Return to regular code */
+ mret
+
+/**
+ * \brief Non-Vector Interrupt Entry
+ * \details
+ * This function provide common entry functions for handling
+ * non-vector interrupts
+ * \remarks
+ * This function provide a default non-vector interrupt entry.
+ * ABI defined caller save register and some CSR registers need
+ * to be saved before enter interrupt handler and be restored before return.
+ */
+.section .text.irq
+/* In CLIC mode, the interrupt entry must be 4bytes aligned */
+.align 2
+.global irq_entry
+/* This label will be set to MTVT2 register */
+irq_entry:
+ /* Save the caller saving registers (context) */
+ SAVE_CONTEXT
+ /* Save the necessary CSR registers */
+ SAVE_CSR_CONTEXT
+
+ /* This special CSR read/write operation, which is actually
+ * claim the CLIC to find its pending highest ID, if the ID
+ * is not 0, then automatically enable the mstatus.MIE, and
+ * jump to its vector-entry-label, and update the link register
+ */
+ csrrw ra, CSR_JALMNXTI, ra
+
+ /* Critical section with interrupts disabled */
+ DISABLE_MIE
+
+ /* Restore the necessary CSR registers */
+ RESTORE_CSR_CONTEXT
+ /* Restore the caller saving registers (context) */
+ RESTORE_CONTEXT
+
+ /* Return to regular code */
+ mret
+
+/* Default Handler for Exceptions / Interrupts */
+.global default_intexc_handler
+Undef_Handler:
+default_intexc_handler:
+1:
+ j 1b
+