#ifndef	__GD32L23x__H
#define __GD32L23x__H

#define UNLOCK_KEY0                ((unsigned int)0x45670123U)                          /*!< FMC/OB unlock key 0 */
#define UNLOCK_KEY1                ((unsigned int)0xCDEF89ABU)                          /*!< FMC/OB unlock key 1 */
#define SLP_UNLOCK_KEY0            ((unsigned int)0x04152637U)                          /*!< SLP unlock key 0 */
#define SLP_UNLOCK_KEY1            ((unsigned int)0xBCAD9E8FU)                          /*!< SLP unlock key 1 */


#define FLASH_PAGE_SIZE     (0x200U)
#define FMC_BASE            (0x40020000U + 0x2000U)
#define RCC_BASE            (0x40020000U + 0x1000U)
#define PWR_BASE            (0x40000000U + 0x7000U)

#define FMC_AC              *(unsigned int *)(FMC_BASE + 0x00000000U)
#define FMC_KEY             *(unsigned int *)(FMC_BASE + 0x00000004U)
#define FMC_OBKEY           *(unsigned int *)(FMC_BASE + 0x00000008U)                         /*!< FMC option bytes unlock key register */
#define FMC_STS             *(unsigned int *)(FMC_BASE + 0x0000000CU)                         /*!< FMC status register */
#define FMC_CTRL            *(unsigned int *)(FMC_BASE + 0x00000010U)                         /*!< FMC control register */
#define FMC_ADDR            *(unsigned int *)(FMC_BASE + 0x00000014U)                         /*!< FMC address register */
#define FMC_OB              *(unsigned int *)(FMC_BASE + 0x0000001CU)                         /*!< FMC option bytes status register */
#define FMC_USER            *(unsigned int *)(FMC_BASE + 0x00000020U)                         /*!< FMC erase/program protection register */
#define FMC_VTOR            *(unsigned int *)(FMC_BASE + 0x00000024U)                         /*!< FMC unlock flash sleep/power-down mode key register */

#define RCC_CFG             *(unsigned int *)(RCC_BASE + 0x00000004U)
#define RCC_CFG2            *(unsigned int *)(RCC_BASE + 0x00000020U) 
#define RCC_CFG_AHBPRES_DIV1    0x00
#define RCC_CFG_APBPRES_DIV1    0x00  

#define PWR_CTRL3           *(unsigned int *)(PWR_BASE + 0x00000004U)

#define FMC_FLAG        0x34
#define FMC_STS_BUSY    (1 << 0)
//#define FMC_STS_FSTAT   (1 << 15)
#define FMC_STS_PGERR   (1 << 2) 
//#define FMC_STS_PGAERR  (1 << 3)
#define FMC_STS_WRPERR  (1 << 4)
#define FMC_STS_EOP     (1 << 5)

#define FMC_CTRL_LOCK   (1 << 7)
#define FMC_CTRL_START  (1 << 6)
#define FMC_CTRL_MER    (1 << 2)
#define FMC_CTRL_PER    (1 << 1)
#define FMC_CTRL_PG     (1 << 0)

#define FMC_TIMEOUT_COUNT   (0x01000000U) 

#define system_init()   do{ \
    PWR_CTRL3 &= ~0x0040;   \
    RCC_CFG |= 0x00001000;  \
    RCC_CFG &= 0xF9FFF80F;  \
    RCC_CFG2 |= 0x00000C01; \
}while(0)

#define flash_unlock()  do{         \
    if((FMC_CTRL & FMC_CTRL_LOCK) != 0) \
    {                               \
        FMC_KEY = UNLOCK_KEY0;      \
        FMC_KEY = UNLOCK_KEY1;      \
    }                               \
}while(0)
#define flash_lock()    do{     \
    FMC_CTRL |= FMC_CTRL_LOCK;  \
}while(0)

#define flash_flagClr() FMC_STS = FMC_FLAG

#define flash_readywait(value)  do{     \
    unsigned int i;                     \
    i = value;                          \
    do{                                 \
        i --;                           \
        if((FMC_STS & FMC_STS_BUSY) == 0) break; \
    }while(i);                          \
}while(0)

#define flash_program()    do{                  \
    unsigned int i;                             \
    flash_unlock();                             \
    for(i=0; i<FlashParameter.size; i += 4)     \
    {                                           \
        flash_flagClr();                        \
        flash_readywait(FMC_TIMEOUT_COUNT);     \
        if((FMC_STS & FMC_STS_BUSY) == 0)       \
        {                                       \
            FMC_CTRL |= FMC_CTRL_PG;            \
            *(unsigned int *)(FlashParameter.addr + i) = *((unsigned int *)(&FlashParameter.data[i]));                    \
            flash_readywait(FMC_TIMEOUT_COUNT); \
            FMC_CTRL &= ~FMC_CTRL_PG;           \
        }                                       \
    }                                           \
    flash_lock();                               \
    FlashParameter.status = 0;                  \
}while(0)

#define flash_erasepage()   do{         \
    flash_unlock();                     \
    flash_flagClr();                    \
    flash_readywait(FMC_TIMEOUT_COUNT); \
    FMC_CTRL |= FMC_CTRL_PER;           \
    FMC_ADDR = FlashParameter.addr;     \
    FMC_CTRL |= FMC_CTRL_START;         \
    flash_readywait(FMC_TIMEOUT_COUNT); \
    FMC_CTRL &= ~FMC_CTRL_PER;          \
    flash_lock();                       \
    FlashParameter.status = 0;          \
}while(0)

#define flash_erasechip()   do{         \
    flash_unlock();                     \
    flash_flagClr();                    \
    flash_readywait(FMC_TIMEOUT_COUNT); \
    FMC_CTRL |= FMC_CTRL_MER;           \
    FMC_ADDR = FlashParameter.addr;     \
    FMC_CTRL |= FMC_CTRL_START;         \
    flash_readywait(FMC_TIMEOUT_COUNT); \
    FMC_CTRL &= ~FMC_CTRL_MER;          \
    flash_lock();                       \
    FlashParameter.status = 0;          \
}while(0)

#endif
