| /**************************************************************************** |
| * arch/risc-v/src/common/riscv_macros.S |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| .file "riscv_macros.S" |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <arch/arch.h> |
| #include <arch/csr.h> |
| #include <arch/irq.h> |
| |
| #include <sys/types.h> |
| |
| #include "riscv_internal.h" |
| #include "riscv_percpu.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: save_ctx |
| * |
| * Parameter: |
| * in - Pointer to where the save is performed (e.g. sp) |
| * |
| * Description: |
| * Save the common context registers (i.e. work / temp / etc). |
| * |
| ****************************************************************************/ |
| |
| .macro save_ctx in |
| |
| REGSTORE x1, REG_X1(\in) /* ra */ |
| #ifdef RISCV_SAVE_GP |
| REGSTORE x3, REG_X3(\in) /* gp */ |
| #endif |
| REGSTORE x4, REG_X4(\in) /* tp */ |
| REGSTORE x5, REG_X5(\in) /* t0 */ |
| REGSTORE x6, REG_X6(\in) /* t1 */ |
| REGSTORE x7, REG_X7(\in) /* t2 */ |
| REGSTORE x8, REG_X8(\in) /* s0 */ |
| REGSTORE x9, REG_X9(\in) /* s1 */ |
| REGSTORE x10, REG_X10(\in) /* a0 */ |
| REGSTORE x11, REG_X11(\in) /* a1 */ |
| REGSTORE x12, REG_X12(\in) /* a2 */ |
| REGSTORE x13, REG_X13(\in) /* a3 */ |
| REGSTORE x14, REG_X14(\in) /* a4 */ |
| REGSTORE x15, REG_X15(\in) /* a5 */ |
| REGSTORE x16, REG_X16(\in) /* a6 */ |
| REGSTORE x17, REG_X17(\in) /* a7 */ |
| REGSTORE x18, REG_X18(\in) /* s2 */ |
| REGSTORE x19, REG_X19(\in) /* s3 */ |
| REGSTORE x20, REG_X20(\in) /* s4 */ |
| REGSTORE x21, REG_X21(\in) /* s5 */ |
| REGSTORE x22, REG_X22(\in) /* s6 */ |
| REGSTORE x23, REG_X23(\in) /* s7 */ |
| REGSTORE x24, REG_X24(\in) /* s8 */ |
| REGSTORE x25, REG_X25(\in) /* s9 */ |
| REGSTORE x26, REG_X26(\in) /* s10 */ |
| REGSTORE x27, REG_X27(\in) /* s11 */ |
| REGSTORE x28, REG_X28(\in) /* t3 */ |
| REGSTORE x29, REG_X29(\in) /* t4 */ |
| REGSTORE x30, REG_X30(\in) /* t5 */ |
| REGSTORE x31, REG_X31(\in) /* t6 */ |
| |
| .endm |
| |
| /**************************************************************************** |
| * Name: riscv_savefpu |
| * |
| * Parameter: |
| * in - Pointer to where the save is performed (e.g. sp) |
| * |
| * Description: |
| * Save the FPU context registers (i.e. work / temp / etc). |
| * |
| ****************************************************************************/ |
| |
| .macro riscv_savefpu in |
| |
| /* Store all floating point registers */ |
| |
| FSTORE f0, REG_F0(\in) |
| FSTORE f1, REG_F1(\in) |
| FSTORE f2, REG_F2(\in) |
| FSTORE f3, REG_F3(\in) |
| FSTORE f4, REG_F4(\in) |
| FSTORE f5, REG_F5(\in) |
| FSTORE f6, REG_F6(\in) |
| FSTORE f7, REG_F7(\in) |
| FSTORE f8, REG_F8(\in) |
| FSTORE f9, REG_F9(\in) |
| FSTORE f10, REG_F10(\in) |
| FSTORE f11, REG_F11(\in) |
| FSTORE f12, REG_F12(\in) |
| FSTORE f13, REG_F13(\in) |
| FSTORE f14, REG_F14(\in) |
| FSTORE f15, REG_F15(\in) |
| FSTORE f16, REG_F16(\in) |
| FSTORE f17, REG_F17(\in) |
| FSTORE f18, REG_F18(\in) |
| FSTORE f19, REG_F19(\in) |
| FSTORE f20, REG_F20(\in) |
| FSTORE f21, REG_F21(\in) |
| FSTORE f22, REG_F22(\in) |
| FSTORE f23, REG_F23(\in) |
| FSTORE f24, REG_F24(\in) |
| FSTORE f25, REG_F25(\in) |
| FSTORE f26, REG_F26(\in) |
| FSTORE f27, REG_F27(\in) |
| FSTORE f28, REG_F28(\in) |
| FSTORE f29, REG_F29(\in) |
| FSTORE f30, REG_F30(\in) |
| FSTORE f31, REG_F31(\in) |
| |
| frcsr t0 |
| REGSTORE t0, REG_FCSR(\in) |
| |
| .endm |
| |
| /**************************************************************************** |
| * Name: riscv_savevpu |
| * |
| * Parameter: |
| * in - Pointer to where the save is performed (e.g. sp) |
| * |
| * Description: |
| * Save the VPU context registers (i.e. work / temp / etc). |
| * |
| ****************************************************************************/ |
| |
| .macro riscv_savevpu in |
| |
| /* Store all vector registers */ |
| |
| mv t1, \in |
| |
| csrr t0, CSR_VSTART |
| REGSTORE t0, REG_VSTART(t1) |
| csrr t0, CSR_VTYPE |
| REGSTORE t0, REG_VTYPE(t1) |
| csrr t0, CSR_VL |
| REGSTORE t0, REG_VL(t1) |
| csrr t0, CSR_VCSR |
| REGSTORE t0, REG_VCSR(t1) |
| csrr t0, CSR_VLENB |
| REGSTORE t0, REG_VLENB(t1) |
| |
| addi t1, t1, VPU_XCPT_SIZE |
| |
| vsetvli t2, x0, e8, m8, ta, ma |
| |
| vse8.v v0, (t1) |
| add t1, t1, t2 |
| vse8.v v8, (t1) |
| add t1, t1, t2 |
| vse8.v v16, (t1) |
| add t1, t1, t2 |
| vse8.v v24, (t1) |
| |
| .endm |
| |
| /**************************************************************************** |
| * Name: load_ctx |
| * |
| * Parameter: |
| * out - Pointer to where the load is performed (e.g. sp) |
| * |
| * Description: |
| * Load the common context registers (i.e. work / temp / etc). |
| * |
| ****************************************************************************/ |
| |
| .macro load_ctx out |
| |
| REGLOAD x1, REG_X1(\out) /* ra */ |
| #ifdef RISCV_SAVE_GP |
| REGLOAD x3, REG_X3(\out) /* gp */ |
| #endif |
| REGLOAD x4, REG_X4(\out) /* tp */ |
| REGLOAD x5, REG_X5(\out) /* t0 */ |
| REGLOAD x6, REG_X6(\out) /* t1 */ |
| REGLOAD x7, REG_X7(\out) /* t2 */ |
| REGLOAD x8, REG_X8(\out) /* s0 */ |
| REGLOAD x9, REG_X9(\out) /* s1 */ |
| REGLOAD x10, REG_X10(\out) /* a0 */ |
| REGLOAD x11, REG_X11(\out) /* a1 */ |
| REGLOAD x12, REG_X12(\out) /* a2 */ |
| REGLOAD x13, REG_X13(\out) /* a3 */ |
| REGLOAD x14, REG_X14(\out) /* a4 */ |
| REGLOAD x15, REG_X15(\out) /* a5 */ |
| REGLOAD x16, REG_X16(\out) /* a6 */ |
| REGLOAD x17, REG_X17(\out) /* a7 */ |
| REGLOAD x18, REG_X18(\out) /* s2 */ |
| REGLOAD x19, REG_X19(\out) /* s3 */ |
| REGLOAD x20, REG_X20(\out) /* s4 */ |
| REGLOAD x21, REG_X21(\out) /* s5 */ |
| REGLOAD x22, REG_X22(\out) /* s6 */ |
| REGLOAD x23, REG_X23(\out) /* s7 */ |
| REGLOAD x24, REG_X24(\out) /* s8 */ |
| REGLOAD x25, REG_X25(\out) /* s9 */ |
| REGLOAD x26, REG_X26(\out) /* s10 */ |
| REGLOAD x27, REG_X27(\out) /* s11 */ |
| REGLOAD x28, REG_X28(\out) /* t3 */ |
| REGLOAD x29, REG_X29(\out) /* t4 */ |
| REGLOAD x30, REG_X30(\out) /* t5 */ |
| REGLOAD x31, REG_X31(\out) /* t6 */ |
| |
| .endm |
| |
| /**************************************************************************** |
| * Name: riscv_loadfpu |
| * |
| * Parameter: |
| * out - Pointer to where the load is performed (e.g. sp) |
| * |
| * Description: |
| * Load the FPU context registers (i.e. work / temp / etc). |
| * |
| ****************************************************************************/ |
| |
| .macro riscv_loadfpu out |
| |
| /* Load all floating point registers */ |
| |
| FLOAD f0, REG_F0(\out) |
| FLOAD f1, REG_F1(\out) |
| FLOAD f2, REG_F2(\out) |
| FLOAD f3, REG_F3(\out) |
| FLOAD f4, REG_F4(\out) |
| FLOAD f5, REG_F5(\out) |
| FLOAD f6, REG_F6(\out) |
| FLOAD f7, REG_F7(\out) |
| FLOAD f8, REG_F8(\out) |
| FLOAD f9, REG_F9(\out) |
| FLOAD f10, REG_F10(\out) |
| FLOAD f11, REG_F11(\out) |
| FLOAD f12, REG_F12(\out) |
| FLOAD f13, REG_F13(\out) |
| FLOAD f14, REG_F14(\out) |
| FLOAD f15, REG_F15(\out) |
| FLOAD f16, REG_F16(\out) |
| FLOAD f17, REG_F17(\out) |
| FLOAD f18, REG_F18(\out) |
| FLOAD f19, REG_F19(\out) |
| FLOAD f20, REG_F20(\out) |
| FLOAD f21, REG_F21(\out) |
| FLOAD f22, REG_F22(\out) |
| FLOAD f23, REG_F23(\out) |
| FLOAD f24, REG_F24(\out) |
| FLOAD f25, REG_F25(\out) |
| FLOAD f26, REG_F26(\out) |
| FLOAD f27, REG_F27(\out) |
| FLOAD f28, REG_F28(\out) |
| FLOAD f29, REG_F29(\out) |
| FLOAD f30, REG_F30(\out) |
| FLOAD f31, REG_F31(\out) |
| |
| /* Store the floating point control and status register */ |
| |
| REGLOAD t0, REG_FCSR(\out) |
| fscsr t0 |
| |
| .endm |
| |
| /**************************************************************************** |
| * Name: riscv_loadvpu |
| * |
| * Parameter: |
| * out - Pointer to where the load is performed (e.g. sp) |
| * |
| * Description: |
| * Load the VPU context registers (i.e. work / temp / etc). |
| * |
| ****************************************************************************/ |
| |
| .macro riscv_loadvpu out |
| |
| /* Load all vector registers */ |
| |
| mv t0, \out |
| addi t1, t0, VPU_XCPT_SIZE |
| |
| vsetvli t2, x0, e8, m8, ta, ma |
| |
| vle8.v v0, (t1) |
| add t1, t1, t2 |
| vle8.v v8, (t1) |
| add t1, t1, t2 |
| vle8.v v16, (t1) |
| add t1, t1, t2 |
| vle8.v v24, (t1) |
| |
| mv t1, t0 |
| |
| REGLOAD t0, REG_VTYPE(t1) |
| REGLOAD t3, REG_VL(t1) |
| vsetvl x0, t3, t0 |
| |
| REGLOAD t0, REG_VSTART(t1) |
| csrw CSR_VSTART, t0 |
| REGLOAD t0, REG_VCSR(t1) |
| csrw CSR_VCSR, t0 |
| |
| .endm |
| |
| /**************************************************************************** |
| * Name: setintstack |
| * |
| * Description: |
| * Set the current stack pointer to the "top" the interrupt stack. Works |
| * for single CPU case in flat mode. |
| * Must be provided by MCU-specific logic in the SMP case, or the kernel |
| * runs in supervisor mode (S-mode). |
| * |
| ****************************************************************************/ |
| |
| #if CONFIG_ARCH_INTERRUPTSTACK > 15 |
| #if !defined(CONFIG_SMP) && !defined(CONFIG_ARCH_USE_S_MODE) |
| .macro setintstack tmp0, tmp1 |
| la sp, g_intstacktop |
| .endm |
| #endif /* !defined(CONFIG_SMP) && !defined(CONFIG_ARCH_USE_S_MODE) */ |
| #endif /* CONFIG_ARCH_INTERRUPTSTACK > 15 */ |
| |
| /**************************************************************************** |
| * Name: riscv_mhartid |
| * |
| * Description: |
| * Context aware way to query hart id |
| * |
| * Returned Value: |
| * Hart id |
| * |
| ****************************************************************************/ |
| |
| .macro riscv_mhartid out |
| #ifdef CONFIG_RISCV_PERCPU_SCRATCH |
| csrr \out, CSR_SCRATCH |
| REGLOAD \out, RISCV_PERCPU_HARTID(\out) |
| #else |
| csrr \out, CSR_MHARTID |
| #endif |
| .endm |
| |
| /**************************************************************************** |
| * Name: riscv_set_inital_sp |
| * |
| * Description: |
| * Set inital sp for riscv core. This function should be only called |
| * when initing. |
| * |
| * sp (stack top) = sp base + idle stack size * hart id |
| * sp (stack base) = sp (stack top) + idle stack size * - XCPTCONTEXT_SIZE |
| * |
| * Note: The XCPTCONTEXT_SIZE byte after stack base is reserved for |
| * up_initial_state since we are already running and using |
| * the per CPU idle stack. |
| * |
| * TODO: Support non-zero boot hart. |
| * |
| * Parameter: |
| * base - Pointer to where the stack is allocated (e.g. _ebss) |
| * size - Stack size for pre cpu to allocate |
| * hartid - Hart id register of this hart (Usually a0) |
| * |
| ****************************************************************************/ |
| .macro riscv_set_inital_sp base, size, hartid |
| la t0, \base |
| li t1, \size |
| mul t1, \hartid, t1 |
| add t0, t0, t1 |
| |
| /* ensure the last XCPTCONTEXT_SIZE is reserved for non boot CPU */ |
| |
| bnez \hartid, 998f |
| li t1, STACK_ALIGN_DOWN(\size) |
| j 999f |
| |
| 998: |
| li t1, STACK_ALIGN_DOWN(\size - XCPTCONTEXT_SIZE) |
| |
| 999: |
| add t0, t0, t1 |
| mv sp, t0 |
| .endm |