diff --git a/.gitmodules b/.gitmodules
index c0e6f8f91..1636b9765 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -124,3 +124,6 @@
 [submodule "hw/mcu/mindmotion/mm32sdk"]
 	path = hw/mcu/mindmotion/mm32sdk
 	url = https://github.com/zhangslice/mm32sdk.git
+[submodule "hw/mcu/gd/nuclei-sdk"]
+	path = hw/mcu/gd/nuclei-sdk
+	url = git@github.com:Nuclei-Software/nuclei-sdk.git
diff --git a/hw/bsp/board_mcu.h b/hw/bsp/board_mcu.h
index 9f6b489ea..acfd7348d 100644
--- a/hw/bsp/board_mcu.h
+++ b/hw/bsp/board_mcu.h
@@ -130,6 +130,9 @@
 #elif CFG_TUSB_MCU == OPT_MCU_RX63X || CFG_TUSB_MCU == OPT_MCU_RX65X
   // no header needed
 
+#elif CFG_TUSB_MCU == OPT_MCU_GD32VF103
+  #include "gd32vf103.h"
+
 #else
   #error "Missing MCU header"
 #endif
diff --git a/hw/bsp/gd32vf103_longan_nano/board.mk b/hw/bsp/gd32vf103_longan_nano/board.mk
new file mode 100644
index 000000000..f34f68c22
--- /dev/null
+++ b/hw/bsp/gd32vf103_longan_nano/board.mk
@@ -0,0 +1,59 @@
+CROSS_COMPILE = riscv32-unknown-elf-
+
+DEPS_SUBMODULES += hw/mcu/gd/nuclei-sdk
+
+NUCLEI_SDK = hw/mcu/gd/nuclei-sdk
+GD32VF103_SDK_SOC_COMMON = $(NUCLEI_SDK)/SoC/gd32vf103/Common
+GD32VF103_SDK_DRIVER = $(GD32VF103_SDK_SOC_COMMON)/Source/Drivers
+SKIP_NANOLIB = 1
+
+CFLAGS += \
+  -march=rv32imac \
+  -mabi=ilp32 \
+  -mcmodel=medlow \
+  -mstrict-align \
+  -nostdlib -nostartfiles \
+  -DCFG_TUSB_MCU=OPT_MCU_GD32VF103 \
+  -DDOWNLOAD_MODE=DOWNLOAD_MODE_FLASHXIP \
+  -DGD32VF103 
+
+# mcu driver cause following warnings
+#CFLAGS += -Wno-error=unused-parameter
+
+# All source paths should be relative to the top level.
+LD_FILE = hw/bsp/$(BOARD)/gcc_gd32vf103xb_flashxip.ld # 128kb ROM 32kb RAM
+# LD_FILE = hw/bsp/$(BOARD)/gcc_gd32vf103x8_flashxip.ld # 64kb ROM 20kb RAM Longan Nano Lite
+
+SRC_C += \
+  src/portable/st/synopsys/dcd_synopsys.c \
+	$(GD32VF103_SDK_DRIVER)/gd32vf103_rcu.c \
+	$(GD32VF103_SDK_DRIVER)/gd32vf103_gpio.c \
+	$(GD32VF103_SDK_DRIVER)/Usb/gd32vf103_usb_hw.c \
+	$(GD32VF103_SDK_DRIVER)/gd32vf103_fmc.c \
+	$(GD32VF103_SDK_DRIVER)/gd32vf103_usart.c \
+	$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/sbrk.c \
+	$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/close.c \
+	$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/isatty.c \
+	$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/fstat.c \
+	$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/lseek.c \
+	$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/read.c 
+
+SRC_S += \
+  $(GD32VF103_SDK_SOC_COMMON)/Source/GCC/startup_gd32vf103.S \
+  $(GD32VF103_SDK_SOC_COMMON)/Source/GCC/intexc_gd32vf103.S
+
+INC += \
+  $(TOP)/hw/bsp/$(BOARD) \
+	$(TOP)/$(NUCLEI_SDK)/NMSIS/Core/Include \
+	$(TOP)/$(GD32VF103_SDK_SOC_COMMON)/Include \
+	$(TOP)/$(GD32VF103_SDK_SOC_COMMON)/Include/Usb \
+
+# For freeRTOS port source
+#FREERTOS_PORT = ARM_CM3
+
+# For flash-jlink target
+JLINK_DEVICE = gd32vf103cb
+
+# flash target ROM bootloader
+flash: $(BUILD)/$(PROJECT).bin
+	dfu-util -R -a 0 --dfuse-address 0x08000000 -D $<
diff --git a/hw/bsp/gd32vf103_longan_nano/gcc_gd32vf103x8_flashxip.ld b/hw/bsp/gd32vf103_longan_nano/gcc_gd32vf103x8_flashxip.ld
new file mode 100644
index 000000000..10f3747e0
--- /dev/null
+++ b/hw/bsp/gd32vf103_longan_nano/gcc_gd32vf103x8_flashxip.ld
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2019 - 2020 Nuclei Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/******************************************************************************
+ * @file     gcc_gd32vf103x8_flashxip.ld
+ * @brief    GNU Linker Script for gd32vf103x8 based device
+ * @version  V1.0.0
+ * @date     1. Dec 2020
+ ******************************************************************************/
+
+/*********** Use Configuration Wizard in Context Menu *************************/
+
+OUTPUT_ARCH( "riscv" )
+/********************* Flash Configuration ************************************
+ *  Flash Configuration
+ *  Flash Base Address <0x0-0xFFFFFFFF:8>
+ *  Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ * 
+ */
+__ROM_BASE = 0x08000000;
+__ROM_SIZE = 0x00010000;
+
+/*--------------------- ILM RAM Configuration ---------------------------
+ *  ILM RAM Configuration
+ *  ILM RAM Base Address    <0x0-0xFFFFFFFF:8>
+ *  ILM RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ * 
+ */
+__ILM_RAM_BASE = 0x80000000;
+__ILM_RAM_SIZE = 0x00010000;
+
+/*--------------------- Embedded RAM Configuration ---------------------------
+ *  RAM Configuration
+ *  RAM Base Address    <0x0-0xFFFFFFFF:8>
+ *  RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ * 
+*/
+__RAM_BASE = 0x20000000;
+__RAM_SIZE = 0x00005000;
+
+/********************* Stack / Heap Configuration ****************************
+ *  Stack / Heap Configuration
+ *  Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ *  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ * 
+ */
+__STACK_SIZE = 0x00000800;
+__HEAP_SIZE  = 0x00000800;
+
+/**************************** end of configuration section ********************/
+
+/* Define base address and length of flash and ram */
+MEMORY
+{
+  flash (rxai!w) : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
+  ram (wxa!ri) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE
+}
+/* Linker script to place sections and symbol values. Should be used together
+ * with other linker script that defines memory regions FLASH,ILM and RAM.
+ * It references following symbols, which must be defined in code:
+ *   _Start : Entry of reset handler
+ *
+ * It defines following symbols, which code can use without definition:
+ *   _ilm_lma
+ *   _ilm
+ *   __etext
+ *   _etext
+ *   etext
+ *   _eilm
+ *   __preinit_array_start
+ *   __preinit_array_end
+ *   __init_array_start
+ *   __init_array_end
+ *   __fini_array_start
+ *   __fini_array_end
+ *   _data_lma
+ *   _edata
+ *   edata
+ *   __data_end__
+ *   __bss_start
+ *   __fbss
+ *   _end
+ *   end
+ *   __heap_end
+ *   __StackLimit
+ *   __StackTop
+ *   __STACK_SIZE
+ */
+/* Define entry label of program */
+ENTRY(_start)
+SECTIONS
+{
+  __STACK_SIZE = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 2K;
+
+  .init           :
+  {
+    /* vector table locate at flash */
+    *(.vtable)
+    KEEP (*(SORT_NONE(.init)))
+  } >flash AT>flash
+
+  .ilalign         :
+  {
+    . = ALIGN(4);
+    /* Create a section label as _ilm_lma which located at flash */
+    PROVIDE( _ilm_lma = . );
+  } >flash AT>flash
+
+  .ialign         :
+  {
+    /* Create a section label as _ilm which located at flash */
+    PROVIDE( _ilm = . );
+  } >flash AT>flash
+
+  /* Code section located at flash */
+  .text           :
+  {
+    *(.text.unlikely .text.unlikely.*)
+    *(.text.startup .text.startup.*)
+    *(.text .text.*)
+    *(.gnu.linkonce.t.*)
+  } >flash AT>flash
+
+  .rodata : ALIGN(4)
+  {
+    . = ALIGN(4);
+    *(.rdata)
+    *(.rodata .rodata.*)
+    /* section information for initial. */
+    . = ALIGN(4);
+    __rt_init_start = .;
+    KEEP(*(SORT(.rti_fn*)))
+    __rt_init_end = .;
+    /* section information for finsh shell */
+    . = ALIGN(4);
+    __fsymtab_start = .;
+    KEEP(*(FSymTab))
+    __fsymtab_end = .;
+    . = ALIGN(4);
+    __vsymtab_start = .;
+    KEEP(*(VSymTab))
+    __vsymtab_end = .;
+    *(.gnu.linkonce.r.*)
+    . = ALIGN(8);
+    *(.srodata.cst16)
+    *(.srodata.cst8)
+    *(.srodata.cst4)
+    *(.srodata.cst2)
+    *(.srodata .srodata.*)
+  } >flash AT>flash
+
+  .fini           :
+  {
+    KEEP (*(SORT_NONE(.fini)))
+  } >flash AT>flash
+
+  . = ALIGN(4);
+
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  PROVIDE( _eilm = . );
+
+
+  .preinit_array  :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  } >flash AT>flash
+
+  .init_array     :
+  {
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+    PROVIDE_HIDDEN (__init_array_end = .);
+  } >flash AT>flash
+
+  .fini_array     :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  } >flash AT>flash
+
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+     * the constructors, so we make sure it is
+     * first.  Because this is a wildcard, it
+     * doesn't matter if the user does not
+     * actually link against crtbegin.o; the
+     * linker won't look for a file to match a
+     * wildcard.  The wildcard also means that it
+     * doesn't matter which directory crtbegin.o
+     * is in.
+     */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*crtbegin?.o(.ctors))
+    /* We don't want to include the .ctor section from
+     * the crtend.o file until after the sorted ctors.
+     * The .ctor section from the crtend file contains the
+     * end of ctors marker and it must be last
+     */
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  } >flash AT>flash
+
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  } >flash AT>flash
+
+  .lalign         :
+  {
+    . = ALIGN(4);
+    PROVIDE( _data_lma = . );
+  } >flash AT>flash
+
+  .dalign         :
+  {
+    . = ALIGN(4);
+    PROVIDE( _data = . );
+  } >ram AT>flash
+
+  /* Define data section virtual address is ram and physical address is flash */
+  .data          :
+  {
+    *(.data .data.*)
+    *(.gnu.linkonce.d.*)
+    . = ALIGN(8);
+    PROVIDE( __global_pointer$ = . + 0x800 );
+    *(.sdata .sdata.* .sdata*)
+    *(.gnu.linkonce.s.*)
+  } >ram AT>flash
+
+  . = ALIGN(4);
+  PROVIDE( _edata = . );
+  PROVIDE( edata = . );
+
+  PROVIDE( _fbss = . );
+  PROVIDE( __bss_start = . );
+  .bss            :
+  {
+    *(.sbss*)
+    *(.gnu.linkonce.sb.*)
+    *(.bss .bss.*)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+    . = ALIGN(4);
+  } >ram AT>ram
+
+  . = ALIGN(8);
+  PROVIDE( _end = . );
+  PROVIDE( end = . );
+  /* Define stack and head location at ram */
+  .stack ORIGIN(ram) + LENGTH(ram) - __STACK_SIZE :
+  {
+    PROVIDE( _heap_end = . );
+    . = __STACK_SIZE;
+    PROVIDE( _sp = . );
+  } >ram AT>ram
+}
diff --git a/hw/bsp/gd32vf103_longan_nano/gcc_gd32vf103xb_flashxip.ld b/hw/bsp/gd32vf103_longan_nano/gcc_gd32vf103xb_flashxip.ld
new file mode 100644
index 000000000..14d317f14
--- /dev/null
+++ b/hw/bsp/gd32vf103_longan_nano/gcc_gd32vf103xb_flashxip.ld
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2019 - 2020 Nuclei Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/******************************************************************************
+ * @file     gcc_gd32vf103xb_flashxip.ld
+ * @brief    GNU Linker Script for gd32vf103xb based device
+ * @version  V1.0.0
+ * @date     1. Dec 2020
+ ******************************************************************************/
+
+/*********** Use Configuration Wizard in Context Menu *************************/
+
+OUTPUT_ARCH( "riscv" )
+/********************* Flash Configuration ************************************
+ *  Flash Configuration
+ *  Flash Base Address <0x0-0xFFFFFFFF:8>
+ *  Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ * 
+ */
+__ROM_BASE = 0x08000000;
+__ROM_SIZE = 0x00020000;
+
+/*--------------------- ILM RAM Configuration ---------------------------
+ *  ILM RAM Configuration
+ *  ILM RAM Base Address    <0x0-0xFFFFFFFF:8>
+ *  ILM RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ * 
+ */
+__ILM_RAM_BASE = 0x80000000;
+__ILM_RAM_SIZE = 0x00010000;
+
+/*--------------------- Embedded RAM Configuration ---------------------------
+ *  RAM Configuration
+ *  RAM Base Address    <0x0-0xFFFFFFFF:8>
+ *  RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ * 
+*/
+__RAM_BASE = 0x20000000;
+__RAM_SIZE = 0x00008000;
+
+/********************* Stack / Heap Configuration ****************************
+ *  Stack / Heap Configuration
+ *  Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ *  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ * 
+ */
+__STACK_SIZE = 0x00000800;
+__HEAP_SIZE  = 0x00000800;
+
+/**************************** end of configuration section ********************/
+
+/* Define base address and length of flash and ram */
+MEMORY
+{
+  flash (rxai!w) : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
+  ram (wxa!ri) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE
+}
+/* Linker script to place sections and symbol values. Should be used together
+ * with other linker script that defines memory regions FLASH,ILM and RAM.
+ * It references following symbols, which must be defined in code:
+ *   _Start : Entry of reset handler
+ *
+ * It defines following symbols, which code can use without definition:
+ *   _ilm_lma
+ *   _ilm
+ *   __etext
+ *   _etext
+ *   etext
+ *   _eilm
+ *   __preinit_array_start
+ *   __preinit_array_end
+ *   __init_array_start
+ *   __init_array_end
+ *   __fini_array_start
+ *   __fini_array_end
+ *   _data_lma
+ *   _edata
+ *   edata
+ *   __data_end__
+ *   __bss_start
+ *   __fbss
+ *   _end
+ *   end
+ *   __heap_end
+ *   __StackLimit
+ *   __StackTop
+ *   __STACK_SIZE
+ */
+/* Define entry label of program */
+ENTRY(_start)
+SECTIONS
+{
+  __STACK_SIZE = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 2K;
+
+  .init           :
+  {
+    /* vector table locate at flash */
+    *(.vtable)
+    KEEP (*(SORT_NONE(.init)))
+  } >flash AT>flash
+
+  .ilalign         :
+  {
+    . = ALIGN(4);
+    /* Create a section label as _ilm_lma which located at flash */
+    PROVIDE( _ilm_lma = . );
+  } >flash AT>flash
+
+  .ialign         :
+  {
+    /* Create a section label as _ilm which located at flash */
+    PROVIDE( _ilm = . );
+  } >flash AT>flash
+
+  /* Code section located at flash */
+  .text           :
+  {
+    *(.text.unlikely .text.unlikely.*)
+    *(.text.startup .text.startup.*)
+    *(.text .text.*)
+    *(.gnu.linkonce.t.*)
+  } >flash AT>flash
+
+  .rodata : ALIGN(4)
+  {
+    . = ALIGN(4);
+    *(.rdata)
+    *(.rodata .rodata.*)
+    /* section information for initial. */
+    . = ALIGN(4);
+    __rt_init_start = .;
+    KEEP(*(SORT(.rti_fn*)))
+    __rt_init_end = .;
+    /* section information for finsh shell */
+    . = ALIGN(4);
+    __fsymtab_start = .;
+    KEEP(*(FSymTab))
+    __fsymtab_end = .;
+    . = ALIGN(4);
+    __vsymtab_start = .;
+    KEEP(*(VSymTab))
+    __vsymtab_end = .;
+    *(.gnu.linkonce.r.*)
+    . = ALIGN(8);
+    *(.srodata.cst16)
+    *(.srodata.cst8)
+    *(.srodata.cst4)
+    *(.srodata.cst2)
+    *(.srodata .srodata.*)
+  } >flash AT>flash
+
+  .fini           :
+  {
+    KEEP (*(SORT_NONE(.fini)))
+  } >flash AT>flash
+
+  . = ALIGN(4);
+
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  PROVIDE( _eilm = . );
+
+
+  .preinit_array  :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  } >flash AT>flash
+
+  .init_array     :
+  {
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+    PROVIDE_HIDDEN (__init_array_end = .);
+  } >flash AT>flash
+
+  .fini_array     :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  } >flash AT>flash
+
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+     * the constructors, so we make sure it is
+     * first.  Because this is a wildcard, it
+     * doesn't matter if the user does not
+     * actually link against crtbegin.o; the
+     * linker won't look for a file to match a
+     * wildcard.  The wildcard also means that it
+     * doesn't matter which directory crtbegin.o
+     * is in.
+     */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*crtbegin?.o(.ctors))
+    /* We don't want to include the .ctor section from
+     * the crtend.o file until after the sorted ctors.
+     * The .ctor section from the crtend file contains the
+     * end of ctors marker and it must be last
+     */
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  } >flash AT>flash
+
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  } >flash AT>flash
+
+  .lalign         :
+  {
+    . = ALIGN(4);
+    PROVIDE( _data_lma = . );
+  } >flash AT>flash
+
+  .dalign         :
+  {
+    . = ALIGN(4);
+    PROVIDE( _data = . );
+  } >ram AT>flash
+
+  /* Define data section virtual address is ram and physical address is flash */
+  .data          :
+  {
+    *(.data .data.*)
+    *(.gnu.linkonce.d.*)
+    . = ALIGN(8);
+    PROVIDE( __global_pointer$ = . + 0x800 );
+    *(.sdata .sdata.* .sdata*)
+    *(.gnu.linkonce.s.*)
+  } >ram AT>flash
+
+  . = ALIGN(4);
+  PROVIDE( _edata = . );
+  PROVIDE( edata = . );
+
+  PROVIDE( _fbss = . );
+  PROVIDE( __bss_start = . );
+  .bss            :
+  {
+    *(.sbss*)
+    *(.gnu.linkonce.sb.*)
+    *(.bss .bss.*)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+    . = ALIGN(4);
+  } >ram AT>ram
+
+  . = ALIGN(8);
+  PROVIDE( _end = . );
+  PROVIDE( end = . );
+  /* Define stack and head location at ram */
+  .stack ORIGIN(ram) + LENGTH(ram) - __STACK_SIZE :
+  {
+    PROVIDE( _heap_end = . );
+    . = __STACK_SIZE;
+    PROVIDE( _sp = . );
+  } >ram AT>ram
+}
diff --git a/hw/bsp/gd32vf103_longan_nano/gd32vf103_longan_nano.c b/hw/bsp/gd32vf103_longan_nano/gd32vf103_longan_nano.c
new file mode 100644
index 000000000..f501c20b4
--- /dev/null
+++ b/hw/bsp/gd32vf103_longan_nano/gd32vf103_longan_nano.c
@@ -0,0 +1,274 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "../board.h"
+#include "nuclei_sdk_hal.h"
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+
+void USBFS_IRQHandler(void) { tud_int_handler(0); }
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+#define HXTAL_VALUE \
+  ((uint32_t)8000000) /*!< value of the external oscillator in Hz */
+#define USB_NO_VBUS_PIN 1
+
+//--------------------------------------------------------------------+
+// LED
+//--------------------------------------------------------------------+
+
+#define LED_PORT GPIOC
+#define LED_PIN GPIO_PIN_13
+#define LED_STATE_ON 1
+
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PIN_0
+#define BUTTON_STATE_ACTIVE 1
+
+//--------------------------------------------------------------------+
+// UART
+//--------------------------------------------------------------------+
+
+#define UART_DEV USART0
+#define UART_GPIO_PORT GPIOA
+#define UART_TX_PIN GPIO_PIN_9
+#define UART_RX_PIN GPIO_PIN_10
+
+/* sipeed longan nano board UART com port */
+#define GD32_COM0 USART0
+#define GD32_COM_CLK RCU_USART0
+#define GD32_COM_TX_PIN GPIO_PIN_9
+#define GD32_COM_RX_PIN GPIO_PIN_10
+#define GD32_COM_TX_GPIO_PORT GPIOA
+#define GD32_COM_RX_GPIO_PORT GPIOA
+#define GD32_COM_TX_GPIO_CLK RCU_GPIOA
+#define GD32_COM_RX_GPIO_CLK RCU_GPIOA
+
+void board_init(void) {
+  /* Disable interrupts during init */
+  __disable_irq();
+
+  /* Reset eclic configuration registers */
+  ECLIC->CFG = 0;
+  ECLIC->MTH = 0;
+
+  /* Reset eclic interrupt registers */
+  for (int32_t i = 0; i < SOC_INT_MAX; i++) {
+    ECLIC->CTRL[0].INTIP = 0;
+    ECLIC->CTRL[0].INTIE = 0;
+    ECLIC->CTRL[0].INTATTR = 0;
+    ECLIC->CTRL[0].INTCTRL = 0;
+  }
+
+  /* Set 4 bits for interrupt level and 0 bits for priority */
+  __ECLIC_SetCfgNlbits(4);
+
+  SystemCoreClockUpdate();
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+  SysTimer_SetLoadValue(0);
+  SysTimer_SetCompareValue(SystemCoreClock / 1000);
+  ECLIC_SetLevelIRQ(SysTimer_IRQn, 3);
+  ECLIC_SetTrigIRQ(SysTimer_IRQn, ECLIC_POSTIVE_EDGE_TRIGGER);
+  ECLIC_EnableIRQ(SysTimer_IRQn);
+  SysTimer_Start();
+#endif
+
+  rcu_periph_clock_enable(RCU_GPIOA);
+  rcu_periph_clock_enable(RCU_GPIOB);
+  rcu_periph_clock_enable(RCU_GPIOC);
+  rcu_periph_clock_enable(RCU_GPIOD);
+  rcu_periph_clock_enable(RCU_AF);
+
+#ifdef BUTTON_PIN
+  gpio_init(BUTTON_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, BUTTON_PIN);
+#endif
+
+#ifdef LED_PIN
+  gpio_init(LED_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED_PIN);
+  board_led_write(0);
+#endif
+
+#if defined(UART_DEV) && CFG_TUSB_DEBUG
+  /* enable GPIO TX and RX clock */
+  rcu_periph_clock_enable(GD32_COM_TX_GPIO_CLK);
+  rcu_periph_clock_enable(GD32_COM_RX_GPIO_CLK);
+
+  /* enable USART clock */
+  rcu_periph_clock_enable(GD32_COM_CLK);
+
+  /* connect port to USARTx_Tx */
+  gpio_init(GD32_COM_TX_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
+            GD32_COM_TX_PIN);
+
+  /* connect port to USARTx_Rx */
+  gpio_init(GD32_COM_RX_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ,
+            GD32_COM_RX_PIN);
+
+  /* USART configure */
+  usart_deinit(UART_DEV);
+  usart_baudrate_set(UART_DEV, 115200U);
+  usart_word_length_set(UART_DEV, USART_WL_8BIT);
+  usart_stop_bit_set(UART_DEV, USART_STB_1BIT);
+  usart_parity_config(UART_DEV, USART_PM_NONE);
+  usart_hardware_flow_rts_config(UART_DEV, USART_RTS_DISABLE);
+  usart_hardware_flow_cts_config(UART_DEV, USART_CTS_DISABLE);
+  usart_receive_config(UART_DEV, USART_RECEIVE_ENABLE);
+  usart_transmit_config(UART_DEV, USART_TRANSMIT_ENABLE);
+  usart_enable(UART_DEV);
+#endif
+
+  /* USB D+ and D- pins don't need to be configured. */
+  /* Configure VBUS Pin */
+#ifndef USB_NO_VBUS_PIN
+  gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
+#endif
+
+  /* This for ID line debug */
+  // gpio_init(GPIOA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
+
+  /* Enable USB OTG clock */
+  usb_rcu_config();
+
+  /* Reset USB OTG peripheral */
+  rcu_periph_reset_enable(RCU_USBFSRST);
+  rcu_periph_reset_disable(RCU_USBFSRST);
+
+  /* Set IRQ priority and trigger */
+  ECLIC_SetLevelIRQ(USBFS_IRQn, 15);
+  ECLIC_SetTrigIRQ(USBFS_IRQn, ECLIC_POSTIVE_EDGE_TRIGGER);
+
+  /* Retrieve otg core registers */
+  usb_gr* otg_core_regs = (usb_gr*)(USBFS_REG_BASE + USB_REG_OFFSET_CORE);
+
+#ifdef USB_NO_VBUS_PIN
+  /* Disable VBUS sense*/
+  otg_core_regs->GCCFG |= GCCFG_VBUSIG | GCCFG_PWRON | GCCFG_VBUSBCEN;
+#else
+  /* Enable VBUS sense via pin PA9 */
+  otg_core_regs->GCCFG |= GCCFG_VBUSIG | GCCFG_PWRON | GCCFG_VBUSBCEN;
+  otg_core_regs->GCCFG &= ~GCCFG_VBUSIG;
+#endif
+
+  /* Enable interrupts globaly */
+  __enable_irq();
+}
+
+#include "gd32vf103_dbg.h"
+
+#define DBG_KEY_UNLOCK 0x4B5A6978
+#define DBG_CMD_RESET 0x1
+
+#define DBG_KEY REG32(DBG + 0x0C)
+#define DBG_CMD REG32(DBG + 0x08)
+
+void gd32vf103_reset(void) {
+  /* The MTIMER unit of the GD32VF103 doesn't have the MSFRST
+   * register to generate a software reset request.
+   * BUT instead two undocumented registers in the debug peripheral
+   * that allow issueing a software reset.
+   * https://github.com/esmil/gd32vf103inator/blob/master/include/gd32vf103/dbg.h
+   */
+  DBG_KEY = DBG_KEY_UNLOCK;
+  DBG_CMD = DBG_CMD_RESET;
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state) {
+  gpio_bit_write(LED_PORT, LED_PIN, state ? LED_STATE_ON : (1 - LED_STATE_ON));
+}
+
+uint32_t board_button_read(void) {
+  return BUTTON_STATE_ACTIVE == gpio_input_bit_get(BUTTON_PORT, BUTTON_PIN);
+}
+
+int board_uart_read(uint8_t* buf, int len) {
+#if defined(UART_DEV) && CFG_TUSB_DEBUG
+
+  int rxsize = len;
+  while (rxsize--) {
+    *(uint8_t*)buf = usart_read(UART_DEV);
+    buf++;
+  }
+  return len;
+#else
+  (void)buf;
+  (void)len;
+  return 0;
+#endif
+}
+
+int board_uart_write(void const* buf, int len) {
+#if defined(UART_DEV) && CFG_TUSB_DEBUG
+
+  int txsize = len;
+  while (txsize--) {
+    usart_write(UART_DEV, *(uint8_t*)buf);
+    buf++;
+  }
+  return len;
+#else
+  (void)buf;
+  (void)len;
+  return 0;
+#endif
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+void eclic_mtip_handler(void) { system_ticks++; }
+uint32_t board_millis(void) { return system_ticks; }
+#endif
+
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief  Reports the name of the source file and the source line number
+ *         where the assert_param error has occurred.
+ * @param  file: pointer to the source file name
+ * @param  line: assert_param error line source number
+ * @retval None
+ */
+void assert_failed(char* file, uint32_t line) {
+  /* USER CODE BEGIN 6 */
+  /* User can add his own implementation to report the file name and line
+     number,
+     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line)
+   */
+  /* USER CODE END 6 */
+}
+#endif /* USE_FULL_ASSERT */
+
+// Required by __libc_init_array in startup code if we are compiling using
+// -nostdlib/-nostartfiles.
+// void _init(void) {}
diff --git a/hw/bsp/gd32vf103_longan_nano/nuclei_sdk_hal.h b/hw/bsp/gd32vf103_longan_nano/nuclei_sdk_hal.h
new file mode 100644
index 000000000..eacfb5eef
--- /dev/null
+++ b/hw/bsp/gd32vf103_longan_nano/nuclei_sdk_hal.h
@@ -0,0 +1,20 @@
+// See LICENSE for license details.
+#ifndef _NUCLEI_SDK_HAL_H
+#define _NUCLEI_SDK_HAL_H
+
+#include "nmsis_gcc.h"
+#include "gd32vf103.h"
+#include "gd32vf103_libopt.h"
+#include "drv_usb_hw.h"
+#include "drv_usb_dev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SOC_DEBUG_UART      USART0
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/hw/bsp/gd32vf103_longan_nano/system_gd32vf103.c b/hw/bsp/gd32vf103_longan_nano/system_gd32vf103.c
new file mode 100644
index 000000000..54c8804c4
--- /dev/null
+++ b/hw/bsp/gd32vf103_longan_nano/system_gd32vf103.c
@@ -0,0 +1,1256 @@
+/*!
+ \file    system_gd32vf103.h
+\brief   RISC-V Device Peripheral Access Layer Source File for
+          GD32VF103 Device Series
+
+*/
+
+/*
+    Copyright (c) 2020, GigaDevice Semiconductor Inc.
+
+    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 the copyright holder 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.
+*/
+
+/* This file refers the RISC-V standard, some adjustments are made according to GigaDevice chips */
+
+#include "gd32vf103_libopt.h"
+
+/* system frequency define */
+#define __IRC8M           (IRC8M_VALUE)            /* internal 8 MHz RC oscillator frequency */
+#define __HXTAL           (HXTAL_VALUE)            /* high speed crystal oscillator frequency */
+#define __SYS_OSC_CLK     (__IRC8M)                /* main oscillator frequency */
+
+/* select a system clock by uncommenting the following line */
+/* use IRC8M */
+//#define __SYSTEM_CLOCK_48M_PLL_IRC8M            (uint32_t)(48000000)
+//#define __SYSTEM_CLOCK_72M_PLL_IRC8M            (uint32_t)(72000000)
+//#define __SYSTEM_CLOCK_108M_PLL_IRC8M           (uint32_t)(108000000)
+
+/********************************************************************/
+//#define __SYSTEM_CLOCK_HXTAL                    (HXTAL_VALUE)
+//#define __SYSTEM_CLOCK_24M_PLL_HXTAL            (uint32_t)(24000000)
+/********************************************************************/
+
+//#define __SYSTEM_CLOCK_36M_PLL_HXTAL            (uint32_t)(36000000)
+//#define __SYSTEM_CLOCK_48M_PLL_HXTAL            (uint32_t)(48000000)
+//#define __SYSTEM_CLOCK_56M_PLL_HXTAL            (uint32_t)(56000000)
+//#define __SYSTEM_CLOCK_72M_PLL_HXTAL            (uint32_t)(72000000)
+#define __SYSTEM_CLOCK_96M_PLL_HXTAL            (uint32_t)(96000000)
+//#define __SYSTEM_CLOCK_108M_PLL_HXTAL           (uint32_t)(108000000)
+
+/*#define SEL_IRC8M       0x00U
+#define SEL_HXTAL       0x01U
+#define SEL_PLL         0x02U*/
+
+/* set the system clock frequency and declare the system clock configuration function */
+#ifdef __SYSTEM_CLOCK_48M_PLL_IRC8M
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_IRC8M;
+static void system_clock_48m_irc8m(void);
+#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_IRC8M;
+static void system_clock_72m_irc8m(void);
+#elif defined (__SYSTEM_CLOCK_108M_PLL_IRC8M)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_108M_PLL_IRC8M;
+static void system_clock_108m_irc8m(void);
+
+#elif defined (__SYSTEM_CLOCK_HXTAL)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_HXTAL;
+static void system_clock_hxtal(void);
+#elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_24M_PLL_HXTAL;
+static void system_clock_24m_hxtal(void);
+#elif defined (__SYSTEM_CLOCK_36M_PLL_HXTAL)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_36M_PLL_HXTAL;
+static void system_clock_36m_hxtal(void);
+#elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_HXTAL;
+static void system_clock_48m_hxtal(void);
+#elif defined (__SYSTEM_CLOCK_56M_PLL_HXTAL)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_56M_PLL_HXTAL;
+static void system_clock_56m_hxtal(void);
+#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_HXTAL;
+static void system_clock_72m_hxtal(void);
+#elif defined (__SYSTEM_CLOCK_96M_PLL_HXTAL)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_96M_PLL_HXTAL;
+static void system_clock_96m_hxtal(void);
+#elif defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_108M_PLL_HXTAL;
+static void system_clock_108m_hxtal(void);
+#else
+uint32_t SystemCoreClock = IRC8M_VALUE;
+#endif /* __SYSTEM_CLOCK_48M_PLL_IRC8M */
+
+/* configure the system clock */
+static void system_clock_config(void);
+
+/*!
+    \brief      configure the system clock
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_config(void)
+{
+#ifdef __SYSTEM_CLOCK_HXTAL
+    system_clock_hxtal();
+#elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
+    system_clock_24m_hxtal();
+#elif defined (__SYSTEM_CLOCK_36M_PLL_HXTAL)
+    system_clock_36m_hxtal();
+#elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
+    system_clock_48m_hxtal();
+#elif defined (__SYSTEM_CLOCK_56M_PLL_HXTAL)
+    system_clock_56m_hxtal();
+#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
+    system_clock_72m_hxtal();
+#elif defined (__SYSTEM_CLOCK_96M_PLL_HXTAL)
+    system_clock_96m_hxtal();
+#elif defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)
+    system_clock_108m_hxtal();
+
+#elif defined (__SYSTEM_CLOCK_48M_PLL_IRC8M)
+    system_clock_48m_irc8m();
+#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
+    system_clock_72m_irc8m();
+#elif defined (__SYSTEM_CLOCK_108M_PLL_IRC8M)
+    system_clock_108m_irc8m();
+#endif /* __SYSTEM_CLOCK_HXTAL */
+}
+
+/*!
+    \brief      setup the microcontroller system, initialize the system
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void SystemInit(void)
+{
+    /* reset the RCC clock configuration to the default reset state */
+    /* enable IRC8M */
+    RCU_CTL |= RCU_CTL_IRC8MEN;
+    
+    /* reset SCS, AHBPSC, APB1PSC, APB2PSC, ADCPSC, CKOUT0SEL bits */
+    RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |
+                  RCU_CFG0_ADCPSC | RCU_CFG0_ADCPSC_2 | RCU_CFG0_CKOUT0SEL);
+
+    /* reset HXTALEN, CKMEN, PLLEN bits */
+    RCU_CTL &= ~(RCU_CTL_HXTALEN | RCU_CTL_CKMEN | RCU_CTL_PLLEN);
+
+    /* Reset HXTALBPS bit */
+    RCU_CTL &= ~(RCU_CTL_HXTALBPS);
+
+    /* reset PLLSEL, PREDV0_LSB, PLLMF, USBFSPSC bits */
+    
+    RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0_LSB | RCU_CFG0_PLLMF |
+                  RCU_CFG0_USBFSPSC | RCU_CFG0_PLLMF_4);
+    RCU_CFG1 = 0x00000000U;
+
+    /* Reset HXTALEN, CKMEN, PLLEN, PLL1EN and PLL2EN bits */
+    RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_PLL1EN | RCU_CTL_PLL2EN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN);
+    /* disable all interrupts */
+    RCU_INT = 0x00FF0000U;
+
+    /* Configure the System clock source, PLL Multiplier, AHB/APBx prescalers and Flash settings */
+    system_clock_config();
+}
+
+/*!
+    \brief      update the SystemCoreClock with current core clock retrieved from cpu registers
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void SystemCoreClockUpdate(void)
+{
+    uint32_t scss;
+    uint32_t pllsel, predv0sel, pllmf, ck_src;
+    uint32_t predv0, predv1, pll1mf;
+
+    scss = GET_BITS(RCU_CFG0, 2, 3);
+
+    switch (scss)
+    {
+        /* IRC8M is selected as CK_SYS */
+        case SEL_IRC8M:
+            SystemCoreClock = IRC8M_VALUE;
+            break;
+            
+        /* HXTAL is selected as CK_SYS */
+        case SEL_HXTAL:
+            SystemCoreClock = HXTAL_VALUE;
+            break;
+            
+        /* PLL is selected as CK_SYS */
+        case SEL_PLL:
+            /* PLL clock source selection, HXTAL or IRC8M/2 */
+            pllsel = (RCU_CFG0 & RCU_CFG0_PLLSEL);
+
+
+            if(RCU_PLLSRC_IRC8M_DIV2 == pllsel){
+                /* PLL clock source is IRC8M/2 */
+                ck_src = IRC8M_VALUE / 2U;
+            }else{
+                /* PLL clock source is HXTAL */
+                ck_src = HXTAL_VALUE;
+
+                predv0sel = (RCU_CFG1 & RCU_CFG1_PREDV0SEL);
+
+                /* source clock use PLL1 */
+                if(RCU_PREDV0SRC_CKPLL1 == predv0sel){
+                    predv1 = ((RCU_CFG1 & RCU_CFG1_PREDV1) >> 4) + 1U;
+                    pll1mf = ((RCU_CFG1 & RCU_CFG1_PLL1MF) >> 8) + 2U;
+                    if(17U == pll1mf){
+                        pll1mf = 20U;
+                    }
+                    ck_src = (ck_src / predv1) * pll1mf;
+                }
+                predv0 = (RCU_CFG1 & RCU_CFG1_PREDV0) + 1U;
+                ck_src /= predv0;
+            }
+
+            /* PLL multiplication factor */
+            pllmf = GET_BITS(RCU_CFG0, 18, 21);
+
+            if((RCU_CFG0 & RCU_CFG0_PLLMF_4)){
+                pllmf |= 0x10U;
+            }
+
+            if(pllmf >= 15U){
+                pllmf += 1U;
+            }else{
+                pllmf += 2U;
+            }
+
+            SystemCoreClock = ck_src * pllmf;
+
+            if(15U == pllmf){
+                /* PLL source clock multiply by 6.5 */
+                SystemCoreClock = ck_src * 6U + ck_src / 2U;
+            }
+
+            break;
+
+        /* IRC8M is selected as CK_SYS */
+        default:
+            SystemCoreClock = IRC8M_VALUE;
+            break;
+    }
+}
+
+#ifdef __SYSTEM_CLOCK_HXTAL
+/*!
+    \brief      configure the system clock to HXTAL
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_hxtal(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+    
+    /* enable HXTAL */
+    RCU_CTL |= RCU_CTL_HXTALEN;
+    
+    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+    }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+    
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+        while(1){
+        }
+    }
+    
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+    
+    /* select HXTAL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_HXTAL;
+    
+    /* wait until HXTAL is selected as system clock */
+    while(0 == (RCU_CFG0 & RCU_SCSS_HXTAL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
+/*!
+    \brief      configure the system clock to 24M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_24m_hxtal(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+
+    /* enable HXTAL */
+    RCU_CTL |= RCU_CTL_HXTALEN;
+
+    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+    }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+        while(1){
+        }
+    }
+
+    /* HXTAL is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_PREDIV0) * 6 = 24 MHz */
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL6);
+
+    if(HXTAL_VALUE==25000000){
+        /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL1EN;
+        /* wait till PLL1 is ready */
+        while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+        }
+
+    }else if(HXTAL_VALUE==8000000){
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+    }
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_36M_PLL_HXTAL)
+/*!
+    \brief      configure the system clock to 36M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_36m_hxtal(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+
+    /* enable HXTAL */
+    RCU_CTL |= RCU_CTL_HXTALEN;
+
+    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+    }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+        while(1){
+        }
+    }
+
+    /* HXTAL is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_PREDIV0) * 9 = 36 MHz */
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL9);
+
+    if(HXTAL_VALUE==25000000){
+        /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL1EN;
+        /* wait till PLL1 is ready */
+        while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+        }
+
+    }else if(HXTAL_VALUE==8000000){
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+    }
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
+/*!
+    \brief      configure the system clock to 48M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_48m_hxtal(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+
+    /* enable HXTAL */
+    RCU_CTL |= RCU_CTL_HXTALEN;
+
+    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+    }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+        while(1){
+        }
+    }
+
+    /* HXTAL is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_PREDIV0) * 12 = 48 MHz */
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL12);
+
+    if(HXTAL_VALUE==25000000){
+
+        /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL1EN;
+        /* wait till PLL1 is ready */
+        while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+        }
+
+    }else if(HXTAL_VALUE==8000000){
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+    }
+
+
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_56M_PLL_HXTAL)
+/*!
+    \brief      configure the system clock to 56M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_56m_hxtal(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+
+    /* enable HXTAL */
+    RCU_CTL |= RCU_CTL_HXTALEN;
+
+    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+    }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+        while(1){
+        }
+    }
+
+    /* HXTAL is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_PREDIV0) * 14 = 56 MHz */
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL14);
+
+    if(HXTAL_VALUE==25000000){
+
+        /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL1EN;
+        /* wait till PLL1 is ready */
+        while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+        }
+
+    }else if(HXTAL_VALUE==8000000){
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+    }
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
+/*!
+    \brief      configure the system clock to 72M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_72m_hxtal(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+
+    /* enable HXTAL */
+    RCU_CTL |= RCU_CTL_HXTALEN;
+
+    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+    }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+        while(1){
+        }
+    }
+
+    /* HXTAL is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_PREDIV0) * 18 = 72 MHz */ 
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL18);
+
+
+    if(HXTAL_VALUE==25000000){
+
+        /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL1EN;
+        /* wait till PLL1 is ready */
+        while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+        }
+
+    }else if(HXTAL_VALUE==8000000){
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+    }
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_96M_PLL_HXTAL)
+/*!
+    \brief      configure the system clock to 96M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_96m_hxtal(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+
+    /* enable HXTAL */
+    RCU_CTL |= RCU_CTL_HXTALEN;
+
+    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+    }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+        while(1){
+        }
+    }
+
+    /* HXTAL is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    if(HXTAL_VALUE==25000000){
+
+        /* CK_PLL = (CK_PREDIV0) * 24 = 96 MHz */
+        RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+        RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL24);
+
+        /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL1EN;
+        /* wait till PLL1 is ready */
+        while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+        }
+
+    }else if(HXTAL_VALUE==8000000){
+        /* CK_PLL = (CK_PREDIV0) * 24 = 96 MHz */
+        RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+        RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL24);
+
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+    }
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)
+/*!
+    \brief      configure the system clock to 108M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+
+static void system_clock_108m_hxtal(void)
+{
+    uint32_t timeout   = 0U;
+    uint32_t stab_flag = 0U;
+
+    /* enable HXTAL */
+    RCU_CTL |= RCU_CTL_HXTALEN;
+
+    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+    }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+        while(1){
+        }
+    }
+
+    /* HXTAL is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_PREDIV0) * 27 = 108 MHz */ 
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL27);
+
+    if(HXTAL_VALUE==25000000){
+        /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PREDV1_DIV5 | RCU_PLL1_MUL8 | RCU_PREDV0_DIV10);
+
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL1EN;
+        /* wait till PLL1 is ready */
+        while(0U == (RCU_CTL & RCU_CTL_PLL1STB)){
+        }
+
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL2EN;
+        /* wait till PLL1 is ready */
+        while(0U == (RCU_CTL & RCU_CTL_PLL2STB)){
+        }
+    }else if(HXTAL_VALUE==8000000){
+        RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+        RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 | RCU_PREDV1_DIV2 | RCU_PLL1_MUL20 | RCU_PLL2_MUL20);
+
+        /* enable PLL1 */
+        RCU_CTL |= RCU_CTL_PLL1EN;
+        /* wait till PLL1 is ready */
+        while(0U == (RCU_CTL & RCU_CTL_PLL1STB)){
+        }
+
+        /* enable PLL2 */
+        RCU_CTL |= RCU_CTL_PLL2EN;
+        /* wait till PLL1 is ready */
+        while(0U == (RCU_CTL & RCU_CTL_PLL2STB)){
+        }
+
+    }
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_48M_PLL_IRC8M)
+/*!
+    \brief      configure the system clock to 48M by PLL which selects IRC8M as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_48m_irc8m(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+    
+    /* enable IRC8M */
+    RCU_CTL |= RCU_CTL_IRC8MEN;
+
+    /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
+    }
+    while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){
+      while(1){
+      }
+    }
+
+    /* IRC8M is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_IRC8M/2) * 12 = 48 MHz */
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= RCU_PLL_MUL12;
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
+/*!
+    \brief      configure the system clock to 72M by PLL which selects IRC8M as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_72m_irc8m(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+    
+    /* enable IRC8M */
+    RCU_CTL |= RCU_CTL_IRC8MEN;
+
+    /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
+    }
+    while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){
+      while(1){
+      }
+    }
+
+    /* IRC8M is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_IRC8M/2) * 18 = 72 MHz */
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= RCU_PLL_MUL18;
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#elif defined (__SYSTEM_CLOCK_108M_PLL_IRC8M)
+/*!
+    \brief      configure the system clock to 108M by PLL which selects IRC8M as its clock source
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+static void system_clock_108m_irc8m(void)
+{
+    uint32_t timeout = 0U;
+    uint32_t stab_flag = 0U;
+    
+    /* enable IRC8M */
+    RCU_CTL |= RCU_CTL_IRC8MEN;
+
+    /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
+    do{
+        timeout++;
+        stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
+    }
+    while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
+
+    /* if fail */
+    if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){
+      while(1){
+      }
+    }
+
+    /* IRC8M is stable */
+    /* AHB = SYSCLK */
+    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+    /* APB2 = AHB/1 */
+    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+    /* APB1 = AHB/2 */
+    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+    /* CK_PLL = (CK_IRC8M/2) * 27 = 108 MHz */
+    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+    RCU_CFG0 |= RCU_PLL_MUL27;
+
+    /* enable PLL */
+    RCU_CTL |= RCU_CTL_PLLEN;
+
+    /* wait until PLL is stable */
+    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+    }
+
+    /* select PLL as system clock */
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+    /* wait until PLL is selected as system clock */
+    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+    }
+}
+
+#endif
+
+/**
+ * \defgroup  NMSIS_Core_IntExcNMI_Handling   Interrupt and Exception and NMI Handling
+ * \brief Functions for interrupt, exception and nmi handle available in system_.c.
+ * \details
+ * Nuclei provide a template for interrupt, exception and NMI handling. Silicon Vendor could adapat according
+ * to their requirement. Silicon vendor could implement interface for different exception code and
+ * replace current implementation.
+ *
+ * @{
+ */
+/** \brief Max exception handler number, don't include the NMI(0xFFF) one */
+#define MAX_SYSTEM_EXCEPTION_NUM        12
+/**
+ * \brief      Store the exception handlers for each exception ID
+ * \note
+ * - This SystemExceptionHandlers are used to store all the handlers for all
+ * the exception codes Nuclei N/NX core provided.
+ * - Exception code 0 - 11, totally 12 exceptions are mapped to SystemExceptionHandlers[0:11]
+ * - Exception for NMI is also re-routed to exception handling(exception code 0xFFF) in startup code configuration, the handler itself is mapped to SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM]
+ */
+static unsigned long SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM + 1];
+
+/**
+ * \brief      Exception Handler Function Typedef
+ * \note
+ * This typedef is only used internal in this system_gd32vf103.c file.
+ * It is used to do type conversion for registered exception handler before calling it.
+ */
+typedef void (*EXC_HANDLER)(unsigned long mcause, unsigned long sp);
+
+/**
+ * \brief      System Default Exception Handler
+ * \details
+ * This function provided a default exception and NMI handling code for all exception ids.
+ * By default, It will just print some information for debug, Vendor can customize it according to its requirements.
+ */
+static void system_default_exception_handler(unsigned long mcause, unsigned long sp)
+{
+    /* TODO: Uncomment this if you have implement printf function */
+    /*printf("MCAUSE: 0x%lx\r\n", mcause);
+    printf("MEPC  : 0x%lx\r\n", __RV_CSR_READ(CSR_MEPC));
+    printf("MTVAL : 0x%lx\r\n", __RV_CSR_READ(CSR_MBADADDR));*/
+    while (1);
+}
+
+/**
+ * \brief      Initialize all the default core exception handlers
+ * \details
+ * The core exception handler for each exception id will be initialized to \ref system_default_exception_handler.
+ * \note
+ * Called in \ref _init function, used to initialize default exception handlers for all exception IDs
+ */
+static void Exception_Init(void)
+{
+    for (int i = 0; i < MAX_SYSTEM_EXCEPTION_NUM + 1; i++) {
+        SystemExceptionHandlers[i] = (unsigned long)system_default_exception_handler;
+    }
+}
+
+/**
+ * \brief       Register an exception handler for exception code EXCn
+ * \details
+ * * For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will be registered into SystemExceptionHandlers[EXCn-1].
+ * * For EXCn == NMI_EXCn, it will be registered into SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM].
+ * \param   EXCn    See \ref EXCn_Type
+ * \param   exc_handler     The exception handler for this exception code EXCn
+ */
+void Exception_Register_EXC(uint32_t EXCn, unsigned long exc_handler)
+{
+    if ((EXCn < MAX_SYSTEM_EXCEPTION_NUM) && (EXCn != 0)) {
+        SystemExceptionHandlers[EXCn] = exc_handler;
+    } else if (EXCn == NMI_EXCn) {
+        SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM] = exc_handler;
+    }
+}
+
+/**
+ * \brief       Get current exception handler for exception code EXCn
+ * \details
+ * * For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will return SystemExceptionHandlers[EXCn-1].
+ * * For EXCn == NMI_EXCn, it will return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM].
+ * \param   EXCn    See \ref EXCn_Type
+ * \return  Current exception handler for exception code EXCn, if not found, return 0.
+ */
+unsigned long Exception_Get_EXC(uint32_t EXCn)
+{
+    if ((EXCn < MAX_SYSTEM_EXCEPTION_NUM) && (EXCn != 0)) {
+        return SystemExceptionHandlers[EXCn];
+    } else if (EXCn == NMI_EXCn) {
+        return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * \brief      Common NMI and Exception handler entry
+ * \details
+ * This function provided a command entry for NMI and exception. Silicon Vendor could modify
+ * this template implementation according to requirement.
+ * \remarks
+ * - RISCV provided common entry for all types of exception. This is proposed code template
+ *   for exception entry function, Silicon Vendor could modify the implementation.
+ * - For the core_exception_handler template, we provided exception register function \ref Exception_Register_EXC
+ *   which can help developer to register your exception handler for specific exception number.
+ */
+uint32_t core_exception_handler(unsigned long mcause, unsigned long sp)
+{
+    uint32_t EXCn = (uint32_t)(mcause & 0X00000fff);
+    EXC_HANDLER exc_handler;
+
+    if ((EXCn < MAX_SYSTEM_EXCEPTION_NUM) && (EXCn > 0)) {
+        exc_handler = (EXC_HANDLER)SystemExceptionHandlers[EXCn];
+    } else if (EXCn == NMI_EXCn) {
+        exc_handler = (EXC_HANDLER)SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
+    } else {
+        exc_handler = (EXC_HANDLER)system_default_exception_handler;
+    }
+    if (exc_handler != NULL) {
+        exc_handler(mcause, sp);
+    }
+    return 0;
+}
+/** @} */ /* End of Doxygen Group NMSIS_Core_ExceptionAndNMI */
+
+void SystemBannerPrint(void)
+{
+#if defined(NUCLEI_BANNER) && (NUCLEI_BANNER == 1)
+#ifndef DOWNLOAD_MODE
+#error DOWNLOAD_MODE is not defined via build system, please check!
+#endif
+    const char* download_modes[] = {"FLASHXIP", "FLASH", "ILM", "DDR"};
+    printf("Nuclei SDK Build Time: %s, %s\r\n", __DATE__, __TIME__);
+    printf("Download Mode: %s\r\n", download_modes[DOWNLOAD_MODE]);
+    printf("CPU Frequency %d Hz\r\n", SystemCoreClock);
+#endif
+}
+
+/**
+ * \brief initialize eclic config
+ * \details
+ * Eclic need initialize after boot up, Vendor could also change the initialization
+ * configuration.
+ */
+void ECLIC_Init(void)
+{
+    /* TODO: Add your own initialization code here. This function will be called by main */
+    ECLIC_SetMth(0);
+    ECLIC_SetCfgNlbits(__ECLIC_INTCTLBITS);
+}
+
+/**
+ * \brief  Initialize a specific IRQ and register the handler
+ * \details
+ * This function set vector mode, trigger mode and polarity, interrupt level and priority,
+ * assign handler for specific IRQn.
+ * \param [in]  IRQn        NMI interrupt handler address
+ * \param [in]  shv         \ref ECLIC_NON_VECTOR_INTERRUPT means non-vector mode, and \ref ECLIC_VECTOR_INTERRUPT is vector mode
+ * \param [in]  trig_mode   see \ref ECLIC_TRIGGER_Type
+ * \param [in]  lvl         interupt level
+ * \param [in]  priority    interrupt priority
+ * \param [in]  handler     interrupt handler, if NULL, handler will not be installed
+ * \return       -1 means invalid input parameter. 0 means successful.
+ * \remarks
+ * - This function use to configure specific eclic interrupt and register its interrupt handler and enable its interrupt.
+ * - If the vector table is placed in read-only section(FLASHXIP mode), handler could not be installed
+ */
+int32_t ECLIC_Register_IRQ(IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void* handler)
+{
+    if ((IRQn > SOC_INT_MAX) || (shv > ECLIC_VECTOR_INTERRUPT) \
+        || (trig_mode > ECLIC_NEGTIVE_EDGE_TRIGGER)) {
+        return -1;
+    }
+
+    /* set interrupt vector mode */
+    ECLIC_SetShvIRQ(IRQn, shv);
+    /* set interrupt trigger mode and polarity */
+    ECLIC_SetTrigIRQ(IRQn, trig_mode);
+    /* set interrupt level */
+    ECLIC_SetLevelIRQ(IRQn, lvl);
+    /* set interrupt priority */
+    ECLIC_SetPriorityIRQ(IRQn, priority);
+    if (handler != NULL) {
+        /* set interrupt handler entry to vector table */
+        ECLIC_SetVector(IRQn, (rv_csr_t)handler);
+    }
+    /* enable interrupt */
+    ECLIC_EnableIRQ(IRQn);
+    return 0;
+}
+/** @} */ /* End of Doxygen Group NMSIS_Core_ExceptionAndNMI */
+
+/**
+ * \brief early init function before main
+ * \details
+ * This function is executed right before main function.
+ * For RISC-V gnu toolchain, _init function might not be called
+ * by __libc_init_array function, so we defined a new function
+ * to do initialization
+ */
+void _premain_init(void)
+{
+    /* TODO: Add your own initialization code here, called before main */
+    //SystemCoreClock = get_cpu_freq();
+    /* configure USART */
+    /*gd_com_init(SOC_DEBUG_UART);*/
+    /* Display banner after UART initialized */
+    /*SystemBannerPrint();*/
+    /* Initialize exception default handlers */
+    Exception_Init();
+    /* ECLIC initialization, mainly MTH and NLBIT */
+    ECLIC_Init();
+}
+
+/**
+ * \brief finish function after main
+ * \param [in]  status     status code return from main
+ * \details
+ * This function is executed right after main function.
+ * For RISC-V gnu toolchain, _fini function might not be called
+ * by __libc_fini_array function, so we defined a new function
+ * to do initialization
+ */
+void _postmain_fini(int status)
+{
+    /* TODO: Add your own finishing code here, called after main */
+}
+
+/**
+ * \brief _init function called in __libc_init_array()
+ * \details
+ * This `__libc_init_array()` function is called during startup code,
+ * user need to implement this function, otherwise when link it will
+ * error init.c:(.text.__libc_init_array+0x26): undefined reference to `_init'
+ * \note
+ * Please use \ref _premain_init function now
+ */
+void _init(void)
+{
+    /* Don't put any code here, please use _premain_init now */
+}
+
+/**
+ * \brief _fini function called in __libc_fini_array()
+ * \details
+ * This `__libc_fini_array()` function is called when exit main.
+ * user need to implement this function, otherwise when link it will
+ * error fini.c:(.text.__libc_fini_array+0x28): undefined reference to `_fini'
+ * \note
+ * Please use \ref _postmain_fini function now
+ */
+void _fini(void)
+{
+    /* Don't put any code here, please use _postmain_fini now */
+}
+
+/** @} */ /* End of Doxygen Group NMSIS_Core_SystemAndClock */
diff --git a/hw/mcu/gd/nuclei-sdk b/hw/mcu/gd/nuclei-sdk
new file mode 160000
index 000000000..834e02fa7
--- /dev/null
+++ b/hw/mcu/gd/nuclei-sdk
@@ -0,0 +1 @@
+Subproject commit 834e02fa7fcc9bb1823cf517003296e01adaa7c7