/* ======================================================================
 *   Copyright (C) 2013 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission
 *   of Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been
 *   supplied.
 * ==================================================================== */
#include "stdint.h"
#include "hw_types.h"
#include "stw_dataTypes.h"
#include "stw_types.h"
#include "interrupt.h"

#define M4_NUM_NVIC_INTERNAL   (16)
#define M4_NUM_NVIC_EXTERNAL   (128)
#define M4_IRQ_EN_SET_START    (0xE000E100u)
#define M4_IRQ_EN_SET_END      (M4_IRQ_EN_SET_START + \
                                (M4_NUM_NVIC_EXTERNAL / 32) * 4)
#define M4_IRQ_EN_CLR_START    (0xE000E180u)
#define M4_IRQ_EN_CLR_END      (M4_IRQ_EN_CLR_START + \
                                (M4_NUM_NVIC_EXTERNAL / 32) * 4)
#define M4_IRQ_ACTIVE_START    (0xE000E300u)
#define M4_IRQ_ACTIVE_END      (M4_IRQ_ACTIVE_START + \
                                (M4_NUM_NVIC_EXTERNAL / 32) * 4)

void       *argArray[M4_NUM_NVIC_EXTERNAL] = {0};
IntrFuncPtr fxnArray[M4_NUM_NVIC_EXTERNAL] = {0};
uint32_t    ieCookie[M4_NUM_NVIC_EXTERNAL / 32];

extern int32_t _c_int00();

void HF()
{
    volatile int32_t a;
    a = 0;
}

#pragma DATA_SECTION(vector_table, ".intvecs");
const volatile uint32_t vector_table[] =
{
    0,                   /* Stack_base + STACK_SIZE*4 */
    (uint32_t) _c_int00, /* ResetHandler               */
    (uint32_t) HF,
    (uint32_t) HF,
    (uint32_t) HF, /* Populate if using MemManage(MPU)  */
    (uint32_t) HF, /* Populate if using Bus fault       */
    (uint32_t) HF, /* Populate if using Usage Fault     */
    (uint32_t) HF,
    (uint32_t) HF,
    (uint32_t) HF,
    (uint32_t) HF, /*   Reserved slots                          */
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF,(uint32_t) HF,  (uint32_t) HF, (uint32_t) HF,
    (uint32_t) HF
};

/**
 *
 * The Default Interrupt Handler.
 *
 * This is the default interrupt handler for all interrupts.  It simply loops
 * forever so that the system state is preserved for observation by a
 * debugger.  Since interrupts should be disabled before unregistering the
 * corresponding handler, this should never be called.
 *
 *
 **/
static void IntDefaultHandler(void *dummy)
{
    /* Go into an infinite loop.*/
    while (1)
    {
        ;
    }
}

/**
 *
 * Master ISR handler.
 *
 * Reads the active interrupt number & check for status.
 * Call the registered ISR function with arguments
 *
 *
 **/

static void masterIsr()
{
    void      (*fxnPtr)(void *);
    uint32_t *irqActiveAddr = (uint32_t *) M4_IRQ_ACTIVE_START;
    uint32_t  intNum        = M4_NUM_NVIC_INTERNAL;
    while (irqActiveAddr < (uint32_t *) M4_IRQ_ACTIVE_END)
    {
        uint32_t i = 0;
        if (*(volatile uint32_t *) irqActiveAddr != 0)
        {
            while (i < 32)
            {
                if (*(volatile uint32_t *) irqActiveAddr & (1 << i))
                {
                    if (fxnArray[intNum] != NULL)
                    {
                        *(volatile uint32_t *) &fxnPtr =
                            (uint32_t) fxnArray[intNum];
                        fxnPtr(argArray[intNum]);
                    }
                }
                i++;
                intNum++;
            }
        }
        else
        {
            intNum += 32;
        }
        irqActiveAddr++;
    }
}

void clearIntr(uint32_t intNum) {}

void Intc_Init(void)
{
    // TODO - Check for Cortex-M3 Interrupt controller( Reset & Init)
}

/**
 * \brief    Registers an interrupt Handler in the interrupt vector table for
 *           system interrupts.
 *
 **/
void Intc_IntRegister(uint16_t intrNum, IntrFuncPtr fptr, void *fun_arg)
{
    *(volatile uint32_t *) (intrNum * 4) = (uint32_t) masterIsr;
    fxnArray[intrNum] = fptr;
    argArray[intrNum] = fun_arg;
}

/**
 * \brief   Unregisters an interrupt
 *
 **/
void Intc_IntUnregister(uint16_t intrNum)
{
    fxnArray[intrNum] = (IntrFuncPtr) IntDefaultHandler;
    argArray[intrNum] = NULL;
}

/**
 * \brief   This API assigns a priority to an interrupt and routes it to
 *          either IRQ or to FIQ. Priority 0 is the highest priority level
 *          Among the host interrupts, FIQ has more priority than IRQ.
 **/
void Intc_IntPrioritySet(uint16_t intrNum, uint16_t priority,
                         uint8_t hostIntRoute)
{
    // Dummy function in Cortex - M3
}

/**
 * \brief   This API enables the system interrupt in INTC. However, for
 *          the interrupt generation, make sure that the interrupt is
 *          enabled at the peripheral level also.
 **/
void Intc_SystemEnable(uint16_t intrNum)
{
    uint32_t *irqEnSetAddr = (uint32_t *) M4_IRQ_EN_SET_START;

    intrNum -= M4_NUM_NVIC_INTERNAL;

    while (intrNum > 32)
    {
        intrNum -= 32;
        irqEnSetAddr++;
    }
    *(volatile uint32_t *) (irqEnSetAddr) = (1 << intrNum);
}

/**
 * \brief   This API disables the system interrupt in INTC.
 **/
void Intc_SystemDisable(uint16_t intrNum)
{
    uint32_t *irqEnClrAddr = (uint32_t *) M4_IRQ_EN_CLR_START;

    intrNum -= M4_NUM_NVIC_INTERNAL;

    while (intrNum > 32)
    {
        intrNum -= 32;
        irqEnClrAddr++;
    }

    *(volatile uint32_t *) (irqEnClrAddr) = (1 << intrNum);
}

/**
 * \brief  Read and save the stasus and Disables the processor IRQ .
 *         Prevents the processor to respond to IRQs.
 **/
uint8_t Intc_IntDisable(void)
{
    uint32_t  dummyRetVal  = 0;
    uint32_t  i            = 0;
    uint32_t *irqEnSetAddr = (uint32_t *) M4_IRQ_EN_SET_START;
    uint32_t *irqEnClrAddr = (uint32_t *) M4_IRQ_EN_CLR_START;
    while (irqEnSetAddr < (uint32_t *) M4_IRQ_EN_SET_END)
    {
        ieCookie[i] = *(volatile uint32_t *) (irqEnSetAddr);
        *(volatile uint32_t *) (irqEnClrAddr) = ieCookie[i];
        i++;
        irqEnSetAddr++;
        irqEnClrAddr++;
        dummyRetVal++;
    }
    return dummyRetVal;
}

/**
 * \brief  Restore the processor IRQ only status. This does not affect
 *          the set of interrupts enabled/disabled in the AINTC.
 **/
void Intc_IntEnable(uint8_t status)
{
    uint32_t  i = 0;
    printf("vector_table 0x%x\n",vector_table);
    uint32_t *irqEnSetAddr = (uint32_t *) M4_IRQ_EN_SET_START;
    while (irqEnSetAddr < (uint32_t *) M4_IRQ_EN_SET_END)
    {
        *(volatile uint32_t *) (irqEnSetAddr) = ieCookie[i];
        i++;
        irqEnSetAddr++;
    }
}

