/*
*********************************************************************************************************
*                                               uC/OS-II
*                                         The Real-Time Kernel
*
*                             (c) Copyright 2010, Micrium, Inc., Weston, FL
*                                          All Rights Reserved
*
*                                                MIPS14K
*							                	MicroMips
*
*
* File    : os_cpu_c.c
* Version : v2.90
* By      : NB
*********************************************************************************************************
*/

#define   OS_CPU_GLOBALS

#include  "includes.h"

/*
*********************************************************************************************************
*                                        OS INITIALIZATION HOOK
*                                             (BEGINNING)
*
* Description: This function is called by OSInit() at the beginning of OSInit().
*
* Arguments  : None
*
* Note(s)    : 1) Interrupts should be disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void  OSInitHookBegin (void)
{
}
#endif

/*
*********************************************************************************************************
*                                        OS INITIALIZATION HOOK
*                                                (END)
*
* Description: This function is called by OSInit() at the end of OSInit().
*
* Arguments  : None
*
* Note(s)    : 1) Interrupts should be disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void  OSInitHookEnd (void)
{
}
#endif

/*
*********************************************************************************************************
*                                          TASK CREATION HOOK
*
* Description: This function is called whenever a task is created.
*
* Arguments  : ptcb    is a pointer to the task control block of the task being created.
*
* Note(s)    : 1) Interrupts are disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0
void  OSTaskCreateHook (OS_TCB *ptcb)
{
}
#endif

/*
*********************************************************************************************************
*                                          TASK DELETION HOOK
*
* Description: This function is called when a task is deleted.
*
* Arguments  : ptcb    is a pointer to the task control block of the task being deleted.
*
* Note(s)    : 1) Interrupts are disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0
void  OSTaskDelHook (OS_TCB *ptcb)
{
    ptcb = ptcb;                       /* Prevent compiler warning                                     */
}
#endif

/*
*********************************************************************************************************
*                                           TASK RETURN HOOK
*
* Description: This function is called when a task returns without being properly deleted.
*
* Arguments  : ptcb   is a pointer to the task control block of the task that was accidently returned.
*
* Note(s)    : 1) Interrupts are disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 
void  OSTaskReturnHook (OS_TCB *ptcb)
{
    ptcb = ptcb;                       /* Prevent compiler warning                                     */
}
#endif


/*
*********************************************************************************************************
*                                            IDLE TASK HOOK
*
* Description: This function is called by the idle task.  This hook has been added to allow you to do
*              such things as STOP the CPU to conserve power.
*
* Arguments  : None
*
* Note(s)    : 1) Interrupts are enabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION >= 251
void  OSTaskIdleHook (void)
{

} 
#endif

/*
*********************************************************************************************************
*                                          STATISTIC TASK HOOK
*
* Description: This function is called every second by uC/OS-II's statistics task.  This allows your
*              application to add functionality to the statistics task.
*
* Arguments  : None
*********************************************************************************************************
*/

#if OS_CPU_HOOKS_EN > 0
void  OSTaskStatHook (void)
{
}
#endif

/*
*********************************************************************************************************
*                                        INITIALIZE A TASK'S STACK
*
* Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the
*              stack frame of the task being created.  This function is processor-specific.
*
* Arguments  : task     is a pointer to the task code.
*
*              p_arg    is a pointer to a user supplied data area 
*
*              ptos     is a pointer to the top of stack.  OSTaskStkInit() assumes that 'ptos' points to 
*                       a free entry on the stack.  If OS_STK_GROWTH is set to 1 then 'ptos' will contain 
*                       the HIGHEST valid address of the stack.  Similarly, if OS_STK_GROWTH is set to 0, 
*                       'ptos' will contain the lowest valid address of the stack.
*
*              opt      specifies options that can be used to alter the behavior of OSTaskStkInit()
*                       (see ucos_ii.h for OS_TASK_OPT_???).
*
* Returns    : The location corresponding to the top of the stack
*
* Note(s)    : 1) Interrupts are enabled when each task starts executing.
* 
*              2) An initialized stack has the structure shown below.
*
*              OSTCBHighRdy->OSTCBStkPtr + 0x00    Free Entry                    (LOW Memory)
*                                        + 0x04    Status Register
*                                        + 0x08    EPC
*                                        + 0x0C    Special Purpose LO Register
*                                        + 0x10    Special Purpose HI Register
*                                        + 0x14    GPR[1]
*                                        + 0x18    GPR[2]
*                                        + 0x1C    GPR[3]
*                                        + 0x20    GPR[4]
*                                        + 0x24    GPR[5]
*                                        + 0x28    GPR[6]
*                                        + 0x2C    GPR[7]
*                                        + 0x30    GPR[8]
*                                        + 0x34    GPR[9]
*                                        + 0x38    GPR[10]
*                                        + 0x3C    GPR[11]
*                                        + 0x40    GPR[12]
*                                        + 0x44    GPR[13]
*                                        + 0x48    GPR[14]
*                                        + 0x4C    GPR[15]
*                                        + 0x50    GPR[16]
*                                        + 0x54    GPR[17]
*                                        + 0x58    GPR[18]
*                                        + 0x5C    GPR[19]
*                                        + 0x60    GPR[20]
*                                        + 0x64    GPR[21]
*                                        + 0x68    GPR[22]
*                                        + 0x6C    GPR[23]
*                                        + 0x70    GPR[24]
*                                        + 0x74    GPR[25]
*                                        + 0x78    GPR[26]
*                                        + 0x7C    GPR[27]
*                                        + 0x80    GPR[28]
*                                        + 0x84    GPR[30]
*                                        + 0x88    GPR[31]                       (HIGH Memory)
*********************************************************************************************************
*/

OS_STK  *OSTaskStkInit (void  (*task)(void *pd), 
			void   *p_arg, 
			OS_STK *ptos, 
			INT16U  opt)
{
    INT32U  *pstk;
    INT32U   sr_val;
    INT32U   gp_val;


    (void)opt;                                 /* Prevent compiler warning for unused arguments        */              

    asm volatile("mfc0   %0,$12"   : "=r"(sr_val));
    sr_val  |= 0x0000C401;                     /* Initialize stack to allow for tick interrupt         */

    asm volatile("addi   %0,$28,0" : "=r"(gp_val));

    pstk     = (INT32U *)ptos; 

    pstk--;                                    /* Ensure that a free entry is being referenced         */
    *pstk--  = (INT32U)task;                   /* GPR[31] (ra) is used by OSStartHighRdy()             */
    *pstk--  = (INT32U)0x30303030;             /* GPR[30]                                              */
    *pstk--  = gp_val;                         /* GPR[28]                                              */
    *pstk--  = (INT32U)0x27272727;             /* GPR[27]                                              */
    *pstk--  = (INT32U)0x26262626;             /* GPR[26]                                              */
    *pstk--  = (INT32U)0x25252525;             /* GPR[25]                                              */
    *pstk--  = (INT32U)0x24242424;             /* GPR[24]                                              */
    *pstk--  = (INT32U)0x23232323;             /* GPR[23]                                              */
    *pstk--  = (INT32U)0x22222222;             /* GPR[22]                                              */
    *pstk--  = (INT32U)0x21212121;             /* GPR[21]                                              */
    *pstk--  = (INT32U)0x20202020;             /* GPR[20]                                              */
    *pstk--  = (INT32U)0x19191919;             /* GPR[19]                                              */
    *pstk--  = (INT32U)0x18181818;             /* GPR[18]                                              */
    *pstk--  = (INT32U)0x17171717;             /* GPR[17]                                              */
    *pstk--  = (INT32U)0x16161616;             /* GPR[16]                                              */
    *pstk--  = (INT32U)0x15151515;             /* GPR[15]                                              */
    *pstk--  = (INT32U)0x14141414;             /* GPR[14]                                              */
    *pstk--  = (INT32U)0x13131313;             /* GPR[13]                                              */
    *pstk--  = (INT32U)0x12121212;             /* GPR[12]                                              */
    *pstk--  = (INT32U)0x11111111;             /* GPR[11]                                              */
    *pstk--  = (INT32U)0x10101010;             /* GPR[10]                                              */
    *pstk--  = (INT32U)0x09090909;             /* GPR[9]                                               */
    *pstk--  = (INT32U)0x08080808;             /* GPR[8]                                               */
    *pstk--  = (INT32U)0x07070707;             /* GPR[7]                                               */
    *pstk--  = (INT32U)0x06060606;             /* GPR[6]                                               */
    *pstk--  = (INT32U)0x05050505;             /* GPR[5]                                               */
    *pstk--  = (INT32U)0x04040404;             /* GPR[4]                                               */
    *pstk--  = (INT32U)0x03030303;             /* GPR[3]                                               */
    *pstk--  = (INT32U)0x02020202;             /* GPR[2]                                               */
    *pstk--  = (INT32U)0x01010101;             /* GPR[1]                                               */
    *pstk--  = (INT32U)0x00000000;             /* Special Purpose HI Register                          */
    *pstk--  = (INT32U)0x00000000;             /* Special Purpose LO Register                          */
    *pstk--  = (INT32U)task;                   /* EPC                                                  */
    *pstk--  = sr_val;                         /* SR                                                   */

    return ((OS_STK *)pstk);                   /* Return new top of stack                              */
}

/*
*********************************************************************************************************
*                                           TASK SWITCH HOOK    
*
* Description: This function is called when a task switch is performed.  This allows you to perform 
*              other operations during a contex switch.
*
* Arguments  : None
*
* Note(s)    : 1) Interrupts are disabled during this call.
*              2) It is assumed that the global pointer OSTCBHighRdy points to the TCB of the task that 
*                 will be switched in (i.e. the highest priority task), and that OSTCBCur points to the
*                 task being switched out (i.e. the preempted task).
*********************************************************************************************************
*/
#if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
void  OSTaskSwHook (void)
{
}
#endif       

/*
*********************************************************************************************************
*                                            OS_TCBInit() HOOK 
*
* Description: This function is called by OS_TCBInit() after setting up most of the TCB.
*
* Arguments  : ptcb    is a pointer to the TCB of the task being created.
*
* Note(s)    : 1) Interrupts may or may not be ENABLED during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void  OSTCBInitHook (OS_TCB *ptcb)
{
    ptcb = ptcb;                       /* Prevent compiler warning                                     */
}
#endif

/*
*********************************************************************************************************
*                                              TICK HOOK
*
* Description: This function is called after every tick interrupt.
*
* Arguments  : None
*
* Note(s)    : 1) Interrupts may or may not be ENABLED during this call.
*********************************************************************************************************
*/
#if (OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0)
void  OSTimeTickHook (void)
{
}
#endif

/*
*********************************************************************************************************
*                                              BSP_Interrupt_Handler
*
* Description: 中断发生时会调用本函数处理具体的中断事宜
*
* Arguments  : None
*
* Note(s)    : 1) Interrupts may or may not be ENABLED during this call.
*********************************************************************************************************
*/
void  BSP_Interrupt_Handler (void)
{
    INT32U   cause_val;
    INT32U   cause_reg;
    INT32U   cause_ip;
    asm ("mfc0   %0,$13"   : "=r"(cause_val));
    cause_reg  = cause_val;                     /* 得到Exc Code        */
    cause_ip = cause_reg & 0x0000FF00;
    //uart_print_str("I am in BSP_Interrupt_Handler  ");
    if((cause_ip & 0x00000400) != 0 )
    {
    	//uart_print_str("Ready To Call TickISR  ");
        TickISR(0x50000);
        asm ("mfc0   %0,$13"   : "=r"(cause_val));
        cause_val = cause_val & 0xfffffbff;
        //asm volatile("mtc0   %0,$13" : : "r"(cause_val));
    	/*TickInterruptClear();*/
    }
}

/*
*********************************************************************************************************
*                                              BSP_Exception_Handler
*
* Description: 调用syscall指令、Txx指令、invalid instruciton发生时会调用本函数处理具体的异常事宜
*
* Arguments  : None
*
* Note(s)    : 1) Interrupts may or may not be ENABLED during this call.
*********************************************************************************************************
*/
void  BSP_Exception_Handler (void)
{
    INT32U   cause_val;
    INT32U   cause_exccode;
    INT32U   EPC;
    asm volatile("mfc0   %0,$13"   : "=r"(cause_val));
    cause_exccode  = (cause_val & 0x0000007C);                     /* 得到Exc Code        */
    if(cause_exccode == 0x00000020 )                             /* 判断是否是由于syscall指令引起 */
    {
    	OSIntCtxSw();                                           
    }
    else if(cause_exccode == 0x00000034)                         /* 判断是否是由于Txx指令引起 */
    {
    	OSIntCtxSw();
    }
    else if(cause_exccode == 0x00000028)                          /* 判断是否是由于invalid instruction引起 */
    {
    	asm volatile("mfc0   %0,$14"   : "=r"(EPC));
      //uart_print_str("Error Cause By Invalid Instruction");
      //uart_print_str("The Address of Invalid Instruction is");
    	//uart_print_int(EPC);
    	//uart_print_str("\n");
    	//if((cause_val & 0x80000000) !=0 )
    		//uart_print_str("Invalid Instruction is in delay slot");
     // else
      //	uart_print_str("Invalid Instruction is not in delay slot");
    } 
}
