/**************************************************************************//**
 * @item     CosyOS-II Config
 * @file     mcucfg_80251.h
 * @brief    80251 Core Config File
 * @author   迟凯峰
 * @version  V1.3.0
 * @date     2024.01.29
 ******************************************************************************/

#ifndef __MCUCFG_80251_H
#define __MCUCFG_80251_H

/******************************************************************************
 *                             USER Definitions                               *
 ******************************************************************************/

          //*** <<< Use Configuration Wizard in Context Menu >>> ***//

///////////////////////////////////////////////////////////////////////////////
// <h> 编译器设置
// <i> 编译器设置

// <o> Code Rom Size
// <0=> Large <1=> Huge
// <i> 此项设置务必要与编译器的实际设置保持一致，否则CosyOS将无法正常运行。
#define MCUCFG_CODEROMSIZE              0

// <q> 4 Byte Interrupt Frame Size
// <i> 此项设置务必要与编译器的实际设置保持一致，否则CosyOS将无法正常运行。
#define MCUCFG_4BYTEINTFRAME            1

// </h>
///////////////////////////////////////////////////////////////////////////////
// <h> 任务栈模式
// <i> 任务栈模式分为MSP模式、PSP模式，您只能选其一。
// <i> MSP模式，与51单片机的任务栈模式相同，任务切换时是要拷贝数据的，效率低，但同时却能拥有100%可靠的任务栈重分配机制，
// <i> 只要主栈和内存池足够大就可确保所有任务栈永不溢出（前提是任务创建模式非静态创建）。
// <i> PSP模式，任务切换效率等同于Cortex-M，但每个任务栈都是主栈，需配置足够大的edata内存。
// <i> 如果您的MCU的edata内存足够大，可以考虑PSP模式，以提高任务切换效率。

// <e> MSP模式
// <i> 是否启用MSP模式？
#define __MCUCFG_MSPMODE                1

// <o> 任务栈重分配增量
// <0=> 0 <8=> 8 <16=> 16 <32=> 32 <64=> 64
// <i> 当任务栈模式为MSP模式、任务创建模式非静态创建时，CosyOS将自动启用任务栈重分配机制，以抵御任务栈溢出的风险。
// <i> 通过合理的配置一个重分配增量，可有效降低重分配的次数，减少内存碎片。
// <i> 此值的选取适当就好，不建议过大或过小。
#define MCUCFG_TASKSTACKREALLOC_INC     16

#if __MCUCFG_MSPMODE == 1

// <o> 系统启动任务的任务栈大小（Bytes）
// <i> 系统启动任务的任务栈大小，单位为字节数
#define MCUCFG_STACKSIZE_STARTER        64

// <o> 系统空闲任务的任务栈大小（Bytes）
// <i> 系统空闲任务的任务栈大小，单位为字节数
#define MCUCFG_STACKSIZE_SYSIDLE        64

#endif
// </e>

// <e> PSP模式
// <i> 是否启用PSP模式？
#define __MCUCFG_PSPMODE                0

#if   __MCUCFG_MSPMODE == 1 && __MCUCFG_PSPMODE == 0
#define MCUCFG_TASKSTACK_MODE           __MSP__
#elif __MCUCFG_MSPMODE == 0 && __MCUCFG_PSPMODE == 1
#define MCUCFG_TASKSTACK_MODE           __PSP__
#elif __MCUCFG_MSPMODE == 0 && __MCUCFG_PSPMODE == 0
#error 任务栈模式未定义！
#elif __MCUCFG_MSPMODE == 1 && __MCUCFG_PSPMODE == 1
#error 任务栈模式重定义！
#endif

#if MCUCFG_TASKSTACK_MODE == __PSP__

// <o> 任务管理器的任务栈大小（Bytes）
// <i> 任务管理器的任务栈大小，单位为字节数
#define MCUCFG_STACKSIZE_TASKMGR        128

// <o> 系统调试任务的任务栈大小（Bytes）
// <i> 系统调试任务的任务栈大小，单位为字节数
#define MCUCFG_STACKSIZE_DEBUGGER       128

// <o> 系统启动任务的任务栈大小（Bytes）
// <i> 系统启动任务的任务栈大小，单位为字节数
#define MCUCFG_STACKSIZE_STARTER        128

// <o> 系统空闲任务的任务栈大小（Bytes）
// <i> 系统空闲任务的任务栈大小，单位为字节数
#define MCUCFG_STACKSIZE_SYSIDLE        128

#endif
// </e>
// </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                0

// <o> 中断开启
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例：EX0 = 1
#define mPendSV_Enable                  EX0 = 1

// <o> 中断关闭
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例：EX0 = 0
#define mPendSV_Disable                 EX0 = 0

// <o> 中断触发（置中断标志位）
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例：IE0 = 1
#define mPendSV_Set                     IE0 = 1

// <o> 中断清零（清中断标志位）
// <i> 此项您应在文本编辑界面中定义。
// <i> 即使该标志位能够在中断服务程序中硬件自动清零，仍建议用户不要省略，以确保其可靠清零。
// <i> 示例：IE0 = 0
#define mPendSV_Clear                   IE0 = 0

// </h>
///////////////////////////////////////////////////////////////////////////////
// <o> PendSV_FIFO深度
// <i> 此项参数取决于您在中断中调用挂起服务的总数及中断的频率。
// <i> 对于80251来说，CosyOS规定PendSV_FIFO的最大深度为120，您应妥善处理中断中调用的挂起服务，避免不必要的调用。
// <i> 可开启PendSV_FIFO监控功能，监控历史上的最大值，再适当增大，以确保其不会溢出。
#define MCUCFG_PENDSVFIFO_DEPTH         64
#if MCUCFG_PENDSVFIFO_DEPTH > 120
#error PendSV_FIFO深度值溢出！
#endif
///////////////////////////////////////////////////////////////////////////////
// <h> 动态内存设置
// <i> CosyOS会使用下列参数自动初始化内存池。

// <o> 内存池指针
// <i> 内存池的起始内存地址
#define MCUCFG_MALLOCMEMBPTR            2048
#if !MCUCFG_MALLOCMEMBPTR
#error 非法的设置值！
#endif

// <o> 内存池大小（Bytes）
// <i> 内存池大小，单位为字节数
#define MCUCFG_MALLOCMEMSIZE            2048
#if !MCUCFG_MALLOCMEMSIZE
#error 非法的设置值！
#endif

// </h>
///////////////////////////////////////////////////////////////////////////////
// <e> 自定义任务切换现场保护
// <i> CosyOS在任务切换时，默认自动保存的寄存器：{PCnext,DR28-DR8,DR4-DR0(REGBANK0),[PSW1],PSW,DPH,DPL}。
// <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_
#define _CONST_MEM_
#define _STACK_MEM_
#define _MALLOC_MEM_
#define _XDATA_MEM_   xdata
#define _OBJ_MEM_

/* Register */
#define _SYS_REG_

/* Typedef */
typedef bit     m_bit_t;
typedef s_u16_t m_sp_t;
typedef s_u8_t  m_taskmsg_t;
typedef s_u16_t m_fetion_t;
typedef s_u16_t m_stacksize_t;
typedef s_u32_t m_pc_t;
typedef s_u32_t m_tick_t;
typedef s_u32_t m_group_t;
#if MCUCFG_CODEROMSIZE == 0
typedef s_u16_t m_psp_t;
#else
typedef s_u32_t m_psp_t;
#endif
#define m_boolvoid_tf *(s_boolvoid_tfp)

/* Extern */
extern bit ebdata m_sign_fifo_0_0;
extern m_pc_t _SYS_MEM_ m_psp;
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(void *addr);

/* CONST & ATTRIBUTE */
#pragma WARNING DISABLE = 177
#define MCUCFG_ISA                __MCS_251__
#define MCUCFG_GNU                __DISABLED__
#define MCUCFG_NOP                _nop_()
#define MCUCFG_PCLEN              4
#if MCUCFG_SYSTICKREGBANK
#define MCUCFG_BANK0SIZE          8
#define MCUCFG_USING              using MCUCFG_SYSTICKREGBANK
#define MCUCFG_BASICSTACKSIZE     (32 - MCUCFG_4BYTEINTFRAME) /** \PUSH {PCnext,DR28-DR8,[PSW1],PSW,DPH,DPL} *//** \SAVE DR4-DR0(REGBANK0) */
#else
#define MCUCFG_BANK0SIZE          0
#define MCUCFG_USING
#define MCUCFG_BASICSTACKSIZE     (40 - MCUCFG_4BYTEINTFRAME) /** \PUSH {PCnext,DR28-DR8,DR4-DR0(REGBANK0),[PSW1],PSW,DPH,DPL} */
#endif
#define MCUCFG_C51USING
#define MCUCFG_SYSTICK_ATTRIBUTE  interrupt 1 MCUCFG_USING
#define MCUCFG_PENDSV_ATTRIBUTE   interrupt MCUCFG_PENDSVIRQ MCUCFG_USING
#define MCUCFG_251_REENTRANT      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        s_u32_t DR0_, s_u32_t DR4_, m_taskmsg_t R11_, m_taskmsg_t m0_
#define MCUCFG_TASKMSG_VAL        0, 0, 0, 1
#endif

/* 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          ((TH0 << 8) | TL0)
#define mSysTick_Disable          ET0 = 0
#define mSysTick_Enable           ET0 = 1

#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{ \
	s_init_mempool((void _MALLOC_MEM_ *)MCUCFG_MALLOCMEMBPTR, MCUCFG_MALLOCMEMSIZE); \
	OS_NOPx1; \
	AUXR = mSysTick_CLKMOD == 1 ? AUXR | 0x80 : AUXR &~0x80; \
	TMOD &= 0xF0; \
	TL0 = (s_u8_t)(mSysTick_InitValue); \
	TH0 = (s_u8_t)(mSysTick_InitValue >> 8); \
	TR0 = 1; \
	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 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; \
	m_psp -= (MCUCFG_BASICSTACKSIZE - 1); \
	s_pc = *(m_pc_t *)m_psp; \
	s_pc = ((s_u16_t)s_pc << 8) | ((s_u16_t)s_pc >> 8) | (s_pc & 0x00FF0000); \
}while(false)
#else
#define mTaskPC_Monitor do{}while(false)
#endif

#define mPendSV_Load \
do{ \
	mPendSV_Loader(&u_psv); \
	mPendSV_Set; \
}while(false)

#define mPendSV_Entry \
	mPendSV_Clear; \
	if(!m_sign_fifo_0_0) mPendSV_Handler()

#define miWriteFlagBits \
	if(!u_psv.value){ \
		do{}while(false)



/*
 * MSP模式
 */

#if MCUCFG_TASKSTACK_MODE == __MSP__

/* CONST & ATTRIBUTE */
#if SYSCFG_TASKCREATEMODE == __STATIC__
#define MCUCFG_TASKSTACK_REALLOC  __DISABLED__
#else
#define MCUCFG_TASKSTACK_REALLOC  __ENABLED__
#endif
#define MCUCFG_STACKSIZE_TASKMGR  (SYSCFG_TASKCREATEMODE != __STATIC__ ? MCUCFG_BASICSTACKSIZE + 8 : MCUCFG_BASICSTACKSIZE + 16)
#define MCUCFG_STACKSIZE_DEBUGGER (SYSCFG_TASKCREATEMODE != __STATIC__ ? MCUCFG_BASICSTACKSIZE + 8 : MCUCFG_BASICSTACKSIZE + 16)

/* MCUAPI */
#define mTaskNode_Head_           m_stacksize_t stacklen;

#define mSys_INIT \
do{ \
	m_msp = (SPH << 8) | SP; \
	m_bsp = m_msp + 1; \
	mSys_init; \
}while(false)

#define mScheduler_INIT \
	s_u8_t i; \
	m_stacksize_t stacklen; \
	s_u8_t  _STACK_MEM_  *msp8; \
	s_u8_t  _MALLOC_MEM_ *psp8; \
	s_u32_t _STACK_MEM_  *msp32; \
	s_u32_t _MALLOC_MEM_ *psp32; \
	s_sign_scheduling = false; \
	__asm{MOV m_psp, DR60}

#define mTaskStack_INIT \
do{ \
	*(s_u32_t *)node_news->bsp = ( \
		  ((s_u16_t)s_task_starter->entry << 8) \
		| ((s_u16_t)s_task_starter->entry >> 8) \
		| ((s_u32_t)s_task_starter->entry & 0xFFFF0000) \
	); \
	*(s_u8_t *)(node_news->bsp + MCUCFG_BASICSTACKSIZE - 3) = 0; \
	node_news->stacklen = MCUCFG_BASICSTACKSIZE; \
}while(false)

#define mTaskStack_LEN \
	stacklen = (m_sp_t)m_psp - m_msp

#define mTaskStack_PUSH \
do{ \
	msp32 = (s_u32_t _STACK_MEM_  *)m_bsp; \
	psp32 = (s_u32_t _MALLOC_MEM_ *)s_task_current->bsp; \
	s_task_current->stacklen = stacklen; \
	i = stacklen >> 2; \
	do{ \
		*psp32++ = *msp32++; \
	}while(--i); \
	i = stacklen & 3; \
	if(i){ \
		msp8 = (s_u8_t _STACK_MEM_  *)msp32; \
		psp8 = (s_u8_t _MALLOC_MEM_ *)psp32; \
		do{ \
			*psp8++ = *msp8++; \
		}while(--i); \
	} \
	mRegBank0_PUSH; \
	mUserReg_PUSH; \
	mTaskPC_Monitor; \
}while(false)

#define mTaskStack_POP \
do{ \
	s_task_current = node_news; \
	msp32 = (s_u32_t _STACK_MEM_  *)m_bsp; \
	psp32 = (s_u32_t _MALLOC_MEM_ *)s_task_current->bsp; \
	stacklen = s_task_current->stacklen; \
	i = stacklen >> 2; \
	do{ \
		*msp32++ = *psp32++; \
	}while(--i); \
	i = stacklen & 3; \
	if(i){ \
		msp8 = (s_u8_t _STACK_MEM_  *)msp32; \
		psp8 = (s_u8_t _MALLOC_MEM_ *)psp32; \
		do{ \
			*msp8++ = *psp8++; \
		}while(--i); \
	} \
	mRegBank0_POP; \
	mUserReg_POP; \
	m_psp = m_msp + stacklen; \
	__asm{MOV DR60, m_psp}; \
}while(false)



/*
 * PSP模式
 */

#elif MCUCFG_TASKSTACK_MODE == __PSP__

/* CONST & ATTRIBUTE */
#define MCUCFG_TASKSTACK_REALLOC  __DISABLED__

/* MCUAPI */
#define mTaskNode_Head_           m_psp_t psp;

#define mSys_INIT \
do{ \
	m_msp = (SPH << 8) | SP; \
	mSys_init; \
}while(false)

#if SYSCFG_DEBUGGING == __ENABLED__
#define mScheduler_INIT \
	m_stacksize_t stacklen; \
	s_sign_scheduling = false; \
	__asm{MOV m_psp, DR60}
#else
#define mScheduler_INIT \
	s_sign_scheduling = false; \
	__asm{MOV m_psp, DR60}
#endif

#define mTaskStack_INIT \
do{ \
	*(s_u32_t *)node_news->bsp = ( \
		  ((s_u16_t)s_task_starter->entry << 8) \
		| ((s_u16_t)s_task_starter->entry >> 8) \
		| ((s_u32_t)s_task_starter->entry & 0xFFFF0000) \
	); \
	*(s_u8_t *)(node_news->bsp + MCUCFG_BASICSTACKSIZE - 3) = 0; \
	node_news->psp = (m_sp_t)node_news->bsp + MCUCFG_BASICSTACKSIZE - 1; \
}while(false)

#if SYSCFG_DEBUGGING == __ENABLED__
#define mTaskStack_LEN \
	stacklen = (m_sp_t)m_psp + 1 - (m_sp_t)s_task_current->bsp
#else
#define mTaskStack_LEN do{}while(false)
#endif

#define mTaskStack_PUSH \
do{ \
	s_task_current->psp = m_psp; \
	mRegBank0_PUSH; \
	mUserReg_PUSH; \
	mTaskPC_Monitor; \
}while(false)

#define mTaskStack_POP \
do{ \
	s_task_current = node_news; \
	mRegBank0_POP; \
	mUserReg_POP; \
	m_psp = s_task_current->psp; \
	__asm{MOV DR60, m_psp}; \
}while(false)

#endif



#endif
