/**************************************************************************//**
 * @item     CosyOS-III Port
 * @file     port_rv32i_HWS.S
 * @brief    RV32I Core Port File for Hardware Stack
 * @note     处理器需要全程仅工作在机器模式。
 * @note     x4(tp)、mscratch、0xE000E040 专用于任务切换，不允许用户使用。
 * @author   迟凯峰
 * @version  v3.0.7
 * @date     2026.08.14
 **************************************************************************//**

 * 断点测试

 1.断点测试功能是为了有效验证，内核解锁后的 break point 1、2 是否等效于仍然处于
   服务层临界区的保护之中，这取决于处理器的微内核架构。
 2.开启断点测试后，如果 break point 1、2 已不在服务层临界区的保护之中，必会调用
   test_breakpoint_hook，用户可在该钩子函数中用打印或点灯等方式来报告测试未通过。
 3.如果通过了断点测试，可确信 break point 1、2 等效于仍然处于服务层临界区的保护
   之中，此时，用户可手动关闭断点防护功能（LINE: 75）提高任务切换效率。
 4.断点测试不是必须的，如果您不追求卓越性能，可不必进行断点测试，默认已开启断点
   防护功能，可确保任务切换的安全、可靠。
 5.测试时间：10分钟即可，如果连续测试10分钟仍未报告测试失败，说明已经通过了测试。
 6.test_breakpoint_hook，需用户自行实现。
 */
#if (0) // 断点测试开关
#define __TEST_BREAKPOINT
#endif
////////////////////////////////////////////////////////////////////////////////

#if !defined ( __riscv_32e )

#include "syscfg.h"
#include "mcucfg_rv32.h"
#define  fstore   fsw
#define   store    sw
#define   load     lw
#define  fload    flw

////////////////////////////////////////////////////////////////////////////////

/* PendSV 软中断 */

.global OS_PendSV_Handler
.align  2
OS_PendSV_Handler: // hardware push Caller

#if defined ( __TEST_BREAKPOINT )
	la      tp, test_breakpoint_hook
	csrw    mscratch, tp
#endif

/* push Callee */
	addi sp, sp,-32 * MCUCFG_REGBYTES
	store    x8,  8 * MCUCFG_REGBYTES(sp)
	store    x9,  9 * MCUCFG_REGBYTES(sp)
	store   x18, 18 * MCUCFG_REGBYTES(sp)
	store   x19, 19 * MCUCFG_REGBYTES(sp)
	store   x20, 20 * MCUCFG_REGBYTES(sp)
	store   x21, 21 * MCUCFG_REGBYTES(sp)
	store   x22, 22 * MCUCFG_REGBYTES(sp)
	store   x23, 23 * MCUCFG_REGBYTES(sp)
	store   x24, 24 * MCUCFG_REGBYTES(sp)
	store   x25, 25 * MCUCFG_REGBYTES(sp)
	store   x26, 26 * MCUCFG_REGBYTES(sp)
	store   x27, 27 * MCUCFG_REGBYTES(sp)

	call    sPendSV_Handler
	beqz    a0,  2f // 直接返回
	la      s1,  s_task_current
	addi    s0,  a0, -1
	beqz    s0,  1f // 恢复现场

/* push mepc */
	csrr    a0,  mepc
#if (1)  // 断点防护功能（默认开启）
	la      t0,  _break_point_ + 4
	bltu    t0,  a0,  0f
	addi    t0,  t0, -4
	bltu    a0,  t0,  0f
	csrr    a0,  mscratch
#endif
0:	store   a0,   0 * MCUCFG_REGBYTES(sp)

/* 任务-PC 监控 */
#if (SYSCFG_TASKPC_MONITOR == 1)
	la      a1,  s_pc
	sw      a0,  (a1)
#endif

/* 内核上锁 */// 使服务层临界区连续
1:	li      a0,   0xFF
	lui     tp,  (0xE000E040 >> 12)
	sw      a0,  (0xE000E040 & 0xFFF)(tp)
	fence.i

/* 返回至 _task_switch_ */
	la      a0,   _task_switch_
	csrw    mepc, a0
	mret // hardware pop Caller

/* pop Callee */
2:	load     x8,  8 * MCUCFG_REGBYTES(sp)
	load     x9,  9 * MCUCFG_REGBYTES(sp)
	load    x18, 18 * MCUCFG_REGBYTES(sp)
	load    x19, 19 * MCUCFG_REGBYTES(sp)
	load    x20, 20 * MCUCFG_REGBYTES(sp)
	load    x21, 21 * MCUCFG_REGBYTES(sp)
	load    x22, 22 * MCUCFG_REGBYTES(sp)
	load    x23, 23 * MCUCFG_REGBYTES(sp)
	load    x24, 24 * MCUCFG_REGBYTES(sp)
	load    x25, 25 * MCUCFG_REGBYTES(sp)
	load    x26, 26 * MCUCFG_REGBYTES(sp)
	load    x27, 27 * MCUCFG_REGBYTES(sp)
	addi sp, sp, 32 * MCUCFG_REGBYTES

	mret // hardware pop Caller

////////////////////////////////////////////////////////////////////////////////

/* 任务切换 */

.local _task_switch_
.align  2
_task_switch_:

	beqz     s0, 1f // 恢复现场
/* push Caller */
	store    x1,  1 * MCUCFG_REGBYTES(sp)
	store    x5,  5 * MCUCFG_REGBYTES(sp)
	store    x6,  6 * MCUCFG_REGBYTES(sp)
	store    x7,  7 * MCUCFG_REGBYTES(sp)
	store   x10, 10 * MCUCFG_REGBYTES(sp)
	store   x11, 11 * MCUCFG_REGBYTES(sp)
	store   x12, 12 * MCUCFG_REGBYTES(sp)
	store   x13, 13 * MCUCFG_REGBYTES(sp)
	store   x14, 14 * MCUCFG_REGBYTES(sp)
	store   x15, 15 * MCUCFG_REGBYTES(sp)
	store   x16, 16 * MCUCFG_REGBYTES(sp)
	store   x17, 17 * MCUCFG_REGBYTES(sp)
	store   x28, 28 * MCUCFG_REGBYTES(sp)
	store   x29, 29 * MCUCFG_REGBYTES(sp)
	store   x30, 30 * MCUCFG_REGBYTES(sp)
	store   x31, 31 * MCUCFG_REGBYTES(sp)

/* push FPU */
#if (MCUCFG_FPU_AUTOSTORE == 1)
	addi sp, sp,-32 * MCUCFG_FPUBYTES
	fstore   f0,  0 * MCUCFG_FPUBYTES(sp)
	fstore   f1,  1 * MCUCFG_FPUBYTES(sp)
	fstore   f2,  2 * MCUCFG_FPUBYTES(sp)
	fstore   f3,  3 * MCUCFG_FPUBYTES(sp)
	fstore   f4,  4 * MCUCFG_FPUBYTES(sp)
	fstore   f5,  5 * MCUCFG_FPUBYTES(sp)
	fstore   f6,  6 * MCUCFG_FPUBYTES(sp)
	fstore   f7,  7 * MCUCFG_FPUBYTES(sp)
	fstore   f8,  8 * MCUCFG_FPUBYTES(sp)
	fstore   f9,  9 * MCUCFG_FPUBYTES(sp)
	fstore  f10, 10 * MCUCFG_FPUBYTES(sp)
	fstore  f11, 11 * MCUCFG_FPUBYTES(sp)
	fstore  f12, 12 * MCUCFG_FPUBYTES(sp)
	fstore  f13, 13 * MCUCFG_FPUBYTES(sp)
	fstore  f14, 14 * MCUCFG_FPUBYTES(sp)
	fstore  f15, 15 * MCUCFG_FPUBYTES(sp)
	fstore  f16, 16 * MCUCFG_FPUBYTES(sp)
	fstore  f17, 17 * MCUCFG_FPUBYTES(sp)
	fstore  f18, 18 * MCUCFG_FPUBYTES(sp)
	fstore  f19, 19 * MCUCFG_FPUBYTES(sp)
	fstore  f20, 20 * MCUCFG_FPUBYTES(sp)
	fstore  f21, 21 * MCUCFG_FPUBYTES(sp)
	fstore  f22, 22 * MCUCFG_FPUBYTES(sp)
	fstore  f23, 23 * MCUCFG_FPUBYTES(sp)
	fstore  f24, 24 * MCUCFG_FPUBYTES(sp)
	fstore  f25, 25 * MCUCFG_FPUBYTES(sp)
	fstore  f26, 26 * MCUCFG_FPUBYTES(sp)
	fstore  f27, 27 * MCUCFG_FPUBYTES(sp)
	fstore  f28, 28 * MCUCFG_FPUBYTES(sp)
	fstore  f29, 29 * MCUCFG_FPUBYTES(sp)
	fstore  f30, 30 * MCUCFG_FPUBYTES(sp)
	fstore  f31, 31 * MCUCFG_FPUBYTES(sp)
#endif

	lw      t0, (s1)
	sw      sp, (t0)
	fence   rw,  rw

/* 恢复现场 */
1:	la      t1,  s_task_news
	lw      t0, (t1)
	lw      sp, (t0)
	sw      t0, (s1)

#if defined ( __TEST_BREAKPOINT )
	li      a0, (0x0001UL << (MCUCFG_XXXx_IRQn % 32)   )
	li      a1, (0xE000E200 + MCUCFG_XXXx_IRQn / 32 * 4)
	sw      a0, (a1) // 触发 PendSV
#endif

/* pop FPU */
#if (MCUCFG_FPU_AUTOSTORE == 1)
	fload   f0,   0 * MCUCFG_FPUBYTES(sp)
	fload   f1,   1 * MCUCFG_FPUBYTES(sp)
	fload   f2,   2 * MCUCFG_FPUBYTES(sp)
	fload   f3,   3 * MCUCFG_FPUBYTES(sp)
	fload   f4,   4 * MCUCFG_FPUBYTES(sp)
	fload   f5,   5 * MCUCFG_FPUBYTES(sp)
	fload   f6,   6 * MCUCFG_FPUBYTES(sp)
	fload   f7,   7 * MCUCFG_FPUBYTES(sp)
	fload   f8,   8 * MCUCFG_FPUBYTES(sp)
	fload   f9,   9 * MCUCFG_FPUBYTES(sp)
	fload   f10, 10 * MCUCFG_FPUBYTES(sp)
	fload   f11, 11 * MCUCFG_FPUBYTES(sp)
	fload   f12, 12 * MCUCFG_FPUBYTES(sp)
	fload   f13, 13 * MCUCFG_FPUBYTES(sp)
	fload   f14, 14 * MCUCFG_FPUBYTES(sp)
	fload   f15, 15 * MCUCFG_FPUBYTES(sp)
	fload   f16, 16 * MCUCFG_FPUBYTES(sp)
	fload   f17, 17 * MCUCFG_FPUBYTES(sp)
	fload   f18, 18 * MCUCFG_FPUBYTES(sp)
	fload   f19, 19 * MCUCFG_FPUBYTES(sp)
	fload   f20, 20 * MCUCFG_FPUBYTES(sp)
	fload   f21, 21 * MCUCFG_FPUBYTES(sp)
	fload   f22, 22 * MCUCFG_FPUBYTES(sp)
	fload   f23, 23 * MCUCFG_FPUBYTES(sp)
	fload   f24, 24 * MCUCFG_FPUBYTES(sp)
	fload   f25, 25 * MCUCFG_FPUBYTES(sp)
	fload   f26, 26 * MCUCFG_FPUBYTES(sp)
	fload   f27, 27 * MCUCFG_FPUBYTES(sp)
	fload   f28, 28 * MCUCFG_FPUBYTES(sp)
	fload   f29, 29 * MCUCFG_FPUBYTES(sp)
	fload   f30, 30 * MCUCFG_FPUBYTES(sp)
	fload   f31, 31 * MCUCFG_FPUBYTES(sp)
	addi sp, sp, 32 * MCUCFG_FPUBYTES
#endif
/* pop mepc to mscratch */
	load    a0,   0 * MCUCFG_REGBYTES(sp)
	csrw    mscratch, a0

/* pop Caller & Callee */
	load    x1,   1 * MCUCFG_REGBYTES(sp)
	load    x5,   5 * MCUCFG_REGBYTES(sp)
	load    x6,   6 * MCUCFG_REGBYTES(sp)
	load    x7,   7 * MCUCFG_REGBYTES(sp)
	load    x8,   8 * MCUCFG_REGBYTES(sp)
	load    x9,   9 * MCUCFG_REGBYTES(sp)
	load    x10, 10 * MCUCFG_REGBYTES(sp)
	load    x11, 11 * MCUCFG_REGBYTES(sp)
	load    x12, 12 * MCUCFG_REGBYTES(sp)
	load    x13, 13 * MCUCFG_REGBYTES(sp)
	load    x14, 14 * MCUCFG_REGBYTES(sp)
	load    x15, 15 * MCUCFG_REGBYTES(sp)
	load    x16, 16 * MCUCFG_REGBYTES(sp)
	load    x17, 17 * MCUCFG_REGBYTES(sp)
	load    x18, 18 * MCUCFG_REGBYTES(sp)
	load    x19, 19 * MCUCFG_REGBYTES(sp)
	load    x20, 20 * MCUCFG_REGBYTES(sp)
	load    x21, 21 * MCUCFG_REGBYTES(sp)
	load    x22, 22 * MCUCFG_REGBYTES(sp)
	load    x23, 23 * MCUCFG_REGBYTES(sp)
	load    x24, 24 * MCUCFG_REGBYTES(sp)
	load    x25, 25 * MCUCFG_REGBYTES(sp)
	load    x26, 26 * MCUCFG_REGBYTES(sp)
	load    x27, 27 * MCUCFG_REGBYTES(sp)
	load    x28, 28 * MCUCFG_REGBYTES(sp)
	load    x29, 29 * MCUCFG_REGBYTES(sp)
	load    x30, 30 * MCUCFG_REGBYTES(sp)
	load    x31, 31 * MCUCFG_REGBYTES(sp)
	addi sp, sp, 32 * MCUCFG_REGBYTES

	sw zero, (0xE000E040 & 0xFFF)(tp) // 内核解锁（退出服务层临界区）

_break_point_:
	csrr tp, mscratch // break point 1
	jr tp             // break point 2

////////////////////////////////////////////////////////////////////////////////

#endif
