/*
 * Copyright (c) 2012-2019 Andes Technology Corporation
 * All rights reserved.
 * trap.c is for those local interrupt sources, that do not pass through the PLIC,
 * include the standard Software interrupts (mswi) and timer interrupts (mtime)
 * for each privilege level.
 * The servicing hart can quickly determine the interrupt source using the mcause register.
 */

#include "platform.h"
#include "debug.h"

void MTIME_DelayTicks(uint32_t ticks)
{
    uint32_t base = RUNTIME_SPV40.Sys_Ticks;

    while (1)
    {
        if ((uint32_t)(RUNTIME_SPV40.Sys_Ticks - base) > ticks)
        {
            break;
        }
    }
}

uint32_t mtime_get_clock(void)
{
    uint32_t clock_freq = 24000000;
    return (clock_freq / 4);
}

__ILM void mtime_update(uint32_t counts)
{
    register uint32_t temp = DEV_MTIME->MTIME_H;
    register uint32_t mtime_lo = DEV_MTIME->MTIME_L;
    register uint32_t mtime_hi = DEV_MTIME->MTIME_H;

    if (mtime_hi != temp)
    {
        mtime_lo = DEV_MTIME->MTIME_L;
    }

    temp = mtime_lo + counts;

    if (temp < mtime_lo)
    {
        mtime_hi = mtime_hi + 1;
    }

    DEV_MTIME->MTIMECMP_L = temp;
    DEV_MTIME->MTIMECMP_H = mtime_hi;
}

void mtime_config(uint32_t period_in_us)
{
    uint32_t clk = mtime_get_clock();
    uint32_t counts = (clk / 15625) * period_in_us / 64;
    RUNTIME_SPV40.Sys_Ticks = 0;
    DEV_MTIME->MTIME_H = 0;
    DEV_MTIME->MTIME_L = 0;
    mtime_update(counts);
    (&RUNTIME_SPV40)->MTIME_Period_Counts = counts;
    HAL_MTIME_ENABLE();
}

__WEAK void mtime_irq_handler(void)
{
}

void mtime_irq_entry(void)
{
    /* Disable the timer interrupt to prevent re-entry */
    HAL_MTIME_DISABLE();
    mtime_update(RUNTIME_SPV40.MTIME_Period_Counts);
    RUNTIME_SPV40.Sys_Ticks++;
    /* Enable interrupts in general to allow nested */
    set_csr(NDS_MSTATUS, MSTATUS_MIE);
    mtime_irq_handler();
    /* Re-enable the timer interrupt. */
    HAL_MTIME_ENABLE();
}

__WEAK void mswi_irq_handler(void)
{
}

__WEAK long exception_handler(long cause, long epc)
{
    return epc;
}

void trap_entry(void) __attribute__((interrupt("machine"), aligned(4)));
void trap_entry(void)
{
    long mcause = read_csr(NDS_MCAUSE);
    long mepc = read_csr(NDS_MEPC);
    long mstatus = read_csr(NDS_MSTATUS);
#if SUPPORT_PFT_ARCH
    long mxstatus = read_csr(NDS_MXSTATUS);
#endif
#ifdef __riscv_dsp
    int ucode = read_csr(NDS_UCODE);
#endif
#ifdef __riscv_flen
    int fcsr = read_fcsr();
#endif

    /* Do your trap handling */
    if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER))
    {
        /* Machine timer interrupt */
        mtime_irq_entry();
    }
    else if ((mcause & MCAUSE_INT)
             && ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT))
    {
        /* Machine SWI interrupt */
        mswi_irq_handler();
        /* Machine SWI is connected to PLIC_SW source 1 */
        __nds__plic_sw_complete_interrupt(1);
    }
    else
    {
        /* Exception Handler */
        mepc = exception_handler(mcause, mepc);
        debug("mcause:%08x\n", mcause);
        debug("mepc:%08x\n", mepc);
        debug("mstatus:%08x\n", mstatus);
        debug("mxstatus:%08x\n", mxstatus);


    }
    //芯片复位
    AON_PMU->VOL_CTL = 0x012d3525;
    AON_PMU->PWR_CTL = 0x00003f00;
    delay_us(360*MHz,500);
    AON_GLOBAL->SVDD_GLOBAL7 |= (1ul << 31);
    DEV_RMU->BOOT |= DEV_RMU_BOOT_RE_BOOT;

   while (1)
   {
	   ;
   }
    /* Restore CSR */
    write_csr(NDS_MSTATUS, mstatus);
    write_csr(NDS_MEPC, mepc);
#if SUPPORT_PFT_ARCH
    write_csr(NDS_MXSTATUS, mxstatus);
#endif
#ifdef __riscv_dsp
    write_csr(NDS_UCODE, ucode);
#endif
#ifdef __riscv_flen
    write_fcsr(fcsr);
#endif
}
