#include "CH32V20xxx.h"
typedef __SIZE_TYPE__ size_t;
extern "C" {
  extern void handle_reset () __attribute__((naked,nothrow,used));
  extern void user_prog ()    __attribute__((used));
  extern int  main      ()    __attribute__((used));
  extern void SystemInit()    __attribute__((used));
  // This is required to allow pure virtual functions to be defined.
  extern void __cxa_pure_virtual() { while (1); }

  // These magic symbols are provided by the linker.
  extern uint32_t _sbss;
  extern uint32_t _ebss;
  extern uint32_t _data_lma;
  extern uint32_t _data_vma;
  extern uint32_t _edata;

  extern void (*__preinit_array_start[]) (void) __attribute__((weak));
  extern void (*__preinit_array_end[]) (void) __attribute__((weak));
  extern void (*__init_array_start[]) (void) __attribute__((weak));
  extern void (*__init_array_end[]) (void) __attribute__((weak));

  static void __init_array () {
      uint32_t * dst, * end;

      /* Zero fill the bss section */
      dst = &_sbss;
      end = &_ebss;
      while (dst < end) * dst++ = 0U;
      /* Copy data section from flash to RAM */
      uint32_t * src;
      src = &_data_lma;
      dst = &_data_vma;
      end = &_edata;
      if (src != dst) {
        while (dst < end) * dst++ = * src++;
      }
      
      size_t count;
      /* Pro Cortex-Mx bylo toto zbytečné, lze předpokládat, že je to tak i zde.
      count = __preinit_array_end - __preinit_array_start;
      for (unsigned i = 0; i < count; i++)  __preinit_array_start[i]();
      */
      count = __init_array_end - __init_array_start;
      for (unsigned i = 0; i < count; i++)  __init_array_start[i]();
  }
  // If you don't override a specific handler, it will just spin forever.
  void DefaultIRQHandler( void ) {
      // Infinite Loop
      for (;;);
  }
  void NMI_RCC_CSS_IRQHandler( void ) {
      RCC.INTR.B.CSSC = RESET;	// clear the clock security int flag
  }
  #define ALIAS(f) __attribute__((nothrow,weak,alias(#f),used))
  void Ecall_M_Mode_Handler( void )        ALIAS(DefaultIRQHandler);
  void Ecall_U_Mode_Handler( void )        ALIAS(DefaultIRQHandler);
  void Break_Point_Handler( void )         ALIAS(DefaultIRQHandler);

  void NMI_Handler( void )                 ALIAS(NMI_RCC_CSS_IRQHandler);
  void HardFault_Handler( void )           ALIAS(DefaultIRQHandler);
  void SysTick_Handler( void )             ALIAS(DefaultIRQHandler);
  void SW_Handler( void )                  ALIAS(DefaultIRQHandler);
  
  void WWDG_IRQHandler             (void) ALIAS(DefaultIRQHandler);
  void PVD_IRQHandler              (void) ALIAS(DefaultIRQHandler);
  void TAMPER_IRQHandler           (void) ALIAS(DefaultIRQHandler);
  void RTC_IRQHandler              (void) ALIAS(DefaultIRQHandler);
  void FLASH_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void RCC_IRQHandler              (void) ALIAS(DefaultIRQHandler);
  void EXTI0_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void EXTI1_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void EXTI2_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void EXTI3_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void EXTI4_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void DMA1_Channel1_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void DMA1_Channel2_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void DMA1_Channel3_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void DMA1_Channel4_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void DMA1_Channel5_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void DMA1_Channel6_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void DMA1_Channel7_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void DMA1_Channel8_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void ADC1_2_IRQHandler           (void) ALIAS(DefaultIRQHandler);
  void USB_HP_CAN1_TX_IRQHandler   (void) ALIAS(DefaultIRQHandler);
  void USB_LP_CAN1_RX0_IRQHandler  (void) ALIAS(DefaultIRQHandler);
  void CAN1_RX1_IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void CAN1_SCE_IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void EXTI9_5_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void TIM1_BRK_IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void TIM1_UP_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void TIM1_TRG_COM_IRQHandler     (void) ALIAS(DefaultIRQHandler);
  void TIM1_CC_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void TIM2_IRQHandler             (void) ALIAS(DefaultIRQHandler);
  void TIM3_IRQHandler             (void) ALIAS(DefaultIRQHandler);
  void TIM4_IRQHandler             (void) ALIAS(DefaultIRQHandler);
  void I2C1_EV_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void I2C1_ER_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void I2C2_EV_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void I2C2_ER_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void SPI1_IRQHandler             (void) ALIAS(DefaultIRQHandler);
  void SPI2_IRQHandler             (void) ALIAS(DefaultIRQHandler);
  void USART1_IRQHandler           (void) ALIAS(DefaultIRQHandler);
  void USART2_IRQHandler           (void) ALIAS(DefaultIRQHandler);
  void USART3_IRQHandler           (void) ALIAS(DefaultIRQHandler);
  void EXTI15_10_IRQHandler        (void) ALIAS(DefaultIRQHandler);
  void RTCAlarm_IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void USBWakeUp_IRQHandler        (void) ALIAS(DefaultIRQHandler);
  void TIM8_BRK_IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void TIM8_UP__IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void TIM8_TRG_COM_IRQHandler     (void) ALIAS(DefaultIRQHandler);
  void TIM8_CC_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void TIM5_IRQHandler             (void) ALIAS(DefaultIRQHandler);
  void SPI3_IRQHandler             (void) ALIAS(DefaultIRQHandler);
  void UART4_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void UART5_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void ETH_IRQHandler              (void) ALIAS(DefaultIRQHandler);
  void ETH_WKUP_IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void OTG_FS_IRQHandler           (void) ALIAS(DefaultIRQHandler);
  void USBHDWakeUp_IRQHandler      (void) ALIAS(DefaultIRQHandler);
  void USBHD_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void UART6_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void UART7_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void UART8_IRQHandler            (void) ALIAS(DefaultIRQHandler);
  void TIM9_BRK_IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void TIM9_UP__IRQHandler         (void) ALIAS(DefaultIRQHandler);
  void TIM9_TRG_COM_IRQHandler     (void) ALIAS(DefaultIRQHandler);
  void TIM9_CC_IRQHandler          (void) ALIAS(DefaultIRQHandler);
  void TIM10_BRK_IRQHandler        (void) ALIAS(DefaultIRQHandler);
  void TIM10_UP__IRQHandler        (void) ALIAS(DefaultIRQHandler);
  void TIM10_TRG_COM_IRQHandler    (void) ALIAS(DefaultIRQHandler);
  void TIM10_CC_IRQHandler         (void) ALIAS(DefaultIRQHandler);

  void ETHWakeUp_IRQHandler( void ) ALIAS(DefaultIRQHandler);
  void OSC32KCal_IRQHandler( void ) ALIAS(DefaultIRQHandler);
  void OSCWakeUp_IRQHandler( void ) ALIAS(DefaultIRQHandler);
  
  
  void Init()                    __attribute__((used,section(".init")));
  /*   Tohle je patrně nedomyšlené, sekce .vector není definována.
  void InterruptVector()         __attribute__((nothrow,naked,section(".vector"),weak,alias("InterruptVectorDefault")));
  void InterruptVectorDefault()  __attribute__((nothrow,naked,section(".vector")));
  */
  typedef void (*pHandler) (void);
  extern const pHandler InterruptVector [] __attribute__((section(".text.vector"),aligned(8)));
};
const pHandler InterruptVector [] = {
  Init,
  0,
  NMI_Handler,                /* NMI */
  HardFault_Handler,          /* Hard Fault */
  0,
  Ecall_M_Mode_Handler,       /* Ecall M Mode */
  0,0,
  Ecall_U_Mode_Handler,       /* Ecall U Mode */
  Break_Point_Handler,        /* Break Point */
  0,0,
  SysTick_Handler,           /* SysTick Handler */                
  0,
  SW_Handler,                /* SW Handler */                     
  0,
  /* External Interrupts */                                              
  WWDG_IRQHandler,            /* Window Watchdog */
  PVD_IRQHandler,             /* PVD through EXTI Line detect */
  TAMPER_IRQHandler,          /* TAMPER */
  RTC_IRQHandler,             /* RTC */
  FLASH_IRQHandler,           /* Flash */
  RCC_IRQHandler,             /* RCC */
  EXTI0_IRQHandler,           /* EXTI Line 0 */
  EXTI1_IRQHandler,           /* EXTI Line 1 */
  EXTI2_IRQHandler,           /* EXTI Line 2 */
  EXTI3_IRQHandler,           /* EXTI Line 3 */
  EXTI4_IRQHandler,           /* EXTI Line 4 */
  DMA1_Channel1_IRQHandler,   /* DMA1 Channel 1 */
  DMA1_Channel2_IRQHandler,   /* DMA1 Channel 2 */
  DMA1_Channel3_IRQHandler,   /* DMA1 Channel 3 */
  DMA1_Channel4_IRQHandler,   /* DMA1 Channel 4 */
  DMA1_Channel5_IRQHandler,   /* DMA1 Channel 5 */
  DMA1_Channel6_IRQHandler,   /* DMA1 Channel 6 */
  DMA1_Channel7_IRQHandler,   /* DMA1 Channel 7 */
  ADC1_2_IRQHandler,          /* ADC1_2 */

  USB_HP_CAN1_TX_IRQHandler,  /* USB HP and CAN1 TX */
  USB_LP_CAN1_RX0_IRQHandler, /* USB LP and CAN1RX0 */
  CAN1_RX1_IRQHandler,        /* CAN1 RX1 */
  CAN1_SCE_IRQHandler,        /* CAN1 SCE */

  EXTI9_5_IRQHandler,         /* EXTI Line 9..5 */
  TIM1_BRK_IRQHandler,        /* TIM1 Break */
  TIM1_UP_IRQHandler,         /* TIM1 Update */
  TIM1_TRG_COM_IRQHandler,    /* TIM1 Trigger and Commutation */
  TIM1_CC_IRQHandler,         /* TIM1 Capture Compare */
  TIM2_IRQHandler,            /* TIM2 */
  TIM3_IRQHandler,            /* TIM3 */
  TIM4_IRQHandler,            /* TIM4 */
  I2C1_EV_IRQHandler,         /* I2C1 Event */
  I2C1_ER_IRQHandler,         /* I2C1 Error */
  I2C2_EV_IRQHandler,         /* I2C2 Event */
  I2C2_ER_IRQHandler,         /* I2C2 Error */
  SPI1_IRQHandler,            /* SPI1 */
  SPI2_IRQHandler,            /* SPI2 */
  USART1_IRQHandler,          /* USART1 */
  USART2_IRQHandler,          /* USART2 */
  USART3_IRQHandler,          /* USART3 */
  EXTI15_10_IRQHandler,       /* EXTI Line 15..10 */
  RTCAlarm_IRQHandler,        /* RTC Alarm through EXTI Line */

  USBWakeUp_IRQHandler,       /* USB Wake up from suspend */
  USBHD_IRQHandler,           /* USBHD Break */

  USBHDWakeUp_IRQHandler,     /* USBHD Wake up from suspend */
  ETH_IRQHandler,             /* ETH global */
  ETHWakeUp_IRQHandler,       /* ETH Wake up */
  0,                          /* BLE BB */
  0,                          /* BLE LLE */
  TIM5_IRQHandler,            /* TIM5 */
  UART4_IRQHandler,           /* UART4 */
  DMA1_Channel8_IRQHandler,   /* DMA1 Channel8 */
  OSC32KCal_IRQHandler,       /* OSC32KCal */
  OSCWakeUp_IRQHandler,       /* OSC Wake Up */
    
};
#if 0
void InterruptVectorDefault() noexcept {
	asm volatile( R"---(
	.align	1
	.option norvc;
	.word   Init

	.word   0
	.word   NMI_Handler                /* NMI */
	.word   HardFault_Handler          /* Hard Fault */
	.word   0

	.word   Ecall_M_Mode_Handler       /* Ecall M Mode */
	.word   0
	.word   0
	.word   Ecall_U_Mode_Handler       /* Ecall U Mode */
	.word   Break_Point_Handler        /* Break Point */
	.word   0
	.word   0
	

	.word   SysTick_Handler           /* SysTick Handler */                
	.word   0
	.word   SW_Handler                /* SW Handler */                     
	.word   0
	/* External Interrupts */                                              
	.word   WWDG_IRQHandler            /* Window Watchdog */
	.word   PVD_IRQHandler             /* PVD through EXTI Line detect */
	.word   TAMPER_IRQHandler          /* TAMPER */
	.word   RTC_IRQHandler             /* RTC */
	.word   FLASH_IRQHandler           /* Flash */
	.word   RCC_IRQHandler             /* RCC */
	.word   EXTI0_IRQHandler           /* EXTI Line 0 */
	.word   EXTI1_IRQHandler           /* EXTI Line 1 */
	.word   EXTI2_IRQHandler           /* EXTI Line 2 */
	.word   EXTI3_IRQHandler           /* EXTI Line 3 */
	.word   EXTI4_IRQHandler           /* EXTI Line 4 */
	.word   DMA1_Channel1_IRQHandler   /* DMA1 Channel 1 */
	.word   DMA1_Channel2_IRQHandler   /* DMA1 Channel 2 */
	.word   DMA1_Channel3_IRQHandler   /* DMA1 Channel 3 */
	.word   DMA1_Channel4_IRQHandler   /* DMA1 Channel 4 */
	.word   DMA1_Channel5_IRQHandler   /* DMA1 Channel 5 */
	.word   DMA1_Channel6_IRQHandler   /* DMA1 Channel 6 */
	.word   DMA1_Channel7_IRQHandler   /* DMA1 Channel 7 */
	.word   ADC1_2_IRQHandler          /* ADC1_2 */
	
	.word   USB_HP_CAN1_TX_IRQHandler  /* USB HP and CAN1 TX */
	.word   USB_LP_CAN1_RX0_IRQHandler /* USB LP and CAN1RX0 */
	.word   CAN1_RX1_IRQHandler        /* CAN1 RX1 */
	.word   CAN1_SCE_IRQHandler        /* CAN1 SCE */
	
	.word   EXTI9_5_IRQHandler         /* EXTI Line 9..5 */
	.word   TIM1_BRK_IRQHandler        /* TIM1 Break */
	.word   TIM1_UP_IRQHandler         /* TIM1 Update */
	.word   TIM1_TRG_COM_IRQHandler    /* TIM1 Trigger and Commutation */
	.word   TIM1_CC_IRQHandler         /* TIM1 Capture Compare */
	.word   TIM2_IRQHandler            /* TIM2 */
	.word   TIM3_IRQHandler            /* TIM3 */
	.word   TIM4_IRQHandler            /* TIM4 */
	.word   I2C1_EV_IRQHandler         /* I2C1 Event */
	.word   I2C1_ER_IRQHandler         /* I2C1 Error */
	.word   I2C2_EV_IRQHandler         /* I2C2 Event */
	.word   I2C2_ER_IRQHandler         /* I2C2 Error */
	.word   SPI1_IRQHandler            /* SPI1 */
	.word   SPI2_IRQHandler            /* SPI2 */
	.word   USART1_IRQHandler          /* USART1 */
	.word   USART2_IRQHandler          /* USART2 */
	.word   USART3_IRQHandler          /* USART3 */
	.word   EXTI15_10_IRQHandler       /* EXTI Line 15..10 */
	.word   RTCAlarm_IRQHandler        /* RTC Alarm through EXTI Line */

	.word   USBWakeUp_IRQHandler       /* USB Wake up from suspend */
	.word   USBHD_IRQHandler           /* USBHD Break */

	.word   USBHDWakeUp_IRQHandler     /* USBHD Wake up from suspend */
	.word   ETH_IRQHandler             /* ETH global */
	.word   ETHWakeUp_IRQHandler       /* ETH Wake up */
	.word   0                          /* BLE BB */
	.word   0                          /* BLE LLE */
	.word   TIM5_IRQHandler            /* TIM5 */
	.word   UART4_IRQHandler           /* UART4 */
	.word   DMA1_Channel8_IRQHandler   /* DMA1 Channel8 */
	.word   OSC32KCal_IRQHandler       /* OSC32KCal */
	.word   OSCWakeUp_IRQHandler       /* OSC Wake Up */
	
)---");
}
#endif
void Init() {
  asm volatile( R"---(
    .align 1
_start:
  j handle_reset
  .rept 12
  .word 0x00000013
  .endr
  
  .word 0x00100073
)---");
}
void handle_reset() noexcept {
	asm volatile(R"---(
.option push
.option norelax
	la gp, __global_pointer$
.option pop
	la sp, _eusrstack
)---"
#if __GNUC__ > 10
".option arch, +zicsr\n"
#endif
// Setup the interrupt vector, processor status and INTSYSCR.
R"---(
    li t0, 0x1f
    csrw 0xbc0, t0
    
	/* Enabled nested and hardware stack */
	li t0, 0x88
	csrs mstatus, t0

	la t0, InterruptVector
	ori t0, t0, 3
	csrw mtvec, t0
   
    /* Takhle RISC-V přejde do uživatelského programu. */
	csrw mepc, %[user]
	mret
)---"
: : [user]"r"(user_prog)/*, "InterruptVector" (InterruptVector)*/
: "t0", "memory" );
}
void user_prog () {
  SystemInit  ();
  __init_array();
  main();
  for (;;);
}