
//linkboyר
//Ƕʽϵͳ - votex

//˵һЭʽϵͳ,Ϊں˺,ں˲и,
//ʱ,ִƵΪ1000Hz(ÿ1msɨ)
//㲿ַɨȫ,ÿжջռ,ͨ"schedule"ýл.

//...ע
// * ޸ SP ĵطҪϹжϱ

//...汾¼
//2012 ʼ汾
//2013.2.18 ںӾ̬Ϊ̬ע뷽ʽ
//2013.2.28 ¼˳ɳ,ͼνвҪ

//2013.6.16 ʱж ע͵ //MCU TIFR = 0b0000_0010, ҪϵͳǷȶ

//2013.10.31
//ѵĳʺͼλ̵ķʽ,ÿ¼˳󲻻Զִ,
//Զ̬¼.

//2014.1.14
//˿л, ע100usں; ǰİ汾СмΪ1000us
//ҪΪֵ֧, LEDƹȿƵȸ

//2014118 ҹ 11:58
//һ, ֻҪ̳رƾͻᴥ, TCBҪݷŵ,ǰ

//20141012 9:52
//Աť, תϵͳס, һʼΪжϸ, Ϊת¼
//ʱָ, 񴴽쵼̳߳,  CreateTask ж, 
//̳߳Ļ͵һ, ֱͷŵеĳ߳.

//201532 9:31
//¼Դ, ʶһ¼Ƿִ, ֹ¼뵼´ǰͻ; ͼν
//ÿ¼Զһ, һʱͻᱻеļָס, ֱ˳Ϊֹ.
//ťͨ, Чǳ.

//2015326 
//׼ѲϵͳֲMEGA644, ҼMEGA32
// * //MCU.SFIOR.2(bit) = 1; ﲻ, Ϊ1ǽֹ

unit OS
{
	//---------------------------------------------------
	public void OS_init()
	{
		#asm "CLI"
		
		//رտŹ
		CloseWatchdog();
		
		//˿ڳʼ
		//ע!! MEGA32, MEGA324һ.
		//һ˼·: Ĵǰ߼,  M32_SFIOR, M32_MCUCR, M324_MCUCR, ...
		
		//ʼ˿
		//ﲻ԰??? ӦΪ0Ч(2015.3.26)
		//MCU.SFIOR.2(bit) = 1;
		
		//ԲҪʼ, ΪλʱӲʼ
		//MCU.DDRA = 0x00;
		//MCU.PORTA = 0x00;
		//MCU.DDRB = 0x00;
		//MCU.PORTB = 0x00;
		//MCU.DDRC = 0x00;
		//MCU.PORTC = 0x00;
		//MCU.DDRD = 0x00;
		//MCU.PORTD = 0x00;
		
		//ʱʼ(޹)
		TimerInit();
		
		//ںʱʼ
		DriverInit();
		
		//OSں˳ʼ
		KernelInit();
		
		tick = 0;
	}
	//=================================================================================
	[uint8*RUN_NUMBER] TickList;
	[uint8*RUN_NUMBER] MaxTickList;
	[uint16*RUN_NUMBER] DriverHandleList;
	
	//..........................
	//ע DriverNumber ɲϵͳʹ,ڵȱ߽,
	// RUN_NUMBER ڶ㹻Ĵ洢,߼
	
	//ں
	uint8 DriverNumber;
	//С洢߽
	public const uint8 RUN_NUMBER = 0;
	//..........................
	
	[uint16*RUN100us_NUMBER] Driver100usHandleList;
	
	//..........................
	//ע Driver100usNumber ɲϵͳʹ,ڵȱ߽,
	// RUN100us_NUMBER ڶ㹻Ĵ洢,߼
	
	//ں
	uint8 Driver100usNumber;
	//С洢߽
	public const uint8 RUN100us_NUMBER = 0;
	//..........................
	
	uint8 tick;
	
	public uint8 DebugTick;
	
	//=================================================================================
	//ṩ¶
	//	* CloseWatchdog()
	//	* TimerInit()
	//궨	* ʱж
	//궨	* رնʱжӦ
	//궨	* ж϶ʱӦ
	#include "$chip$.txt"
	
	//ʱʼ, ͨ궨滻ĺ, ӳ䵽ӦĵƬʱ
	//void TimerInit()
	//=================================================================================
	
	//---------------------------------------------------
	//жϷ,עտʼж,ж(ڵ)
	//ʱһtickѾٴӶ½,ɸ.
	//ǧû! һжʱжϱ־
	//MCU TIFR | 0b0000_0010; ERROR!
	MACRO_TIMER_TICK
	void OS_run()
	{
		MACRO_TIMER_OFF();
		
		//עʱжϱ־,ϵͳǷȶ
		//MCU TIFR = 0b0000_0010;
		#asm "SEI"
		
		//пںб
		RunDriver100usList();
		
		//б,
		tick + 1;
		if( tick >= 10 ) {
			RunDriverList();
			tick = 0;

			DebugTick += 1;
		}
		#asm "CLI"
		
		MACRO_TIMER_ON();
	}
	//---------------------------------------------------
	//ʼںʱ
	void DriverInit()
	{
		DriverNumber = 0;
		for( uint8 i = 0; i < RUN_NUMBER; i + 1 ) {
			TickList[i] = 0;
			MaxTickList[i] = 0;
			DriverHandleList[i] = 0;
		}
		Driver100usNumber = 0;
	}
	//---------------------------------------------------
	//עں˽
	public void CreateDriver( uint16 Handle, uint8 MaxTick )
	{
		DriverHandleList[DriverNumber] = Handle;
		MaxTickList[DriverNumber] = MaxTick;
		DriverNumber + 1;
	}
	//---------------------------------------------------
	//עں˽
	public void CreateDriver100us( uint16 Handle )
	{
		Driver100usHandleList[Driver100usNumber] = Handle;
		Driver100usNumber + 1;
	}
	//---------------------------------------------------
	//б,
	void RunDriverList()
	{
		for( uint8 i = 0; i < DriverNumber; i + 1 ) {
			TickList[i] + 1;
			if( TickList[i] == MaxTickList[i] ) {
				TickList[i] = 0;
				D_CALL( DriverHandleList[i] );
			}
		}
	}
	//---------------------------------------------------
	//б,
	void RunDriver100usList()
	{
		for( uint8 i = 0; i < Driver100usNumber; i + 1 ) {
			D_CALL( Driver100usHandleList[i] );
		}
	}
	//---------------------------------------------------
	//̬÷װ,ַʽͨ
	void D_CALL( uint16 Handle )
	{
		#asm "ldd r30,y+0"
		#asm "ldd r31,y+1"
		
		//һַʽ: ͨרָICALLӵ R30 R31 ָĵַ
		#asm "ICALL"
		
		//ڶַʽ: ͨ ret Ͷջ R30 R31 ָĵַ
//		#asm "push r30"
//		#asm "push r31"
//		#asm "ret"
	}
	//=================================================================================
	//ƿ
	struct TCB
	{
		//ʹõĴ洢ռ,ڶջַ,ֲ͵úַı
		//ջݸʽ(ʼ״̬):
		//λ: 0    1    2   ~~   L-8  L-7  L-6  L-5  L-4  L-3  L-2  L-1
		//Ԫ: *    *    *   ~~   R29  R28  PCE  PCH  PCL  SHE  SDH  SDL
		//ջָ: *    *    *   ~~   /^\   *    *    *    *    *    *    * 
		[uint8*STACK_LENGTH] Stack;
		
		//ռõԴ(¼), 0ʱʾӦ¼ڱռ
		->uint8 e_res_count;
		
		//Ƿʹ
		bool open;

		//ǰ󶨵¼ָ
		uint16 EventProc;
		
		//ĵǰSPָ
		uint16 SP;
	}
	[struct TCB * TASK_NUMBER] AppTCB;
	
	//ÿռݵĴ洢ռС
	const uint16 STACK_LENGTH = 200;
	
	//ǰ
	uint16 CurrentTaskIndex;
	
	//С洢߽
	const uint16 TASK_NUMBER = 5;
	//...................
	
	//ջָ
	uint16 SP = #addr 0x5D;
	
	//---------------------------------------------------
	//ں˳ʼ
	void KernelInit()
	{
		CurrentTaskIndex = 0;
		for( uint8 i = 0; i < TASK_NUMBER; i + 1 ) {
			AppTCB[i].open = false;
		}
	}
	//---------------------------------------------------
	//ʼ
	public void Start()
	{
		SP = AppTCB[0].SP;
		#asm "POP R29"
		#asm "POP R28"
		#asm "RETI"
	}
	//---------------------------------------------------
	//ִֹһָŵ¼
	public void TrigEvent( uint8 i )
	{
		#asm "PUSH R28"
		#asm "PUSH R29"
		
		AppTCB[CurrentTaskIndex].SP = SP;
		
		CurrentTaskIndex = i;
		
		//׼лĽ
		uint16 BSP = AppTCB[CurrentTaskIndex].SP;
		
		//һҪж,Ϊ SP һ16λ,ڼ䱻ж
		#asm "CLI"
		SP = BSP;
		#asm "SEI"
		
		#asm "POP R29"
		#asm "POP R28"
		#asm "RET"
	}
	//---------------------------------------------------
	//עһ¼¼б
	public uint8 CreateTask( uint16 Proc )
	{
		//ʱ, ݵĵײ
		uint16 NP;
		->uint8 P;
		
		//һеĽ, ̳߳˵Ļ, Զһνͷ
		uint8 i = 0;
		forever {
			if( !AppTCB[i].open ) {
				break;
			}
			i + 1;
			//i % TASK_NUMBER;
			if( i == TASK_NUMBER ) {
				i = 0;
				Schedule();
			}
		}
		//󶨵ǰ̵¼ָ
		AppTCB[i].EventProc = Proc;

		//¼
		AppTCB[i].Stack[STACK_LENGTH - 4] = Proc.0(uint8);
		AppTCB[i].Stack[STACK_LENGTH - 5] = Proc.8(uint8);
		AppTCB[i].Stack[STACK_LENGTH - 6] = 0;
		
		//¼ɳ,֤¼ȫ˳
		uint16 SandboxHandle = #addr EventSandbox;
		AppTCB[i].Stack[STACK_LENGTH - 1] = SandboxHandle.0(uint8);
		AppTCB[i].Stack[STACK_LENGTH - 2] = SandboxHandle.8(uint8);
		AppTCB[i].Stack[STACK_LENGTH - 3] = 0;
		
		//¼ռ
		P -> AppTCB[i].Stack[0];
		#asm "LDD r30,y+&P"
		#asm "LDD r31,y+&P+1"
		#asm "STD y+&NP,r30"
		#asm "STD y+&NP+1,r31"
		AppTCB[i].Stack[STACK_LENGTH - 7] = NP.0(uint8);
		AppTCB[i].Stack[STACK_LENGTH - 8] = NP.8(uint8);
		
		//ý̵¼Դ
		if( i != 0 ) {
			AppTCB[i].e_res_count -> AppTCB[CurrentTaskIndex].e_res_count;
			AppTCB[i].e_res_count + 1;
		}
		
		//öջָ,ָջβ,ƶ6PCָ(ɳ  ¼ʼ)  2ջָĿռ
		P -> AppTCB[i].Stack[STACK_LENGTH - 1 - 8];
		#asm "LDD r30,y+&P"
		#asm "LDD r31,y+&P+1"
		#asm "STD y+&NP,r30"
		#asm "STD y+&NP+1,r31"
		AppTCB[i].SP = NP;
		
		AppTCB[i].open = true;

		return i;
	}
	//---------------------------------------------------
	//һε, ѵǰֲָ뱣浽ǰĶջ,
	//Ȼлһ,ӦľֲָPC,һ
	public void Schedule()
	{
		#asm "PUSH R28"
		#asm "PUSH R29"
		
		AppTCB[CurrentTaskIndex].SP = SP;
		
		//һĽ
		forever {
			CurrentTaskIndex + 1;
			CurrentTaskIndex % TASK_NUMBER;
			if( AppTCB[CurrentTaskIndex].open ) {
				break;
			}
		}
		//׼лĽ
		uint16 BSP = AppTCB[CurrentTaskIndex].SP;
		
		//һҪж,Ϊ SP һ16λ,ڼ䱻ж
		#asm "CLI"
		SP = BSP;
		#asm "SEI"
		
		#asm "POP R29"
		#asm "POP R28"
		#asm "RET"
	}
	//---------------------------------------------------
	//ָ¼
	public void DeleteTask( uint16 Proc )
	{
		//¼̳
		uint8 i = 0;
		loop( TASK_NUMBER ) {
			if( AppTCB[i].open && AppTCB[i].EventProc == Proc ) {
				AppTCB[i].e_res_count = 0;
				AppTCB[i].open = false;
			}
			i + 1;
		}
	}
	//---------------------------------------------------
	//¼ɳ, ȷ¼ȫ˳
	void EventSandbox()
	{
		AppTCB[CurrentTaskIndex].e_res_count - 1;
		
		//ռû¼ռ,6洢Ԫ(PCָ),ֹ±ߵĴи¼ջʼ
		#asm "CLI"
		SP - 6;
		#asm "SEI"
		
		AppTCB[CurrentTaskIndex].open = false;
		Schedule();
	}
	//---------------------------------------------------
	//ʱ
	void SafelineDelay()
	{
		loop( 250 ) loop( 250 ) {}
	}
}







