#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     (0x1000U)
#define FMC_BASE            (0x40020000U + 0x00002000U)
#define FMC_WS              *(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_STAT            *(unsigned int *)(FMC_BASE + 0x0000000CU)                         /*!< FMC status register */
#define FMC_CTL             *(unsigned int *)(FMC_BASE + 0x00000010U)                         /*!< FMC control register */
#define FMC_ADDR            *(unsigned int *)(FMC_BASE + 0x00000014U)                         /*!< FMC address register */
#define FMC_OBSTAT          *(unsigned int *)(FMC_BASE + 0x0000001CU)                         /*!< FMC option bytes status register */
#define FMC_WP              *(unsigned int *)(FMC_BASE + 0x00000020U)                         /*!< FMC erase/program protection register */
#define FMC_SLPKEY          *(unsigned int *)(FMC_BASE + 0x00000024U)                         /*!< FMC unlock flash sleep/power-down mode key register */
#define FMC_PID             *(unsigned int *)(FMC_BASE + 0x00000100U)                         /*!< FMC product ID register */

#define FMC_FLAG        0x3c
#define FMC_CTL_LK      (1 << 7)
#define FMC_STAT_BUSY   (1 << 0)
#define FMC_STAT_FSTAT  (1 << 15)
#define FMC_STAT_PGERR  (1 << 2) 
#define FMC_STAT_PGAERR (1 << 3)
#define FMC_STAT_WPERR  (1 << 4)
#define FMC_STAT_ENDF   (1 << 5)
#define FMC_CTL_PER     (1 << 1)
#define FMC_CTL_START   (1 << 6)
#define FMC_CTL_MER     (1 << 2)
#define FMC_CTL_PG      (1 << 0)

#define FMC_TIMEOUT_COUNT   (0x01000000U) 

#define system_init()

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

#define flash_flagClr() FMC_STAT = FMC_FLAG

#define flash_readywait(value)  do{     \
    unsigned int i;                     \
    i = value;                          \
    do{                                 \
        i --;                           \
        if((FMC_STAT & FMC_STAT_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_STAT & FMC_STAT_BUSY) == 0)     \
        {                                       \
            FMC_CTL |= FMC_CTL_PG;              \
            *(unsigned int *)(FlashParameter.addr + i) = *((unsigned int *)(&FlashParameter.data[i]));                    \
            flash_readywait(FMC_TIMEOUT_COUNT); \
            FMC_CTL &= ~FMC_CTL_PG;             \
        }                                       \
    }                                           \
    flash_lock();                               \
    FlashParameter.status = 0;                  \
}while(0)

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

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

#endif
