/**************************************************************************//**
 * @item     CosyOS-II Config
 * @file     mcucfg_8051.h
 * @brief    8051 Core Config File
 * @author   迟凯峰
 * @version  V2.0.1
 * @date     2024.03.18
 ******************************************************************************/

#ifndef __MCUCFG_8051_H
#define __MCUCFG_8051_H

/******************************************************************************
 *                             USER Definitions                               *
 ******************************************************************************/

          //*** <<< Use Configuration Wizard in Context Menu >>> ***//

///////////////////////////////////////////////////////////////////////////////
// <h> 任务栈配置
// <i> 任务栈配置

// <o> 任务栈重分配增量
// <0=> 0 <4=> 4 <8=> 8 <16=> 16 <32=> 32
// <i> 当任务创建模式非静态创建时，CosyOS将自动启用任务栈重分配机制，以抵御任务栈溢出的风险。
// <i> 通过合理的配置一个重分配增量，可有效降低重分配的次数，减少内存碎片。
// <i> 此值的选取适当就好，不建议过大或过小。
#define MCUCFG_TASKSTACKREALLOC_INC     8

// <o> 系统启动任务的任务栈大小（Bytes）
// <i> 系统启动任务的任务栈大小，单位为字节数
#define MCUCFG_STACKSIZE_STARTER        32

// <o> 系统空闲任务的任务栈大小（Bytes）
// <i> 系统空闲任务的任务栈大小，单位为字节数
#define MCUCFG_STACKSIZE_SYSIDLE        32

// </h>
///////////////////////////////////////////////////////////////////////////////
// <o> 最低优先级中断REGBANK
// <0=> bank0 <1=> bank1 <2=> bank2 <3=> bank3
// <i> 所有最低优先级中断的REGBANK，bank0为不使用独立的REGBANK。
#define MCUCFG_SYSTICKREGBANK           0
///////////////////////////////////////////////////////////////////////////////
// <h> PendSV_Handler设置
// <i> 您可选择一个未使用的硬件中断，做为PendSV_Handler，用于执行系统的挂起服务。
// <i> 还需在初始化钩子中配置该中断，确保它不会被硬件触发，中断优先级必须为最低级。

// <o> 中断向量号
// <i> 中断向量号
#define MCUCFG_PENDSVIRQ                10

// <o> 中断开启
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例：EX0 = 1
#define mPendSV_Enable                  INTCLKO |= EX2

// <o> 中断关闭
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例：EX0 = 0
#define mPendSV_Disable                 INTCLKO &= ~EX2

// <o> 中断触发（置中断标志位）
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例：IE0 = 1
#define mPendSV_Set                     AUXINTIF |= INT2IF

// <o> 中断清零（清中断标志位）
// <i> 此项您应在文本编辑界面中定义。
// <i> 即使该标志位能够在中断服务程序中硬件自动清零，仍建议用户不要省略，以确保其可靠清零。
// <i> 示例：IE0 = 0
#define mPendSV_Clear                   AUXINTIF &= ~INT2IF

// </h>
///////////////////////////////////////////////////////////////////////////////
// <o> PendSV_FIFO深度
// <i> 此项参数取决于您在中断中调用挂起服务的总数及中断的频率。
// <i> 对于8051来说，CosyOS规定PendSV_FIFO的最大深度为56，您应妥善处理中断中调用的挂起服务，避免不必要的调用。
// <i> 可开启PendSV_FIFO监控功能，监控历史上的最大值，再适当增大，以确保其不会溢出。
#define MCUCFG_PENDSVFIFO_DEPTH         32
#if MCUCFG_PENDSVFIFO_DEPTH > 56
#error PendSV_FIFO深度值溢出！
#endif
///////////////////////////////////////////////////////////////////////////////
// <h> 动态内存设置
// <i> CosyOS会使用下列参数自动初始化内存池。

// <o> 内存池指针
// <i> 内存池的起始内存地址
#define MCUCFG_MALLOCMEMBPTR            6144
#if !MCUCFG_MALLOCMEMBPTR
#error 非法的设置值！
#endif

// <o> 内存池大小（Bytes）
// <i> 内存池大小，单位为字节数
#define MCUCFG_MALLOCMEMSIZE            2048
#if !MCUCFG_MALLOCMEMSIZE
#error 非法的设置值！
#endif

// </h>
///////////////////////////////////////////////////////////////////////////////
// <e> 自定义任务切换现场保护
// <i> CosyOS在任务切换时，默认自动保存的寄存器：{PCnext,A,B,DPH,DPL,PSW,R0-R7(REGBANK0)}。
// <i> 如您需要额外增加对其它寄存器的现场保护，可在下方自行添加代码。
// <i> 下方各定义项已经直接给出示例代码（保存：REGBANK1,P_SW2），直接在文本编辑界面中修改即可。
#define __MCUCFG_USERREG_SAVING         0

#if __MCUCFG_USERREG_SAVING == 1
// <o> 定义用于现场保护的数组
// <i> 定义一个"unsigned char"类型的数组，结尾必须加语句结束符";"。
#define mUserReg_                       unsigned char user_reg[9];

// <o> 定义保存现场代码
// <i> 用c语言代码，将相应寄存器的内容拷贝至自定义的数组中。
#define mUserReg_PUSH \
do{ \
	*(unsigned long *)(s_task_current->user_reg + 0) = *(unsigned long data *)0x08; \
	*(unsigned long *)(s_task_current->user_reg + 4) = *(unsigned long data *)0x0C; \
	s_task_current->user_reg[8] = P_SW2; \
}while(false)

// <o> 定义恢复现场代码
// <i> 用c语言代码，将自定义数组中的数据恢复至相应的寄存器。
#define mUserReg_POP \
do{ \
	*(unsigned long data *)0x08 = *(unsigned long *)(s_task_current->user_reg + 0); \
	*(unsigned long data *)0x0C = *(unsigned long *)(s_task_current->user_reg + 4); \
	P_SW2 = s_task_current->user_reg[8]; \
}while(false)

#else
#define mUserReg_
#define mUserReg_PUSH  do{}while(false)
#define mUserReg_POP   do{}while(false)
#endif

// </e>
///////////////////////////////////////////////////////////////////////////////

                //*** <<< end of configuration section >>> ***//

/******************************************************************************
 *                               OS Definitions                               *
 ******************************************************************************/

/* Header */
#include <string.h>
#include <intrins.h>
#include "..\System\os_base.h"
#include SYSCFG_STANDARDHEAD

/* Memory */
#define _SYS_MEM_     data
#define _CODE_MEM_    code
#define _CONST_MEM_   code
#define _STACK_MEM_   idata
#ifndef _MALLOC_MEM_
#define _MALLOC_MEM_  xdata
#endif
#define _XDATA_MEM_   xdata
#define _OBJ_MEM_     xdata

/* Register */
#define _SYS_REG_     _SYS_MEM_

/* Typedef */
typedef bit     m_bit_t;
typedef s_u8_t  m_sp_t;
typedef s_u8_t  m_taskmsg_t;
typedef s_u8_t  m_fetion_t;
typedef s_u8_t  m_stacksize_t;
typedef s_u16_t m_pc_t;
typedef s_u16_t m_tick_t;
typedef s_u32_t m_group_t;
#define m_boolvoid_tf (s_boolvoid_tf)

/* Extern */
extern bit m_sign_fifo_0_0;
extern m_sp_t _SYS_MEM_ m_msp;
extern m_sp_t _SYS_MEM_ m_bsp;
extern s_u8_t mPendSV_FIFO_DepthMAX;
void mx_disable_irq(void);
void mx_resume_irq(void);
void mPendSV_Handler(void);
void mPendSV_Loader(s_u16_t addr);

/* CONST & ATTRIBUTE */
#define MCUCFG_ISA                __MCS_51__
#define MCUCFG_GNU                __DISABLED__
#define MCUCFG_NOP                _nop_()
#define MCUCFG_PCLEN              2
#if MCUCFG_SYSTICKREGBANK
#define MCUCFG_BANK0SIZE          8
#define MCUCFG_USING              using MCUCFG_SYSTICKREGBANK
#define MCUCFG_BASICSTACKSIZE     7  /** \PUSH {PCnext,A,B,DPH,DPL,PSW} *//** \SAVE {R0-R7(REGBANK0)} */
#else
#define MCUCFG_BANK0SIZE          0
#define MCUCFG_USING
#define MCUCFG_BASICSTACKSIZE     15 /** \PUSH {PCnext,A,B,DPH,DPL,PSW,R0-R7(REGBANK0)} */
#endif
#define MCUCFG_C51USING           MCUCFG_USING
#define MCUCFG_SYSTICK_ATTRIBUTE  interrupt 19 MCUCFG_USING
#define MCUCFG_PENDSV_ATTRIBUTE   interrupt MCUCFG_PENDSVIRQ MCUCFG_USING
#define MCUCFG_251_REENTRANT
#define MCUCFG_STACK_ALIGN
#define MCUCFG_TASKMSG_TYPE       0
#define MCUCFG_TASKMSG_PSP
#define MCUCFG_TASKMSG_SIZE       (s_u8_t)(&mx - &m0 - 1)
#if SYSCFG_TASKMSGMODE == __PERFORMANCE__
#define MCUCFG_TASKMSG_VAR        m_taskmsg_t m0_
#define MCUCFG_TASKMSG_VAL        1
#elif SYSCFG_TASKMSGMODE == __INTELLIGENT__
#define MCUCFG_TASKMSG_VAR        m_taskmsg_t R3_, m_taskmsg_t R5_, m_taskmsg_t R7_, m_taskmsg_t m0_
#define MCUCFG_TASKMSG_VAL        0, 0, 0, 1
#endif
#define MCUCFG_TERNARYMASK        false;
#define MCUCFG_TASKSTACK_REALLOC  __ENABLED__
#define MCUCFG_STACKSIZE_TASKMGR  (MCUCFG_BASICSTACKSIZE + 16)
#define MCUCFG_STACKSIZE_DEBUGGER (MCUCFG_BASICSTACKSIZE + 16)

/* MCUAPI */
#define mSysTick_CLKMOD           (SYSCFG_SYSCLK / (1000000UL / SYSCFG_SYSTICKCYCLE) <= 65536 ? 1 : 12)
#define mSysTick_Cycle            (SYSCFG_SYSCLK / (1000000UL / SYSCFG_SYSTICKCYCLE) / mSysTick_CLKMOD)
#if mSysTick_Cycle > 65536
#error 系统滴答定时器溢出，必须减小系统时钟或系统滴答周期。
#elif 1000000UL % SYSCFG_SYSTICKCYCLE
#warning 每秒钟的系统滴答周期数不为整数，建议重新调整系统滴答周期。
#elif SYSCFG_SYSCLK % (1000000UL / SYSCFG_SYSTICKCYCLE)
#warning 每秒钟的系统滴答周期数不为整数，建议重新调整系统时钟或系统滴答周期。
#elif SYSCFG_SYSCLK / (1000000UL / SYSCFG_SYSTICKCYCLE) % mSysTick_CLKMOD
#warning 每秒钟的系统滴答周期数不为整数，建议重新调整系统时钟或系统滴答周期。
#endif
#define mSysTick_InitValue        (65536 - mSysTick_Cycle)
#define mSysTick_Counter          ((T3H << 8) | T3L)
#define mSysTick_Disable          IE2 &=~ET3
#define mSysTick_Enable           IE2 |= ET3
#define mSysTick_Clear            do{}while(false)

#define mTaskNode_Head_           m_stacksize_t stacklen;
#if MCUCFG_BANK0SIZE
#define mTaskNode_Tail_ \
	s_u8_t bank0[MCUCFG_BANK0SIZE]; \
	mUserReg_
#define mRegBank0_PUSH \
do{ \
	*(s_u32_t *)(s_task_current->bank0 + 0) = *(s_u32_t _SYS_MEM_ *)0; \
	*(s_u32_t *)(s_task_current->bank0 + 4) = *(s_u32_t _SYS_MEM_ *)4; \
}while(false)
#define mRegBank0_POP \
do{ \
	*(s_u32_t _SYS_MEM_ *)0 = *(s_u32_t *)(s_task_current->bank0 + 0); \
	*(s_u32_t _SYS_MEM_ *)4 = *(s_u32_t *)(s_task_current->bank0 + 4); \
}while(false)
#else
#define mTaskNode_Tail_ mUserReg_
#define mRegBank0_PUSH  do{}while(false)
#define mRegBank0_POP   do{}while(false)
#endif

#define mSysIRQ_Disable \
do{ \
	mPendSV_Disable; \
	mSysTick_Disable; \
}while(false)

#define mSysIRQ_Enable \
do{ \
	mSysTick_Enable; \
	mPendSV_Enable; \
}while(false)

#define mxDisableIRQ mx_disable_irq()
#define mxResumeIRQ  mx_resume_irq()

#define mSys_Idle \
do{ \
	PCON |= 0x01; \
	OS_NOPx4; \
}while(false)

#define mSys_INIT \
do{ \
	m_msp = SP; \
	m_bsp = SP + 1; \
	s_init_mempool((void _MALLOC_MEM_ *)MCUCFG_MALLOCMEMBPTR, MCUCFG_MALLOCMEMSIZE); \
	OS_NOPx1; \
	T4T3M = mSysTick_CLKMOD == 1 ? T4T3M | 0x02 : T4T3M &~0x02; \
	T3L = (s_u8_t)(mSysTick_InitValue); \
	T3H = (s_u8_t)(mSysTick_InitValue >> 8); \
	T4T3M |= T3R; \
	mSysIRQ_Enable; \
	EA = 1; \
}while(false)

#define mSysTick_Counting \
do{ \
	if(mSysTick_Counter <= tick_temp) break; \
	s_tick_counter1 += mSysTick_Counter - tick_temp; \
	s_tick_counter2++; \
}while(false)

#define mScheduler_INIT \
	m_stacksize_t _SYS_REG_ stacklen; \
	s_u8_t _STACK_MEM_  * _SYS_REG_ msp8; \
	s_u8_t _MALLOC_MEM_ * _SYS_REG_ psp8; \
	s_sign_scheduling = false

#define mTaskStack_INIT \
do{ \
	*(s_u16_t *)node_news->bsp = ((s_u16_t)s_task_starter->entry << 8) | ((s_u16_t)s_task_starter->entry >> 8); \
	*(s_u8_t *)(node_news->bsp + 7 - 1) = 0; \
	node_news->stacklen = MCUCFG_BASICSTACKSIZE; \
}while(false)

#define mTaskStack_LEN  stacklen = SP - m_msp

#define mUsedTime_END \
do{ \
	if(usedtime[0]){ \
		usedtime[0]--; \
		usedtime[1] = 65536 - usedtime[1] + counter - mSysTick_InitValue; \
	} \
	else{ \
		if(counter >= usedtime[1]){ \
			usedtime[1] = counter - usedtime[1]; \
		} \
		else{ \
			usedtime[1] = 65536 - usedtime[1] + counter - mSysTick_InitValue; \
		} \
	} \
	s_task_current->usedtime[0] += usedtime[0]; \
	s_task_current->usedtime[0] += (s_task_current->usedtime[1] + usedtime[1]) / mSysTick_Cycle; \
	s_task_current->usedtime[1]  = (s_task_current->usedtime[1] + usedtime[1]) % mSysTick_Cycle; \
}while(false)

#define mUsedTime_INIT \
do{ \
	usedtime[0] = 0; \
	usedtime[1] = counter; \
}while(false)

#if SYSCFG_TASKPC_MONITOR == __ENABLED__
#define mTaskPC_Monitor \
do{ \
	if(!s_sign_taskmgr) break; \
	s_pc = *(m_pc_t *)(SP + 1 - MCUCFG_BASICSTACKSIZE); \
	s_pc = (s_pc << 8) | (s_pc >> 8); \
}while(false)
#else
#define mTaskPC_Monitor do{}while(false)
#endif

#define mTaskStack_PUSH \
do{ \
	msp8 = (s_u8_t _STACK_MEM_  *)m_bsp; \
	psp8 = (s_u8_t _MALLOC_MEM_ *)s_task_current->bsp; \
	s_task_current->stacklen = stacklen; \
	do{ \
		*psp8++ = *msp8++; \
	}while(--stacklen); \
	mRegBank0_PUSH; \
	mUserReg_PUSH; \
	mTaskPC_Monitor; \
}while(false)

#define mTaskStack_POP \
do{ \
	s_task_current = node_news; \
	msp8 = (s_u8_t _STACK_MEM_  *)m_bsp; \
	psp8 = (s_u8_t _MALLOC_MEM_ *)s_task_current->bsp; \
	stacklen = s_task_current->stacklen; \
	SP = m_msp + stacklen; \
	do{ \
		*msp8++ = *psp8++; \
	}while(--stacklen); \
	mRegBank0_POP; \
	mUserReg_POP; \
}while(false)

#define mPendSV_Load \
do{ \
	mPendSV_Loader((s_u16_t)&u_psv); \
	mPendSV_Set; \
}while(false)

#define mPendSV_Entry \
	mPendSV_Clear; \
	if(!m_sign_fifo_0_0) mPendSV_Handler()

#define miWriteFlagBits \
	static bit u_f = false; \
	if(!u_f){ \
		u_f = true



#endif
