/*Begin Function:_Sys_Init*****************************************************
Description : Initiate The Application Memory Page Allocation.
Input       : Void.
Output      : Void.
******************************************************************************/
void _Sys_Init(void)						                                   //The Paramount Process;Its PID is 0,forever.	  
{
	u16 Count;
  
    while(1)
    {
        DISABLE_ALL_INTS();
#if(ENABLE_SIGNAL==TRUE)
    	for(Count=1;Count<MAX_NUMBER_OF_TASKS+1;Count++)				       //Process The Signals Here.
	    	_Sys_Signal_Handler(Count);
#endif
                                                                               //The Code Below Sets The Task Sequence.
       PCB_TASK_SEQ_PTR=0;			                                           //Reset The Process PTR.
       for(Count=1;Count<MAX_NUMBER_OF_TASKS+2;Count++)
       {		                                                               //From 1,For "Init" Do Not Count Here.
       		if(((PCB_PID_STATUS[Count]&OCCUPY)!=0)&&((PCB_PID_STATUS[Count]&SLEEP)==0)&&((PCB_PID_STATUS[Count]&ZOMBIE)==0))
            {	
                PCB_REMAINING_TIME[Count]=PCB_TIM[Count];
                PCB_TASK_SEQ[PCB_TASK_SEQ_PTR++]=Count;                        //Find Out The PIDs Occupied&Not Sleeping&Not Zombie And Create The Next Schedule Table.
            }
       }
       PCB_TASK_SEQ[PCB_TASK_SEQ_PTR]=0;			                           //The Last Must Be The Init process,Or The System Will Crash.Remember To Decrease The value By One,Or The System To Crash.
    
       PCB_TASK_SEQ_PTR=0;			                                           //Reset The Process PTR.
      
       ENABLE_ALL_INTS();  
       
       Sys_Switch_Now(); 
    }       
}
/* Begin Function:_Sys_Systick_Routine ****************************************
Description : The systick interrupt routine. No need to disable interrupts here, 
              because other interrupts may override it.
Input       : None.
Output      : None.
Return      : None.
******************************************************************************/
void _Sys_Systick_Routine(void)
{      
    /* Always increase the tick count by one */
    if(System_Status.Time.OS_Total_Ticks.Low_Bits==0xFFFFFFFF)
    {
        System_Status.Time.OS_Total_Ticks.Low_Bits=0;
        System_Status.Time.OS_Total_Ticks.High_Bits++;
    }
    else
        System_Status.Time.OS_Total_Ticks.Low_Bits++;
    
    /* Process the signals again here, because the process may receive signals from ISR */
    _Sys_Signal_Handler(Current_PID);
    
    /* Process the timers here - see if any of them is expired */
    _Sys_Timer_Handler(); 
    /* Process the system process delay here - see if any of them is expired */
    _Sys_Proc_Delay_Handler();
    /* Do a scheduling here */
    _Sys_Schedule_Trigger();
}
/* Begin Function:_Sys_Get_High_Ready *****************************************
Description : The function for deciding the highest priority task.
              The routine has a very simple way to decide who's the final
              task to run at last-it will set the "Current_PID" and the 
              "Current_Prio" correspondingly, and this only the two variables
              will be used by the assembly function.
              There's no need to disable interrupts here; because this is always 
              at the lowest priority.
Input       : None.
Output      : None.
Return      : None.
******************************************************************************/
void _Sys_Get_High_Ready(void)
{		  
    /* See if the scheduler is locked .If yes, then we cannot switch the tasks */
    if(Scheduler_Locked==0)
    {  
        /* The system is booting from "Init" process. We need do abandon the SP automatically
         * saved by the "SYS_SAVE_SP" assembly function this time.
         */
        if(System_Status.Kernel.Boot_Done==FALSE)
        {
            PCB_Cur_SP[0]=PCB[0].Info.Init_Stack_Ptr-PRESET_STACK_SIZE;
            System_Status.Kernel.Boot_Done=TRUE;
        }
        
        /*If possible, decrease the remaining timeslice by 1.*/ 
        if(PCB[Current_PID].Time.Lft_Tim>0)
        {   
            PCB[Current_PID].Time.Lft_Tim-=1;                        
        } 
        else
        {
            /* Refresh the timer */
            PCB[Current_PID].Time.Lft_Tim=PCB[Current_PID].Time.Cur_Tim;  
            
            /* If the priority level still exists, then perform a normal context switch */
            if(Prio_List[Current_Prio].Proc_Num!=0)
            {
                /* Do normal context switch first - See if the current process is running */
                if(((struct PCB_Struct*)
                    (Prio_List[Current_Prio].Running_List.Next))
                   ->Info.PID==Current_PID)
                {
                    /* If the current process is running, then put it at the end of the queue */
                    Sys_List_Delete_Node(PCB[Current_PID].Head.Prev,PCB[Current_PID].Head.Next);
                    Sys_List_Insert_Node((struct List_Head*)&(PCB[Current_PID].Head),
                                         Prio_List[Current_Prio].Running_List.Prev, 
                                         (struct List_Head*)&(Prio_List[Current_Prio].Running_List));
                }
                else
                {
                    /* Do nothing - The current process is not running */
                }
            }
        } 
        
        /* Now get the highest priority level's next process to run */
        Current_Prio=((struct Prio_List_Struct*)(Prio_List_Head.Next))->Priority;
        Current_PID=((struct PCB_Struct*)
                     (Prio_List[Current_Prio].Running_List.Next))
                    ->Info.PID;
    }
    else
    {
        /* One of the scheduling action is pending due to scheduler lock. So 
         * after the scheduler unlocks, we will perform a schedule right away.
         */
        Pend_Sched_Cnt++;
    }
    
    /* Refresh the system status,which is only for query*/
    System_Status.Kernel.Proc_Running_Ptr=(struct List_Head*)(&(PCB[Current_PID].Head)); 
    System_Status.Kernel.Cur_Prio_Ptr=(struct List_Head*)(&(Prio_List[PCB[Current_PID].Status.Priority].Head));                 

    /* Process the signals here - The signal handlers will be directly called */
    _Sys_Signal_Handler(Current_PID);
}