#include <mips/cpu.h>
#include <mips/hal.h>

#include "hv_chip_Config.h"
#ifdef HV_CONFIG_HARD_FLOAT
/* pointer to the current and old fpu context for lazy context switching */
struct fp64ctx g_stCtx;
/* fpu context of current running task */
struct fp64ctx *g_pstCurrentCtx;
/* fpu context of last task that executed fpu */
struct fp64ctx *g_pstOldCtx;
#endif

void _mips_handle_exception(struct gpctx *pstCtx, int iException)
{
#ifdef HV_CONFIG_HARD_FLOAT
        if ( iException == EXC_CPU )
        {
            mips_bissr(SR_CU1);
            pstCtx->status |= SR_CU1;

            if ( !g_pstCurrentCtx )
            {
                g_pstCurrentCtx = &g_stCtx;
                if ( g_pstCurrentCtx == NULL )
                {
                    Hv_Chip_DebugUartPuts("assert failed at boot_main _mips_handle_exception.\n");
                }
            }

            /* this means no one exec'd fpu since we last run */
            if ( g_pstOldCtx == g_pstCurrentCtx )
            {
                return;
            }

            if ( g_pstOldCtx )
            {
                _fpctx_save( &g_pstOldCtx->fp );
            }

            _fpctx_load( &g_pstCurrentCtx->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 */
            g_pstOldCtx = g_pstCurrentCtx;
        }
        else
        {
            __exception_handle( pstCtx, iException );
        }
#else
    if ( iException == EXC_CPU )
    {
        mips_bissr(SR_CU1);
        pstCtx->status |= SR_CU1;
        Hv_Chip_DebugUartPuts("FPU exception.\n");
    }
    __exception_handle( pstCtx, iException );
#endif
}

__attribute__((long_call)) extern void _risc_interrup_handler(int num);

HV_IRQ_FUNCTION _risc_isr_sw0(void)
{
    _risc_interrup_handler(0);
}

HV_IRQ_FUNCTION _risc_isr_sw1(void)
{
    _risc_interrup_handler(1);
}

HV_IRQ_FUNCTION _risc_isr_hw0(void)
{
    _risc_interrup_handler(2);
}

HV_IRQ_FUNCTION _risc_isr_hw1(void)
{
    _risc_interrup_handler(3);
}

HV_IRQ_FUNCTION _risc_isr_hw2(void)
{
    _risc_interrup_handler(4);
}
HV_IRQ_FUNCTION _risc_isr_hw3(void)
{
    _risc_interrup_handler(5);
}

HV_IRQ_FUNCTION _risc_isr_hw4(void)
{
    _risc_interrup_handler(6);
}

HV_IRQ_FUNCTION _risc_isr_hw5(void)
{
    _risc_interrup_handler(7);
}


