/*
    FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd.
    All rights reserved

    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

    ***************************************************************************
     *                                                                       *
     *    FreeRTOS provides completely free yet professionally developed,    *
     *    robust, strictly quality controlled, supported, and cross          *
     *    platform software that has become a de facto standard.             *
     *                                                                       *
     *    Help yourself get started quickly and support the FreeRTOS         *
     *    project by purchasing a FreeRTOS tutorial book, reference          *
     *    manual, or both from: http://www.FreeRTOS.org/Documentation        *
     *                                                                       *
     *    Thank you!                                                         *
     *                                                                       *
    ***************************************************************************

    This file is part of the FreeRTOS distribution.

    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.

    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
    >>!   distribute a combined work that includes FreeRTOS without being   !<<
    >>!   obliged to provide the source code for proprietary components     !<<
    >>!   outside of the FreeRTOS kernel.                                   !<<

    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available from the following
    link: http://www.freertos.org/a00114.html

    1 tab == 4 spaces!

    ***************************************************************************
     *                                                                       *
     *    Having a problem?  Start by reading the FAQ "My application does   *
     *    not run, what could be wrong?"                                     *
     *                                                                       *
     *    http://www.FreeRTOS.org/FAQHelp.html                               *
     *                                                                       *
    ***************************************************************************

    http://www.FreeRTOS.org - Documentation, books, training, latest versions,
    license and Real Time Engineers Ltd. contact details.

    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.

    http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
    Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and MiddleWare.

    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.

    1 tab == 4 spaces!
*/

/*-----------------------------------------------------------
 * Implementation of functions defined in portable.h for the RISC32 port.
 *----------------------------------------------------------*/

#include <mips/hal.h>
#include <mips/m32c0.h>
#include <string.h>

/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"

/* Timer handling files */
#include "port_timer.h"

/* Interrupt handler */
#include "int_handler.h"

/* Let the user override the pre-loading of the initial RA with the address of
prvTaskExitError() in case is messes up unwinding of the stack in the
debugger - in which case configTASK_RETURN_ADDRESS can be defined as 0 (NULL). */
#ifdef configTASK_RETURN_ADDRESS
    #define portTASK_RETURN_ADDRESS    configTASK_RETURN_ADDRESS
#else
    #define portTASK_RETURN_ADDRESS    prvTaskExitError
#endif

/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task
stack checking.  A problem in the ISR stack will trigger an assert, not call the
stack overflow hook function (because the stack overflow hook is specific to a
task stack, not the ISR stack). */
#if( configCHECK_FOR_STACK_OVERFLOW > 2 )

    /* Don't use 0xa5 as the stack fill bytes as that is used by the kernel for
    the task stacks, and so will legitimately appear in many positions within
    the ISR stack. */
    #define portISR_STACK_FILL_BYTE    0xee

    static const uint8_t ucExpectedStackBytes[] = {
                                    portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE,        \
                                    portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE,        \
                                    portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE,        \
                                    portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE,        \
                                    portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE };    \

    #define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) )
#else
    /* Define the function away. */
    #define portCHECK_ISR_STACK()
#endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */

/*-----------------------------------------------------------*/

/*
 * Place the prototype here to ensure the interrupt vector is correctly installed.
 * Note that because the interrupt is written in assembly, the IPL setting in the
 * following line of code has no effect.  The interrupt priority is set by the
 * call to ConfigIntTimer1() in vApplicationSetupTickTimerInterrupt().
 */
extern void vPortTickInterruptHandler( void );

/*
 * Used to catch tasks that attempt to return from their implementing function.
 */
static void prvTaskExitError( void );

/*-----------------------------------------------------------*/

/* Records the interrupt nesting depth. - unused currently as no int stack */
volatile UBaseType_t uxInterruptNesting = 0x0;

/* Stores the task stack pointer when a switch is made to use the system stack. */
UBaseType_t uxSavedTaskStackPointer = 0;

/* The stack used by interrupt service routines that cause a context switch. */
StackType_t xISRStack[ configISR_STACK_SIZE ] = { 0 };

/* The top of stack value ensures there is enough space to store 6 registers on
the callers stack, as some functions seem to want to do this. */
const StackType_t * const xISRStackTop = &( xISRStack[ configISR_STACK_SIZE - 7 ] );

#ifdef __mips_hard_float
/* pointer to the current and old fpu context for lazy context switching */
struct fp64ctx *currentfpctx;    /* fpu context of current running task */
struct fp64ctx *oldfpctx;        /* fpu context of last task that executed fpu */
#endif

/*-----------------------------------------------------------*/

/*
 * See header file for description.
 */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
    *pxTopOfStack = (StackType_t) 0xDEADBEEF;
    pxTopOfStack--;

    *pxTopOfStack = (StackType_t) 0x12345678;       /* Word to which the stack pointer will be left pointing after context restore. */
    pxTopOfStack--;

#ifdef __mips_hard_float
    *pxTopOfStack = (StackType_t) 0; /* padding for 8-byte alignment */
    pxTopOfStack--;
    *pxTopOfStack = (StackType_t) 0; /* pointer to fpu context */
    pxTopOfStack--;
#endif

    /* create a space for a full context */
    pxTopOfStack -= CTX_SIZE/4;
#ifdef __mips_dsp
    pxTopOfStack -= DSPCTX_SIZE/4;
#endif

    /* fill up some initial values for us to kick in */
    *( pxTopOfStack + CTX_CAUSE/4 ) = (StackType_t) mips_getcr();
    *( pxTopOfStack + CTX_STATUS/4 ) = (StackType_t) (mips32_get_c0(C0_STATUS) | portINITIAL_SR | SR_TIMER_IRQ );
    *( pxTopOfStack + CTX_EPC/4 ) = (StackType_t) pxCode;
    *( pxTopOfStack + CTX_RA/4 ) = (StackType_t) portTASK_RETURN_ADDRESS;
    *( pxTopOfStack + CTX_A0/4 ) = (StackType_t) pvParameters; /* Parameters to pass in. */

    /* Save GP register value in the context */
     asm volatile ("sw $gp, %0" : "=m" (*( pxTopOfStack + CTX_GP/4 )));

    return pxTopOfStack;
}
/*-----------------------------------------------------------*/

static void prvTaskExitError( void )
{
    /* A function that implements a task must not exit or attempt to return to
    its caller as there is nothing to return to.  If a task wants to exit it
    should instead call vTaskDelete( NULL ).

    Artificially force an assert() to be triggered if configASSERT() is
    defined, then stop here so application writers can catch the error. */
    configASSERT( uxSavedTaskStackPointer == 0UL );
    portDISABLE_INTERRUPTS();
    for( ;; );
}
/*-----------------------------------------------------------*/

void vPortEndScheduler(void)
{
    /* Not implemented in ports where there is nothing to return to.
    Artificially force an assert. */
    configASSERT( uxInterruptNesting == 1000UL );
}
/*-----------------------------------------------------------*/



BaseType_t xPortStartScheduler( void )
{
extern void vPortStartFirstTask( void );
extern void *pxCurrentTCB;

    #if ( configCHECK_FOR_STACK_OVERFLOW > 2 )
    {
        /* Fill the ISR stack to make it easy to asses how much is being used. */
        memset( ( void * ) xISRStack, portISR_STACK_FILL_BYTE, sizeof( xISRStack ) );
    }
    #endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */

    /* Clear the pending interrupts */
    portCLEAR_PENDING_INTERRUPTS();

    /* Setup the timer to generate the tick.  Interrupts will have been
    disabled by the time we get here. */
    vApplicationSetupTickTimerInterrupt();

    /* Install the software yield handler */
    vApplicationSetupSoftwareInterrupt();

    /* Kick off the highest priority task that has been created so far.
    Its stack location is loaded into uxSavedTaskStackPointer. */
    uxSavedTaskStackPointer = *( UBaseType_t * ) pxCurrentTCB;
    vPortStartFirstTask();

    /* Should never get here as the tasks will now be executing!  Call the task
    exit error function to prevent compiler warnings about a static function
    not being called in the case that the application writer overrides this
    functionality by defining configTASK_RETURN_ADDRESS. */
    prvTaskExitError();

    return pdHV_FALSE;
}
/*-----------------------------------------------------------*/

void vPortIncrementTick( void )
{
UBaseType_t uxSavedStatus;

 //  HV_LOGI("Now enter int\n");
    uxSavedStatus = uxPortSetInterruptMaskFromISR();
    {
        if( xTaskIncrementTick() != pdHV_FALSE )
        {
            /* Pend a context switch. */
            portYIELD();
        }
    }
    vPortClearInterruptMaskFromISR( uxSavedStatus );

    /* Look for the ISR stack getting near or past its limit. */
    portCHECK_ISR_STACK();

 //   HV_LOGI("Now after int is 0x%08x\n",uxSavedStatus);
    /* Clear timer interrupt. */
    configCLEAR_TICK_TIMER_INTERRUPT();
}
/*-----------------------------------------------------------*/

#if configCHECK_FOR_STACK_OVERFLOW > 0
/* Assert at a stack overflow. */
void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
{
    configASSERT( xTask == NULL );
}
#endif

/*remove to boot_main*/
#ifndef HV_CONFIG_HARD_FLOAT
#ifdef __mips_hard_float
void _mips_handle_exception (struct gpctx *ctx, int exception)
{
    if ( exception == EXC_CPU ) {
        mips_bissr(SR_CU1);
        ctx->status |= SR_CU1;

        if ( !currentfpctx ) {
            currentfpctx = pvPortMalloc( sizeof( struct fp64ctx ) );
            configASSERT( currentfpctx != NULL );
        }

        /* this means no one exec'd fpu since we last run */
        if ( oldfpctx == currentfpctx )
                return;

        if ( oldfpctx )
            _fpctx_save( &oldfpctx->fp );

        _fpctx_load( &currentfpctx->fp );

        /* next fpu exception must save our context as it's not necessarily the
         * next context switch will cause fpu exception and it's very hard for
         * any future task to determine which was the last one that performed
         * fpu operations. so by saving this pointer now we give this knowledge
         * to that future task */
        oldfpctx = currentfpctx;
    } else {
        __exception_handle( ctx, exception );
    }
}
#endif
#endif
