/********************************** (C) COPYRIGHT  *******************************
 * File Name          : core_riscv.h
 * Author             : WCH
 * Version            : V1.0.0
 * Date               : 2024/07/25
 * Description        : CH585 Series RISC-V Core Peripheral Access Layer Header File
 *********************************************************************************
 * Copyright (c) 2024 Nanjing Qinheng Microelectronics Co., Ltd.
 * Attention: This software (modified or not) and binary are used for 
 * microcontroller manufactured by Nanjing Qinheng Microelectronics.
 *******************************************************************************/
#ifndef __CORE_RISCV_H__
#define __CORE_RISCV_H__

#ifdef __cplusplus
extern "C" {
#endif

/* define compiler specific symbols */
#if defined ( __CC_ARM   )
#define __ASM            __asm                                      /*!< asm keyword for ARM Compiler          */
#define __INLINE         __inline                                   /*!< inline keyword for ARM Compiler       */

#elif defined ( __ICCARM__ )
#define __ASM           __asm                                       /*!< asm keyword for IAR Compiler          */
#define __INLINE        inline                                      /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */

#elif defined   (  __GNUC__  )
#define __ASM            __asm                                      /*!< asm keyword for GNU Compiler          */
#define __INLINE         inline                                     /*!< inline keyword for GNU Compiler       */

#elif defined   (  __TASKING__  )
#define __ASM            __asm                                      /*!< asm keyword for TASKING Compiler      */
#define __INLINE         inline                                     /*!< inline keyword for TASKING Compiler   */

#endif

/* IO definitions */
#ifdef __cplusplus
#define __I                 volatile            /*!< defines 'read only' permissions      */
#else
#define __I                 volatile const      /*!< defines 'read only' permissions     */
#endif
#define __O                 volatile            /*!< defines 'write only' permissions     */
#define __IO                volatile            /*!< defines 'read / write' permissions   */
#define RV_STATIC_INLINE    static inline

//typedef enum {SUCCESS = 0, ERROR = !SUCCESS} ErrorStatus;

typedef enum
{
    DISABLE = 0,
    ENABLE = !DISABLE
} FunctionalState;
typedef enum
{
    RESET = 0,
    SET = !RESET
} FlagStatus, ITStatus;

/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
typedef struct
{
    __I uint32_t  ISR[8];           // 0
    __I uint32_t  IPR[8];           // 20H
    __IO uint32_t ITHRESDR;         // 40H
    uint8_t       RESERVED[8];      // 44H
    __I uint32_t  GISR;             // 4CH
    __IO uint8_t  VTFIDR[4];        // 50H
    uint8_t       RESERVED0[0x0C];  // 54H
    __IO uint32_t VTFADDR[4];       // 60H
    uint8_t       RESERVED1[0x90];  // 70H
    __O uint32_t  IENR[8];          // 100H
    uint8_t       RESERVED2[0x60];  // 120H
    __O uint32_t  IRER[8];          // 180H
    uint8_t       RESERVED3[0x60];  // 1A0H
    __O uint32_t  IPSR[8];          // 200H
    uint8_t       RESERVED4[0x60];  // 220H
    __O uint32_t  IPRR[8];          // 280H
    uint8_t       RESERVED5[0x60];  // 2A0H
    __IO uint32_t IACTR[8];         // 300H
    uint8_t       RESERVED6[0xE0];  // 320H
    __IO uint8_t  IPRIOR[256];      // 400H
    uint8_t       RESERVED7[0x810]; // 500H
    __IO uint32_t SCTLR;            // D10H
} PFIC_Type;

/* memory mapped structure for SysTick */
typedef struct
{
    __IO uint32_t CTLR;
    __IO uint32_t SR;
    union
    {
        __IO uint32_t CNT;
        __IO uint32_t CNTL;
    };
    uint8_t       RESERVED[4];
    union
    {
        __IO uint32_t CMP;
        __IO uint32_t CMPL;
    };
    uint8_t       RESERVED0[4];
} SysTick_Type;

#define PFIC                    ((PFIC_Type *)0xE000E000)
#define SysTick                 ((SysTick_Type *)0xE000F000)

#define PFIC_KEY1               ((uint32_t)0xFA050000)
#define PFIC_KEY2               ((uint32_t)0xBCAF0000)
#define PFIC_KEY3               ((uint32_t)0xBEEF0000)

/* ##########################   define  #################################### */
#define __nop()                 __asm__ volatile("nop")

#define read_csr(reg)           ({unsigned long __tmp;                      \
        __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp));                  \
        __tmp; })

#define write_csr(reg, val)     ({                                          \
        if (__builtin_constant_p(val) && (unsigned long)(val) < 32)         \
        __asm__ volatile ("csrw  " #reg ", %0" :: "i"(val));                \
        else                                                                \
            __asm__ volatile ("csrw  " #reg ", %0" :: "r"(val)); })

/*********************************************************************
 * @fn      __risc_v_enable_irq
 *
 * @brief   recover Global Interrupt
 *
 * @return  mpie and mie bit in mstatus.
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __risc_v_enable_irq(uint32_t mpie_mie)
{
    uint32_t result;

    __asm volatile("csrrs %0, 0x800, %1" : \
                   "=r"(result): "r"(mpie_mie) : "memory");
    return result;
}

/*********************************************************************
 * @fn      __disable_irq
 *
 * @brief   Disable Global Interrupt
 *
 * @return  mpie and mie bit in mstatus.
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __risc_v_disable_irq(void)
{
    uint32_t result;

    __asm volatile("csrrc %0, 0x800, %1" : \
                   "=r"(result): "r"(0x88) : "memory");
    return result & 0x88;
}

/* ##########################   PFIC functions  #################################### */

#define PFIC_EnableAllIRQ()     {write_csr(0x800, 0x88);}
#define PFIC_DisableAllIRQ()    {write_csr(0x800, 0x80);asm volatile("fence.i");}

/*******************************************************************************
 * @fn      PFIC_EnableIRQ
 *
 * @brief   Enable Interrupt
 *
 * @param   IRQn    - Interrupt Numbers
 */
__attribute__((always_inline)) RV_STATIC_INLINE void PFIC_EnableIRQ(IRQn_Type IRQn)
{
    PFIC->IENR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

/*******************************************************************************
 * @fn      PFIC_DisableIRQ
 *
 * @brief   Disable Interrupt
 *
 * @param   IRQn    - Interrupt Numbers
 */
__attribute__((always_inline)) RV_STATIC_INLINE void PFIC_DisableIRQ(IRQn_Type IRQn)
{
    PFIC->IRER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
    asm volatile("fence.i");
}

/*******************************************************************************
 * @fn      PFIC_GetStatusIRQ
 *
 * @brief   Get Interrupt Enable State
 *
 * @param   IRQn    - Interrupt Numbers
 *
 * @return  1: Interrupt Enable
 *          0: Interrupt Disable
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t PFIC_GetStatusIRQ(IRQn_Type IRQn)
{
    return ((uint32_t)((PFIC->ISR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F))) ? 1 : 0));
}

/*******************************************************************************
 * @fn      PFIC_GetPendingIRQ
 *
 * @brief   Get Interrupt Pending State
 *
 * @param   IRQn    - Interrupt Numbers
 *
 * @return  1: Interrupt Pending Enable
 *          0: Interrupt Pending Disable
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t PFIC_GetPendingIRQ(IRQn_Type IRQn)
{
    return ((uint32_t)((PFIC->IPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F))) ? 1 : 0));
}

/*******************************************************************************
 * @fn      PFIC_SetPendingIRQ
 *
 * @brief   Set Interrupt Pending
 *
 * @param   IRQn    - Interrupt Numbers
 */
__attribute__((always_inline)) RV_STATIC_INLINE void PFIC_SetPendingIRQ(IRQn_Type IRQn)
{
    PFIC->IPSR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

/*******************************************************************************
 * @fn      PFIC_ClearPendingIRQ
 *
 * @brief   Clear Interrupt Pending
 *
 * @param   IRQn    - Interrupt Numbers
 */
__attribute__((always_inline)) RV_STATIC_INLINE void PFIC_ClearPendingIRQ(IRQn_Type IRQn)
{
    PFIC->IPRR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

/*******************************************************************************
 * @fn      PFIC_GetActive
 *
 * @brief   Get Interrupt Active State
 *
 * @param   IRQn    - Interrupt Numbers
 *
 * @return  1: Interrupt Active
 *          0: Interrupt No Active.
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t PFIC_GetActive(IRQn_Type IRQn)
{
    return ((uint32_t)((PFIC->IACTR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F))) ? 1 : 0));
}

/*******************************************************************************
 * @fn      PFIC_SetPriority
 *
 * @brief   Set Interrupt Priority
 *
 * @param   IRQn        - Interrupt Numbers
 * @param   priority    - bit7:         pre-emption priority
 */
__attribute__((always_inline)) RV_STATIC_INLINE void PFIC_SetPriority(IRQn_Type IRQn, uint8_t priority)
{
    PFIC->IPRIOR[(uint32_t)(IRQn)] = priority ? 0x80 : 0;
}

/*********************************************************************
 * @fn      SetVTFIRQ
 *
 * @brief   Set VTF Interrupt
 *
 * @param   addr - VTF interrupt service function base address.
 *                  IRQn - Interrupt Numbers
 *                  num - VTF Interrupt Numbers
 *                  NewState -  DISABLE or ENABLE
 *
 * @return  none
 */
__attribute__((always_inline)) RV_STATIC_INLINE void SetVTFIRQ(uint32_t addr, IRQn_Type IRQn, uint8_t num, FunctionalState NewState)
{
    if (num > 3)  return ;

    if (NewState != DISABLE)
    {
        PFIC->VTFIDR[num] = IRQn;
        PFIC->VTFADDR[num] = ((addr & 0xFFFFFFFE) | 0x1);
    }
    else
    {
        PFIC->VTFIDR[num] = IRQn;
        PFIC->VTFADDR[num] = ((addr & 0xFFFFFFFE) & (~0x1));
    }
}

/*********************************************************************
 * @fn       _SEV
 *
 * @brief   Set Event
 *
 * @return  none
 */
__attribute__((always_inline)) RV_STATIC_INLINE void _SEV(void)
{

    PFIC->SCTLR |= (1 << 3) | (1 << 5);

}

/*********************************************************************
 * @fn       _WFE
 *
 * @brief   Wait for Events
 *
 * @return  none
 */
__attribute__((always_inline)) RV_STATIC_INLINE void _WFE(void)
{
    PFIC->SCTLR |= (1 << 3);
    asm volatile("wfi");
}


/*********************************************************************
 * @fn      __WFE
 *
 * @brief   Wait for Events
 *
 * @return  None
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __WFE(void)
{
    _SEV();
    _WFE();
    _WFE();
}

/*********************************************************************
 * @fn      __WFI
 *
 * @brief   Wait for Interrupt
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __WFI(void)
{
    PFIC->SCTLR &= ~(1 << 3); // wfi
    __asm__ volatile("wfi");
}

/*********************************************************************
 * @fn      PFIC_SystemReset
 *
 * @brief   Initiate a system reset request
 */
__attribute__((always_inline)) RV_STATIC_INLINE void PFIC_SystemReset(void)
{
    PFIC->SCTLR = 0x80000000;
}

/*********************************************************************
 * @fn      __get_MSTATUS
 *
 * @brief   Return the Machine Status Register
 *
 * @return  mstatus value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MSTATUS(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mstatus" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __set_MSTATUS
 *
 * @brief   Set the Machine Status Register
 *
 * @param   value  - set mstatus value
 *
 * @return  none
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __set_MSTATUS(uint32_t value)
{
    __ASM volatile("csrw mstatus, %0" : : "r"(value));
}

/*********************************************************************
 * @fn      __get_MISA
 *
 * @brief   Return the Machine ISA Register
 *
 * @return  misa value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MISA(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "misa" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __set_MISA
 *
 * @brief   Set the Machine ISA Register
 *
 * @param   value  - set misa value
 *
 * @return  none
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __set_MISA(uint32_t value)
{
    __ASM volatile("csrw misa, %0" : : "r"(value));
}

/*********************************************************************
 * @fn      __get_MTVEC
 *
 * @brief   Return the Machine Trap-Vector Base-Address Register
 *
 * @return  mtvec value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MTVEC(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mtvec" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __set_MTVEC
 *
 * @brief   Set the Machine Trap-Vector Base-Address Register
 *
 * @param   value  - set mtvec value
 *
 * @return  none
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __set_MTVEC(uint32_t value)
{
    __ASM volatile("csrw mtvec, %0" : : "r"(value));
}

/*********************************************************************
 * @fn      __get_MSCRATCH
 *
 * @brief   Return the Machine Seratch Register
 *
 * @return  mscratch value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MSCRATCH(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mscratch" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __set_MSCRATCH
 *
 * @brief   Set the Machine Seratch Register
 *
 * @param   value  - set mscratch value
 *
 * @return  none
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __set_MSCRATCH(uint32_t value)
{
    __ASM volatile("csrw mscratch, %0" : : "r"(value));
}

/*********************************************************************
 * @fn      __get_MEPC
 *
 * @brief   Return the Machine Exception Program Register
 *
 * @return  mepc value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MEPC(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mepc" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __set_MEPC
 *
 * @brief   Set the Machine Exception Program Register
 *
 * @return  mepc value
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __set_MEPC(uint32_t value)
{
    __ASM volatile("csrw mepc, %0" : : "r"(value));
}

/*********************************************************************
 * @fn      __get_MCAUSE
 *
 * @brief   Return the Machine Cause Register
 *
 * @return  mcause value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MCAUSE(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mcause" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __set_MEPC
 *
 * @brief   Set the Machine Cause Register
 *
 * @return  mcause value
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __set_MCAUSE(uint32_t value)
{
    __ASM volatile("csrw mcause, %0" : : "r"(value));
}

/*********************************************************************
 * @fn      __get_MTVAL
 *
 * @brief   Return the Machine Trap Value Register
 *
 * @return  mtval value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MTVAL(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mtval" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __set_MTVAL
 *
 * @brief   Set the Machine Trap Value Register
 *
 * @return  mtval value
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __set_MTVAL(uint32_t value)
{
    __ASM volatile("csrw mtval, %0" : : "r"(value));
}

/*********************************************************************
 * @fn      __get_MVENDORID
 *
 * @brief   Return Vendor ID Register
 *
 * @return  mvendorid value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MVENDORID(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mvendorid" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __get_MARCHID
 *
 * @brief   Return Machine Architecture ID Register
 *
 * @return  marchid value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MARCHID(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "marchid" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __get_MIMPID
 *
 * @brief   Return Machine Implementation ID Register
 *
 * @return  mimpid value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MIMPID(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mimpid" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __get_MHARTID
 *
 * @brief   Return Hart ID Register
 *
 * @return  mhartid value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_MHARTID(void)
{
    uint32_t result;

    __ASM volatile("csrr %0," "mhartid" : "=r"(result));
    return (result);
}

/*********************************************************************
 * @fn      __get_SP
 *
 * @brief   Return SP Register
 *
 * @return  SP value
 */
__attribute__((always_inline)) RV_STATIC_INLINE uint32_t __get_SP(void)
{
    uint32_t result;

    __ASM volatile("mv %0," "sp" : "=r"(result) :);
    return (result);
}

/*********************************************************************
 * @fn        __MCPY
 *
 * @brief    fast memory copy asm instruction.
 * @details  copy memory from start to dst, copy length is (end - start).
 *
 *
 * @return  None.
 */
__attribute__((always_inline)) RV_STATIC_INLINE void __MCPY(void *dst, void *start, void *end)
{
    __asm volatile("mcpy %2, %0, %1" : \
                   "+r"(start), "+r"(dst) : "r"(end) : "memory");
}

#define SysTick_SR_SWIE             (1 << 31)
#define SysTick_SR_CNTIF            (1 << 0)

#define SysTick_LOAD_RELOAD_Msk     (0xFFFFFFFF)
#define SysTick_CTLR_INIT           (1 << 5)
#define SysTick_CTLR_MODE           (1 << 4)
#define SysTick_CTLR_STRE           (1 << 3)
#define SysTick_CTLR_STCLK          (1 << 2)
#define SysTick_CTLR_STIE           (1 << 1)
#define SysTick_CTLR_STE            (1 << 0)


RV_STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
    if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)
        return (1); /* Reload value impossible */

 //   SysTick->CNTL = 0;
    SysTick->CMP = ticks - 1;   /* set reload register */
    PFIC_EnableIRQ(SysTick_IRQn);
    SysTick->CTLR = SysTick_CTLR_INIT   |       //Æô¶¯
                    SysTick_CTLR_STRE   |
                    SysTick_CTLR_STCLK  |
                    SysTick_CTLR_STIE   |
                    SysTick_CTLR_STE;   /* Enable SysTick IRQ and SysTick Timer */
    return (0);                         /* Function successful */
}

RV_STATIC_INLINE uint32_t __SysTick_Config(uint32_t ticks)
{
    if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)
        return (1); /* Reload value impossible */

    SysTick->CNTL = 0;
    SysTick->CMP = ticks - 1;   /* set reload register */
    SysTick->CTLR = SysTick_CTLR_STRE   |
                    SysTick_CTLR_STCLK  |
                    SysTick_CTLR_STIE   |
                    SysTick_CTLR_STE;   /* Enable SysTick IRQ and SysTick Timer */
    return (0);                         /* Function successful */
}

#ifdef __cplusplus
}
#endif

#endif /* __CORE_RV3A_H__ */
