Files
RTOS/CPU/CH32V10x/os_port_gnu.S
T
2026-05-28 15:23:19 +08:00

426 lines
17 KiB
ArmAsm
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "os_config.h"
#if __riscv_xlen == 64
#define REG_BYTES 8
#define STORE sd
#define LOAD ld
#define FSTORE fsd
#define FLOAD fld
#elif __riscv_xlen == 32
#define REG_BYTES 4
#define STORE sw
#define LOAD lw
#define FSTORE fsw
#define FLOAD flw
#else
#error Assembler did not define __riscv_xlen
#endif
#define CONTEXT_SIZE (32 * REG_BYTES)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//// CODE
#ifdef OS_CFG_CPU_CLZ_ASM_PRESENT
.section .text.cpu_clz,"ax",%progbits
.align 8
.func
.global cpu_clz
cpu_clz:
clz a0, a0
ret
.endfunc
#endif
.section .text.os_port_context_switch_to,"ax",%progbits
.align 2
.func
.global os_port_context_switch_to
.extern os_port_on_switch_success
os_port_context_switch_to:
li t0, 0x1800
csrw mstatus, t0 // 1. 关中断
/* 设置中断栈/系统栈空间 */
la t0, _eusrstack
addi t0, t0, -512
csrw mscratch, t0 // 备用栈指针存入 mscratch
/* =====================================================================
* 第一步:切换到中断栈,安全调用通知 C 函数
* ===================================================================== */
jal os_port_on_switch_success // 调用 C 函数(此时随便它怎么污染寄存器)
/* =====================================================================
* 第二步:获取新任务的栈指针 SP
* ===================================================================== */
LOAD sp, 0(a0) // a0 是传入的 &g_os_port_switch_to_sp,从中取出 sp
/* =====================================================================
* 第三步:恢复 FPU 浮点寄存器(与保存栈帧严格镜像)
* 修复宏定义:将 MPU 改回 FPU
* ===================================================================== */
#if (OS_CFG_CPU_FPU_PRESENT)
FLOAD f0, (CONTEXT_SIZE + 0 * REG_BYTES)(sp)
FLOAD f1, (CONTEXT_SIZE + 1 * REG_BYTES)(sp)
FLOAD f2, (CONTEXT_SIZE + 2 * REG_BYTES)(sp)
FLOAD f3, (CONTEXT_SIZE + 3 * REG_BYTES)(sp)
FLOAD f4, (CONTEXT_SIZE + 4 * REG_BYTES)(sp)
FLOAD f5, (CONTEXT_SIZE + 5 * REG_BYTES)(sp)
FLOAD f6, (CONTEXT_SIZE + 6 * REG_BYTES)(sp)
FLOAD f7, (CONTEXT_SIZE + 7 * REG_BYTES)(sp)
FLOAD f8, (CONTEXT_SIZE + 8 * REG_BYTES)(sp)
FLOAD f9, (CONTEXT_SIZE + 9 * REG_BYTES)(sp)
FLOAD f10, (CONTEXT_SIZE + 10 * REG_BYTES)(sp)
FLOAD f11, (CONTEXT_SIZE + 11 * REG_BYTES)(sp)
FLOAD f12, (CONTEXT_SIZE + 12 * REG_BYTES)(sp)
FLOAD f13, (CONTEXT_SIZE + 13 * REG_BYTES)(sp)
FLOAD f14, (CONTEXT_SIZE + 14 * REG_BYTES)(sp)
FLOAD f15, (CONTEXT_SIZE + 15 * REG_BYTES)(sp)
FLOAD f16, (CONTEXT_SIZE + 16 * REG_BYTES)(sp)
FLOAD f17, (CONTEXT_SIZE + 17 * REG_BYTES)(sp)
FLOAD f18, (CONTEXT_SIZE + 18 * REG_BYTES)(sp)
FLOAD f19, (CONTEXT_SIZE + 19 * REG_BYTES)(sp)
FLOAD f20, (CONTEXT_SIZE + 20 * REG_BYTES)(sp)
FLOAD f21, (CONTEXT_SIZE + 21 * REG_BYTES)(sp)
FLOAD f22, (CONTEXT_SIZE + 22 * REG_BYTES)(sp)
FLOAD f23, (CONTEXT_SIZE + 23 * REG_BYTES)(sp)
FLOAD f24, (CONTEXT_SIZE + 24 * REG_BYTES)(sp)
FLOAD f25, (CONTEXT_SIZE + 25 * REG_BYTES)(sp)
FLOAD f26, (CONTEXT_SIZE + 26 * REG_BYTES)(sp)
FLOAD f27, (CONTEXT_SIZE + 27 * REG_BYTES)(sp)
FLOAD f28, (CONTEXT_SIZE + 28 * REG_BYTES)(sp)
FLOAD f29, (CONTEXT_SIZE + 29 * REG_BYTES)(sp)
FLOAD f30, (CONTEXT_SIZE + 30 * REG_BYTES)(sp)
FLOAD f31, (CONTEXT_SIZE + 31 * REG_BYTES)(sp)
#endif
/* =====================================================================
* 第四步:恢复通用寄存器(最后恢复 t0
* ===================================================================== */
LOAD x1, 1 * REG_BYTES(sp)
LOAD x4, 4 * REG_BYTES(sp)
LOAD x6, 6 * REG_BYTES(sp)
LOAD x7, 7 * REG_BYTES(sp)
LOAD x8, 8 * REG_BYTES(sp)
LOAD x9, 9 * REG_BYTES(sp)
LOAD x10, 10 * REG_BYTES(sp)
LOAD x11, 11 * REG_BYTES(sp)
LOAD x12, 12 * REG_BYTES(sp)
LOAD x13, 13 * REG_BYTES(sp)
LOAD x14, 14 * REG_BYTES(sp)
LOAD x15, 15 * REG_BYTES(sp)
LOAD x16, 16 * REG_BYTES(sp)
LOAD x17, 17 * REG_BYTES(sp)
LOAD x18, 18 * REG_BYTES(sp)
LOAD x19, 19 * REG_BYTES(sp)
LOAD x20, 20 * REG_BYTES(sp)
LOAD x21, 21 * REG_BYTES(sp)
LOAD x22, 22 * REG_BYTES(sp)
LOAD x23, 23 * REG_BYTES(sp)
LOAD x24, 24 * REG_BYTES(sp)
LOAD x25, 25 * REG_BYTES(sp)
LOAD x26, 26 * REG_BYTES(sp)
LOAD x27, 27 * REG_BYTES(sp)
LOAD x28, 28 * REG_BYTES(sp)
LOAD x29, 29 * REG_BYTES(sp)
LOAD x30, 30 * REG_BYTES(sp)
LOAD x31, 31 * REG_BYTES(sp)
/* =====================================================================
* 第五步:恢复特权级控制 CSR 寄存器
* ===================================================================== */
LOAD t0, 2 * REG_BYTES(sp) // 恢复初始 PC mepc
csrw mepc, t0
LOAD t0, 0 * REG_BYTES(sp) // 从栈中读取准备好的初始 mstatus
csrw mstatus, t0 // 修复:改用 csrw 强行覆盖
LOAD x5, 5 * REG_BYTES(sp) // 此时最后安全恢复 t0(x5)
/* =====================================================================
* 第六步:统一释放栈空间并退出
* ===================================================================== */
#if (OS_CFG_CPU_FPU_PRESENT)
addi sp, sp, (CONTEXT_SIZE + 32 * REG_BYTES)
#else
addi sp, sp, CONTEXT_SIZE
#endif
mret
.endfunc
.section .text.SW_Handler,"ax",%progbits
.align 2
.func
.global SW_Handler
.extern g_os_port_switch_from_sp
.extern g_os_port_switch_to_sp
.extern os_port_on_switch_success
SW_Handler:
csrci mstatus, 0x08 // 立刻关闭全局中断 MIE = 0
/* =====================================================================
* 第一步:一揽子分配所有栈空间(防止碎片和二次偏移错误)
* ===================================================================== */
#if (OS_CFG_CPU_FPU_PRESENT)
addi sp, sp, -(CONTEXT_SIZE + 32 * REG_BYTES)
#else
addi sp, sp, -CONTEXT_SIZE
#endif
/* =====================================================================
* 第二步:保存通用寄存器
* ===================================================================== */
STORE x5, 5 * REG_BYTES(sp) // 优先保存 t0,腾出临时寄存器
li t0, 0x1800
csrw mstatus, t0 // M 模式
li t0, 0x1880
STORE t0, 0 * REG_BYTES(sp) // 设置 MPIE
csrr t0, mepc
STORE t0, 2*REG_BYTES(sp) // 保存正在运行任务的 pc 指针
STORE x1, 1 * REG_BYTES(sp) // ra
STORE x4, 4 * REG_BYTES(sp) // tp
STORE x6, 6 * REG_BYTES(sp) // t1
STORE x7, 7 * REG_BYTES(sp) // t2
STORE x8, 8 * REG_BYTES(sp) // s0/fp
STORE x9, 9 * REG_BYTES(sp) // s1
STORE x10, 10 * REG_BYTES(sp) // a0
STORE x11, 11 * REG_BYTES(sp) // a1
STORE x12, 12 * REG_BYTES(sp) // a2
STORE x13, 13 * REG_BYTES(sp) // a3
STORE x14, 14 * REG_BYTES(sp) // a4
STORE x15, 15 * REG_BYTES(sp) // a5
STORE x16, 16 * REG_BYTES(sp) // a6
STORE x17, 17 * REG_BYTES(sp) // a7
STORE x18, 18 * REG_BYTES(sp) // s2
STORE x19, 19 * REG_BYTES(sp) // s3
STORE x20, 20 * REG_BYTES(sp) // s4
STORE x21, 21 * REG_BYTES(sp) // s5
STORE x22, 22 * REG_BYTES(sp) // s6
STORE x23, 23 * REG_BYTES(sp) // s7
STORE x24, 24 * REG_BYTES(sp) // s8
STORE x25, 25 * REG_BYTES(sp) // s9
STORE x26, 26 * REG_BYTES(sp) // s10
STORE x27, 27 * REG_BYTES(sp) // s11
STORE x28, 28 * REG_BYTES(sp) // t3
STORE x29, 29 * REG_BYTES(sp) // t4
STORE x30, 30 * REG_BYTES(sp) // t5
STORE x31, 31 * REG_BYTES(sp) // t6
/* =====================================================================
* 第三步:保存 FPU 浮点寄存器(使用确定的、不受干扰的高位偏移)
* ===================================================================== */
#if (OS_CFG_CPU_FPU_PRESENT)
FSTORE f0, (CONTEXT_SIZE + 0 * REG_BYTES)(sp)
FSTORE f1, (CONTEXT_SIZE + 1 * REG_BYTES)(sp)
FSTORE f2, (CONTEXT_SIZE + 2 * REG_BYTES)(sp)
FSTORE f3, (CONTEXT_SIZE + 3 * REG_BYTES)(sp)
FSTORE f4, (CONTEXT_SIZE + 4 * REG_BYTES)(sp)
FSTORE f5, (CONTEXT_SIZE + 5 * REG_BYTES)(sp)
FSTORE f6, (CONTEXT_SIZE + 6 * REG_BYTES)(sp)
FSTORE f7, (CONTEXT_SIZE + 7 * REG_BYTES)(sp)
FSTORE f8, (CONTEXT_SIZE + 8 * REG_BYTES)(sp)
FSTORE f9, (CONTEXT_SIZE + 9 * REG_BYTES)(sp)
FSTORE f10, (CONTEXT_SIZE + 10 * REG_BYTES)(sp)
FSTORE f11, (CONTEXT_SIZE + 11 * REG_BYTES)(sp)
FSTORE f12, (CONTEXT_SIZE + 12 * REG_BYTES)(sp)
FSTORE f13, (CONTEXT_SIZE + 13 * REG_BYTES)(sp)
FSTORE f14, (CONTEXT_SIZE + 14 * REG_BYTES)(sp)
FSTORE f15, (CONTEXT_SIZE + 15 * REG_BYTES)(sp)
FSTORE f16, (CONTEXT_SIZE + 16 * REG_BYTES)(sp)
FSTORE f17, (CONTEXT_SIZE + 17 * REG_BYTES)(sp)
FSTORE f18, (CONTEXT_SIZE + 18 * REG_BYTES)(sp)
FSTORE f19, (CONTEXT_SIZE + 19 * REG_BYTES)(sp)
FSTORE f20, (CONTEXT_SIZE + 20 * REG_BYTES)(sp)
FSTORE f21, (CONTEXT_SIZE + 21 * REG_BYTES)(sp)
FSTORE f22, (CONTEXT_SIZE + 22 * REG_BYTES)(sp)
FSTORE f23, (CONTEXT_SIZE + 23 * REG_BYTES)(sp)
FSTORE f24, (CONTEXT_SIZE + 24 * REG_BYTES)(sp)
FSTORE f25, (CONTEXT_SIZE + 25 * REG_BYTES)(sp)
FSTORE f26, (CONTEXT_SIZE + 26 * REG_BYTES)(sp)
FSTORE f27, (CONTEXT_SIZE + 27 * REG_BYTES)(sp)
FSTORE f28, (CONTEXT_SIZE + 28 * REG_BYTES)(sp)
FSTORE f29, (CONTEXT_SIZE + 29 * REG_BYTES)(sp)
FSTORE f30, (CONTEXT_SIZE + 30 * REG_BYTES)(sp)
FSTORE f31, (CONTEXT_SIZE + 31 * REG_BYTES)(sp)
#endif
/* =====================================================================
* 第四步:保存旧任务 sp,并安全调用通知函数
* ===================================================================== */
la t0, g_os_port_switch_from_sp
LOAD t0, 0(t0)
STORE sp, 0(t0) // sp 存入 g_os_port_switch_from_sp
// 此时调用 C 函数是完全安全的,因为所有寄存器都已在任务栈里备考
jal os_port_on_switch_success
/* =====================================================================
* 第五步:载入新任务的栈指针(SP
* ===================================================================== */
la t0, g_os_port_switch_to_sp
LOAD t0, 0(t0)
LOAD sp, 0(t0) // sp 指向 g_os_port_switch_to_sp
/* =====================================================================
* 第六步:恢复新任务的 FPU 浮点寄存器
* ===================================================================== */
#if (OS_CFG_CPU_FPU_PRESENT)
FLOAD f0, (CONTEXT_SIZE + 0 * REG_BYTES)(sp)
FLOAD f1, (CONTEXT_SIZE + 1 * REG_BYTES)(sp)
FLOAD f2, (CONTEXT_SIZE + 2 * REG_BYTES)(sp)
FLOAD f3, (CONTEXT_SIZE + 3 * REG_BYTES)(sp)
FLOAD f4, (CONTEXT_SIZE + 4 * REG_BYTES)(sp)
FLOAD f5, (CONTEXT_SIZE + 5 * REG_BYTES)(sp)
FLOAD f6, (CONTEXT_SIZE + 6 * REG_BYTES)(sp)
FLOAD f7, (CONTEXT_SIZE + 7 * REG_BYTES)(sp)
FLOAD f8, (CONTEXT_SIZE + 8 * REG_BYTES)(sp)
FLOAD f9, (CONTEXT_SIZE + 9 * REG_BYTES)(sp)
FLOAD f10, (CONTEXT_SIZE + 10 * REG_BYTES)(sp)
FLOAD f11, (CONTEXT_SIZE + 11 * REG_BYTES)(sp)
FLOAD f12, (CONTEXT_SIZE + 12 * REG_BYTES)(sp)
FLOAD f13, (CONTEXT_SIZE + 13 * REG_BYTES)(sp)
FLOAD f14, (CONTEXT_SIZE + 14 * REG_BYTES)(sp)
FLOAD f15, (CONTEXT_SIZE + 15 * REG_BYTES)(sp)
FLOAD f16, (CONTEXT_SIZE + 16 * REG_BYTES)(sp)
FLOAD f17, (CONTEXT_SIZE + 17 * REG_BYTES)(sp)
FLOAD f18, (CONTEXT_SIZE + 18 * REG_BYTES)(sp)
FLOAD f19, (CONTEXT_SIZE + 19 * REG_BYTES)(sp)
FLOAD f20, (CONTEXT_SIZE + 20 * REG_BYTES)(sp)
FLOAD f21, (CONTEXT_SIZE + 21 * REG_BYTES)(sp)
FLOAD f22, (CONTEXT_SIZE + 22 * REG_BYTES)(sp)
FLOAD f23, (CONTEXT_SIZE + 23 * REG_BYTES)(sp)
FLOAD f24, (CONTEXT_SIZE + 24 * REG_BYTES)(sp)
FLOAD f25, (CONTEXT_SIZE + 25 * REG_BYTES)(sp)
FLOAD f26, (CONTEXT_SIZE + 26 * REG_BYTES)(sp)
FLOAD f27, (CONTEXT_SIZE + 27 * REG_BYTES)(sp)
FLOAD f28, (CONTEXT_SIZE + 28 * REG_BYTES)(sp)
FLOAD f29, (CONTEXT_SIZE + 29 * REG_BYTES)(sp)
FLOAD f30, (CONTEXT_SIZE + 30 * REG_BYTES)(sp)
FLOAD f31, (CONTEXT_SIZE + 31 * REG_BYTES)(sp)
#endif
/* =====================================================================
* 第七步:全面恢复通用寄存器(最后恢复 t0
* ===================================================================== */
LOAD x1, 1 * REG_BYTES(sp)
LOAD x4, 4 * REG_BYTES(sp)
// LOAD x5, 5 * REG_BYTES(sp) // 恢复 t0
LOAD x6, 6 * REG_BYTES(sp)
LOAD x7, 7 * REG_BYTES(sp)
LOAD x8, 8 * REG_BYTES(sp)
LOAD x9, 9 * REG_BYTES(sp)
LOAD x10, 10 * REG_BYTES(sp)
LOAD x11, 11 * REG_BYTES(sp)
LOAD x12, 12 * REG_BYTES(sp)
LOAD x13, 13 * REG_BYTES(sp)
LOAD x14, 14 * REG_BYTES(sp)
LOAD x15, 15 * REG_BYTES(sp)
LOAD x16, 16 * REG_BYTES(sp)
LOAD x17, 17 * REG_BYTES(sp)
LOAD x18, 18 * REG_BYTES(sp)
LOAD x19, 19 * REG_BYTES(sp)
LOAD x20, 20 * REG_BYTES(sp)
LOAD x21, 21 * REG_BYTES(sp)
LOAD x22, 22 * REG_BYTES(sp)
LOAD x23, 23 * REG_BYTES(sp)
LOAD x24, 24 * REG_BYTES(sp)
LOAD x25, 25 * REG_BYTES(sp)
LOAD x26, 26 * REG_BYTES(sp)
LOAD x27, 27 * REG_BYTES(sp)
LOAD x28, 28 * REG_BYTES(sp)
LOAD x29, 29 * REG_BYTES(sp)
LOAD x30, 30 * REG_BYTES(sp)
LOAD x31, 31 * REG_BYTES(sp)
/* =====================================================================
* 第八步:恢复新任务的 CSR 寄存器
* ===================================================================== */
LOAD t0, 2 * REG_BYTES(sp) // 恢复 mepc
csrw mepc, t0
LOAD t0, 0 * REG_BYTES(sp) // 恢复 mstatus
csrw mstatus, t0
LOAD x5, 5 * REG_BYTES(sp) // 恢复 t0
/* =====================================================================
* 第九步:彻底释放栈空间并退出
* ===================================================================== */
#if (OS_CFG_CPU_FPU_PRESENT)
addi sp, sp, (CONTEXT_SIZE + 32 * REG_BYTES)
#else
addi sp, sp, CONTEXT_SIZE
#endif
/* 执行 mret。此时:
* 1. 硬件会自动把当前 mstatus.MPIE (1) 复制到 mstatus.MIE,从而开启全局中断。
* 2. 程序跳转到 mepc 寄存器指向的地址(即新任务继续运行的代码处)。 */
mret // M 模式退出
.endfunc
.section .text.SysTick_Handler,"ax",%progbits
.align 2
.global SysTick_Handler
.extern SysTick_Handler_C
.func
SysTick_Handler:
// csrci mstatus, 8 // 关闭中断
/* 1. 因为是硬件中断,先在当前栈上保存必要的临时寄存器(Caller-saved) */
addi sp, sp, -16 * REG_BYTES
STORE x1, 0 * REG_BYTES(sp) # ra
STORE x5, 1 * REG_BYTES(sp) # t0
STORE x6, 2 * REG_BYTES(sp) # t1
STORE x7, 3 * REG_BYTES(sp) # t2
STORE x10, 4 * REG_BYTES(sp) # a0
STORE x11, 5 * REG_BYTES(sp) # a1
STORE x12, 6 * REG_BYTES(sp) # a2
STORE x13, 7 * REG_BYTES(sp) # a3
STORE x14, 8 * REG_BYTES(sp) # a4
STORE x15, 9 * REG_BYTES(sp) # a5
STORE x16, 10 * REG_BYTES(sp) # a6
STORE x17, 11 * REG_BYTES(sp) # a7
STORE x28, 12 * REG_BYTES(sp) # t3
STORE x29, 13 * REG_BYTES(sp) # t4
STORE x30, 14 * REG_BYTES(sp) # t5
STORE x31, 15 * REG_BYTES(sp) # t6
/* 2. 清除定时器硬件中断标志位(防止重复触发),并调用 C 语言的时钟处理函数 */
jal SysTick_Handler_C
/* 3. 恢复临时寄存器 */
LOAD x1, 0 * REG_BYTES(sp) # ra
LOAD x5, 1 * REG_BYTES(sp) # t0
LOAD x6, 2 * REG_BYTES(sp) # t1
LOAD x7, 3 * REG_BYTES(sp) # t2
LOAD x10, 4 * REG_BYTES(sp) # a0
LOAD x11, 5 * REG_BYTES(sp) # a1
LOAD x12, 6 * REG_BYTES(sp) # a2
LOAD x13, 7 * REG_BYTES(sp) # a3
LOAD x14, 8 * REG_BYTES(sp) # a4
LOAD x15, 9 * REG_BYTES(sp) # a5
LOAD x16, 10 * REG_BYTES(sp) # a6
LOAD x17, 11 * REG_BYTES(sp) # a7
LOAD x28, 12 * REG_BYTES(sp) # t3
LOAD x29, 13 * REG_BYTES(sp) # t4
LOAD x30, 14 * REG_BYTES(sp) # t5
LOAD x31, 15 * REG_BYTES(sp) # t6
addi sp, sp, 16 * REG_BYTES
/* 4. 退出硬件中断 */
mret
.endfunc
.align 4
.end