/* mbed Microcontroller Library
 * CMSIS-style functionality to support dynamic vectors
 *******************************************************************************
 * Copyright (c) 2011 ARM Limited. All rights reserved.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of ARM Limited nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************
 */
#ifndef __ARM_ARCH_ISA_ARM

#include "cmsis_nvic.h"
#include "plat_types.h"
#include "plat_addr_map.h"
#include "hal_location.h"
#ifdef __ARMCC_VERSION
#include "link_sym_armclang.h"
#endif

STATIC_ASSERT(NVIC_NUM_VECTORS * 4 <= VECTOR_SECTION_SIZE, "ERROR: VECTOR_SECTION_SIZE too small!");

// The vector table must be aligned to NVIC_NUM_VECTORS-word boundary, rounding up to the next power of two
// -- 0x100 for 33~64 vectors, and 0x200 for 65~128 vectors
#ifdef __ARMCC_VERSION
#define VECTOR_LOC                              __attribute__((section(".bss.vector_table")))
#else
#define VECTOR_LOC                              __attribute__((section(".vector_table")))
#endif

#define FAULT_HANDLER                           __attribute__((weak,alias("NVIC_default_handler")))

static uint32_t VECTOR_LOC vector_table[NVIC_NUM_VECTORS];

void NVIC_DisableAllIRQs(void)
{
    int i;

    for (i = 0; i < (USER_IRQn_QTY + 31) / 32; i++) {
        NVIC->ICER[i] = ~0UL;
    }
    SCB->VTOR = 0;
}

static void NAKED BOOT_TEXT_FLASH_LOC NVIC_default_handler(void)
{
    asm volatile("_loop:; nop; nop; nop; nop; b _loop;");
}

void FAULT_HANDLER Reset_Handler(void);
void FAULT_HANDLER NMI_Handler(void);
void FAULT_HANDLER HardFault_Handler(void);
void FAULT_HANDLER MemManage_Handler(void);
void FAULT_HANDLER BusFault_Handler(void);
void FAULT_HANDLER UsageFault_Handler(void);
void FAULT_HANDLER SecureFault_Handler(void);
void FAULT_HANDLER SVC_Handler(void);
void FAULT_HANDLER DebugMon_Handler(void);
void FAULT_HANDLER PendSV_Handler(void);
void FAULT_HANDLER SysTick_Handler(void);
extern uint32_t __rom_stack[];
extern uint32_t __stack[];

static const uint32_t BOOT_RODATA_FLASH_LOC fault_handlers[NVIC_USER_IRQ_OFFSET] = {
#if defined(ROM_BUILD) && !defined(ROM_IN_FLASH)
    (uint32_t)__rom_stack,
#else
    (uint32_t)__stack,
#endif
    (uint32_t)Reset_Handler,
    (uint32_t)NMI_Handler,
    (uint32_t)HardFault_Handler,
    (uint32_t)MemManage_Handler,
    (uint32_t)BusFault_Handler,
    (uint32_t)UsageFault_Handler,
    (uint32_t)SecureFault_Handler,
    (uint32_t)NVIC_default_handler,
    (uint32_t)NVIC_default_handler,
    (uint32_t)NVIC_default_handler,
    (uint32_t)SVC_Handler,
    (uint32_t)DebugMon_Handler,
    (uint32_t)NVIC_default_handler,
    (uint32_t)PendSV_Handler,
    (uint32_t)SysTick_Handler,
};

void BOOT_TEXT_FLASH_LOC NVIC_InitVectors(void)
{
    int i;

    for (i = 0; i < NVIC_NUM_VECTORS; i++) {
        vector_table[i] = (i < ARRAY_SIZE(fault_handlers)) ?
            fault_handlers[i] : (uint32_t)NVIC_default_handler;
    }

    SCB->VTOR = (uint32_t)vector_table;
    __DSB();
}

void NVIC_SetDefaultFaultHandler(NVIC_DEFAULT_FAULT_HANDLER_T handler)
{
    int i;

    for (i = 1; i < ARRAY_SIZE(fault_handlers); i++) {
        if (vector_table[i] == (uint32_t)NVIC_default_handler) {
            vector_table[i] = (uint32_t)handler;
        }
    }
}

IRQn_Type NVIC_GetCurrentActiveIRQ(void)
{
    IRQn_Type irq = (__get_IPSR() & IPSR_ISR_Msk) - NVIC_USER_IRQ_OFFSET;
    return irq;
}

#ifdef CORE_SLEEP_POWER_DOWN

void SRAM_TEXT_LOC NVIC_PowerDownSleep(uint32_t *buf, uint32_t cnt)
{
    int i;
    uint32_t idx;
    __IO uint32_t *regs;

    idx = 0;
    for (i = 0; i < (NVIC_NUM_VECTORS - NVIC_USER_IRQ_OFFSET + 31) / 32; i++) {
        buf[idx++] = NVIC->ISER[i];
    }
#if (__CORTEX_M <= 4)
    regs = (__IO uint32_t *)&NVIC->IP[0];
#else
    regs = (__IO uint32_t *)&NVIC->IPR[0];
#endif
    for (i = 0; i < (NVIC_NUM_VECTORS - NVIC_USER_IRQ_OFFSET + 3) / 4; i++) {
        buf[idx++] = regs[i];
    }
    buf[idx++] = SCnSCB->ACTLR;
    buf[idx++] = SCB->ICSR;
    buf[idx++] = SCB->AIRCR;
    buf[idx++] = SCB->SCR;
    buf[idx++] = SCB->CCR;
#if (__CORTEX_M <= 4)
    regs = (__IO uint32_t *)&SCB->SHP[0];
#else
    regs = (__IO uint32_t *)&SCB->SHPR[0];
#endif
    buf[idx++] = regs[0];
    buf[idx++] = regs[1];
    buf[idx++] = regs[2];
    buf[idx++] = SCB->SHCSR;
    buf[idx++] = SysTick->CTRL;
    buf[idx++] = SysTick->LOAD;

    if (idx > cnt) {
        do { asm volatile("nop \n nop \n nop \n nop"); } while (1);
    }
}

void SRAM_TEXT_LOC NVIC_PowerDownWakeup(uint32_t *buf, uint32_t cnt)
{
    int i;
    uint32_t idx;
    __IO uint32_t *regs;

    idx = 0;
    for (i = 0; i < (NVIC_NUM_VECTORS - NVIC_USER_IRQ_OFFSET + 31) / 32; i++) {
        NVIC->ISER[i] = buf[idx++];
    }
#if (__CORTEX_M <= 4)
    regs = (__IO uint32_t *)&NVIC->IP[0];
#else
    regs = (__IO uint32_t *)&NVIC->IPR[0];
#endif
    for (i = 0; i < (NVIC_NUM_VECTORS - NVIC_USER_IRQ_OFFSET + 3) / 4; i++) {
        regs[i] = buf[idx++];
    }
    SCnSCB->ACTLR = buf[idx++];
    SCB->ICSR = buf[idx++];
    SCB->AIRCR = buf[idx++];
    SCB->SCR = buf[idx++];
    SCB->CCR = buf[idx++];
#if (__CORTEX_M <= 4)
    regs = (__IO uint32_t *)&SCB->SHP[0];
#else
    regs = (__IO uint32_t *)&SCB->SHPR[0];
#endif
    regs[0] = buf[idx++];
    regs[1] = buf[idx++];
    regs[2] = buf[idx++];
    SCB->SHCSR = buf[idx++];
    SysTick->CTRL = buf[idx++];
    SysTick->LOAD = buf[idx++];

    SCB->VTOR = (uint32_t)vector_table;
    SysTick->VAL = 0;
}

#endif

#endif

