/* SPDX-License-Identifier: MIT */
// This contains a copy of ch32v00x.h and core_riscv.h ch32v00x_conf.h and other misc functions See copyright explanation at the end of the file.

#ifndef __CH32FUN_H
#define __CH32FUN_H

#include "funconfig.h"

/*****************************************************************************
	CH32V003 BASICS

	1. Be sure to see configuration section below!

	2. Backend Initialization
		SystemInit();

	3. Arduino-like I/O
		funGpioInitAll();
		funPinMode( PA2, GPIO_CFGLR_OUT_10Mhz_PP );
		funDigitalWrite( PA2, FUN_HIGH );
		funDigitalWrite( PA2, FUN_LOW );
		funAnalogRead( 0 ); // Not Pin number, but rather analog number.

	4. Delays
		Delay_Us(n)
		Delay_Ms(n)
		DelaySysTick( uint32_t n );

	5. printf
		printf, _write may be semihosted, or printed to UART.

		poll_input, handle_debug_input may be used with semihsoting to accept input from host.

		For UART printf, on:
			CH32V003, Port D5, 115200 8n1
			CH32V203, Port A9, 115200 8n1

		Modifications can be made to SetupUart, or your own version as desired.

    6. ISR Control Routines
		__enable_irq();    // For global interrupt enable
		__disable_irq();   // For global interrupt disable
		__isenabled_irq(); // For seeing if interrupts are enabled.
		NVIC_EnableIRQ(IRQn_Type IRQn) // To enable a specific interrupt

	7. Hardware MMIO structs, i.e.
		SysTick->CNT = current system tick counter (can be Hclk or Hclk/8)
		TIM2->CH1CVR = direct control over a PWM output

    8. Default debug behavior, when semihosting:
        a. You get access to DidDebuggerAttach() - so you can see if a debugger has attached.
        b. WaitForDebuggerToAttach( int timeout_ms ) - if timeout_ms == 0, will wait for forever.
        c. printf will wait 120ms (configurable) to make sure it doesn't drop data.  Otherwise,
           printf will fast-path to exit after the first timeout. It will still do the string
           formatting, but will not wait on output. Timeout is configured with
           FUNCONF_DEBUGPRINTF_TIMEOUT.
        d. If you hard fault, it will wait indefinitely for a debugger to attach, once attached,
           will printf the fault cause, and the memory address of the fault. Space can be saved
           by setting FUNCONF_DEBUG_HARDFAULT to 0.
*/



/******************************************************************************
 * CH32V003 Fun Configs; please define any non-default options in funconfig.h *

#define FUNCONF_USE_PLL 1               // Use built-in 2x PLL 
#define FUNCONF_USE_HSI 1               // Use HSI Internal Oscillator
#define FUNCONF_USE_HSE 0               // Use External Oscillator
#define FUNCONF_HSITRIM 0x10            // Use factory calibration on HSI Trim.
#define FUNCONF_SYSTEM_CORE_CLOCK 48000000  // Computed Clock in Hz (Default only for 003, other chips have other defaults)
#define FUNCONF_HSE_BYPASS 0            // Use HSE Bypass feature (for oscillator input)
#define FUNCONF_USE_CLK_SEC	1			// Use clock security system, enabled by default
#define FUNCONF_USE_DEBUGPRINTF 1
#define FUNCONF_USE_UARTPRINTF  0
#define FUNCONF_NULL_PRINTF 0           // Have printf but direct it "nowhere"
#define FUNCONF_SYSTICK_USE_HCLK 0      // Should systick be at 48 MHz (1) or 6MHz (0) on an '003.  Typically set to 0 to divide HCLK by 8.
#define FUNCONF_TINYVECTOR 0            // If enabled, Does not allow normal interrupts.
#define FUNCONF_UART_PRINTF_BAUD 115200 // Only used if FUNCONF_USE_UARTPRINTF is set.
#define FUNCONF_DEBUGPRINTF_TIMEOUT 0x100000 // Arbitrary time units, this is around 200ms.
#define FUNCONF_ENABLE_HPE 1            // Enable hardware interrupt stack.  Very good on QingKeV4, i.e. x035, v10x, v20x, v30x, but questionable on 003. 
                                        // If you are using that, consider using INTERRUPT_DECORATOR as an attribute to your interrupt handlers.
#define FUNCONF_USE_5V_VDD 0            // Enable this if you plan to use your part at 5V - affects USB and PD configration on the x035.
#define FUNCONF_DEBUG_HARDFAULT    1    // Log fatal errors with "printf"
#define FUNCONF_ISR_IN_RAM 0            // Put the interrupt vector in RAM.
#define FUNCONF_SUPPORT_CONSTRUCTORS 0	// Call functions with __attribute__((constructor)) in SystemInit()
#define FUNCONF_ICACHE_EN 1				// Enables ICache on cores that support it, may require power-down + power up to work properly at flash time.
*/

// Sanity check for when porting old code.
#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x) || defined(CH32L103)  || defined(CH32H41x)
	#if defined(CH32V003)
		#error Cannot define CH32V003 and another arch.
	#endif
#endif

#if !defined(FUNCONF_USE_DEBUGPRINTF) && !defined(FUNCONF_USE_UARTPRINTF)
	#define FUNCONF_USE_DEBUGPRINTF 1
#endif

#if defined(FUNCONF_USE_UARTPRINTF) && FUNCONF_USE_UARTPRINTF && !defined(FUNCONF_UART_PRINTF_BAUD)
	#define FUNCONF_UART_PRINTF_BAUD 115200
#endif

#if defined(FUNCONF_USE_DEBUGPRINTF) && FUNCONF_USE_DEBUGPRINTF && !defined(FUNCONF_DEBUGPRINTF_TIMEOUT)
	#define FUNCONF_DEBUGPRINTF_TIMEOUT 0x100000
#endif

#if defined(FUNCONF_USE_HSI) && defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSI && FUNCONF_USE_HSE
       #error FUNCONF_USE_HSI and FUNCONF_USE_HSE cannot both be set
#endif

#if !defined( FUNCONF_USE_HSI ) && !defined( FUNCONF_USE_HSE )
	#define FUNCONF_USE_HSI 1 // Default to use HSI
	#define FUNCONF_USE_HSE 0
#endif

#if defined( CH32X03x ) && FUNCONF_USE_HSE
	#error No HSE in CH32X03x
#endif

#if !defined( FUNCONF_USE_PLL )
	#if defined( CH32X03x )
		#define FUNCONF_USE_PLL 0 // No PLL on X03x
	#else
		#define FUNCONF_USE_PLL 1 // Default to use PLL
	#endif
#endif

#if !defined( FUNCONF_DEBUG_HARDFAULT )
	#define FUNCONF_DEBUG_HARDFAULT 1
#endif

#if defined( CH32X03x ) && FUNCONF_USE_PLL
	#error No PLL on the X03x
#endif

#ifndef FUNCONF_ENABLE_HPE
	#define FUNCONF_ENABLE_HPE 0
#endif

#if FUNCONF_ENABLE_HPE == 1
	#define INTERRUPT_DECORATOR  __attribute__((interrupt("WCH-Interrupt-fast")))
#else
	#define INTERRUPT_DECORATOR  __attribute__((interrupt))
#endif


#if !defined( FUNCONF_USE_CLK_SEC )
	#define FUNCONF_USE_CLK_SEC  1// use clock security system by default
#endif

#ifndef HSE_VALUE
	#if defined(CH32V003)
		#define HSE_VALUE                 (24000000) // Value of the External oscillator in Hz, default
	#elif defined(CH32V10x)
		#define HSE_VALUE				  (8000000)
	#elif defined(CH32V20x) || defined(CH32L103)
		#if defined(CH32V20x_D8) || defined(CH32V20x_D8W)
		#define HSE_VALUE    			  (32000000)
		#else
		#define HSE_VALUE    			  (8000000)
		#endif
	#elif defined(CH32V30x)
		#define HSE_VALUE				  (8000000)
	#elif defined(CH57x) || defined(CH58x) || defined(CH59x)
		#define HSE_VALUE				  (32000000)
	#elif defined(CH32H41x)
		#define HSE_VALUE				  (25000000)
	#endif
#endif

// Value of the Internal oscillator in Hz, default.
#ifndef HSI_VALUE
	#if defined(CH32V003) || defined(CH32V00x)
		#define HSI_VALUE					(24000000)
	#elif defined(CH32X03x)
		#define HSI_VALUE					(48000000)
	#elif defined(CH32V10x)
		#define HSI_VALUE					(8000000)
	#elif defined(CH32V20x) || defined(CH32L103)
		#define HSI_VALUE					(8000000)
	#elif defined(CH32V30x)
		#define HSI_VALUE					(8000000)
	#elif defined(CH32H41x)
		#define HSI_VALUE					(25000000)
	#endif
#endif

#ifndef FUNCONF_HSITRIM
	#define FUNCONF_HSITRIM 0x10  // Default (Chip default)
#endif

#ifndef FUNCONF_USE_PLL
	#define FUNCONF_USE_PLL 1     // Default, Use PLL.
#endif

#if !defined( FUNCONF_PLL_MULTIPLIER )
	#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
		#if defined(CH32V10x)
			#define FUNCONF_PLL_MULTIPLIER 10	// Default: 8 * 10 = 80 MHz
		#elif defined(CH32L103)
			#define FUNCONF_PLL_MULTIPLIER 12   // Default: 8 * 12 = 96 MHz
												// Note: Can be overclocked to 144 MHz
		#elif defined(CH32V20x)
			#define FUNCONF_PLL_MULTIPLIER 18	// Default: 8 * 18 = 144 MHz
		#elif defined(CH32V30x)
			#define FUNCONF_PLL_MULTIPLIER 18	// Default: 8 * 18 = 144 MHz
		#elif defined(CH32H41x)
			#define FUNCONF_PLL_MULTIPLIER 16	// Default: 25 * 16 = 400 MHz
		#else // CH32V003
			#define FUNCONF_PLL_MULTIPLIER 2	// Default: 24 * 2 = 48 MHz
		#endif
	#else
		#define FUNCONF_PLL_MULTIPLIER 1
	#endif
#endif

#ifndef FUNCONF_SYSTEM_CORE_CLOCK
	#if defined(CH57x) || defined(CH58x) || defined(CH59x) // no PLL multiplier, but a divider from the 480 MHz clock
		#define FUNCONF_SYSTEM_CORE_CLOCK 60000000 // default in ch32fun.c using CLK_SOURCE_PLL_60MHz
		#if defined(CLK_SOURCE_CH5XX)
			#error Must define FUNCONF_SYSTEM_CORE_CLOCK too if CLK_SOURCE_CH5XX is defined
		#endif
	#elif defined(CH32H41x)
		#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
			#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
				#define FUNCONF_SYSTEM_CORE_CLOCK ((HSI_VALUE / 4)*(FUNCONF_PLL_MULTIPLIER))
			#elif defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
				#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE / 4)*(FUNCONF_PLL_MULTIPLIER))
			#endif
		#else
			#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
				#define FUNCONF_SYSTEM_CORE_CLOCK ((HSI_VALUE)*(FUNCONF_PLL_MULTIPLIER))
			#elif defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
				#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE)*(FUNCONF_PLL_MULTIPLIER))
			#endif
		#endif
	#elif defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
		#define FUNCONF_SYSTEM_CORE_CLOCK ((HSI_VALUE)*(FUNCONF_PLL_MULTIPLIER))
	#elif defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
		#if defined(CH32V20x_D8) || defined(CH32V20x_D8W)
			#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE/4)*(FUNCONF_PLL_MULTIPLIER))
		#else
			#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE)*(FUNCONF_PLL_MULTIPLIER))
		#endif
	#else
		#error Must define either FUNCONF_USE_HSI or FUNCONF_USE_HSE to be 1.
	#endif
#endif

#ifndef FUNCONF_USE_5V_VDD
	#define FUNCONF_USE_5V_VDD 0
#endif

#ifndef FUNCONF_ISR_IN_RAM
	#define FUNCONF_ISR_IN_RAM 0
#endif

#ifndef FUNCONF_ICACHE_EN
	#define FUNCONF_ICACHE_EN 1
#endif

// Default package for CH32V20x
#if defined(CH32V20x)
#if !defined(CH32V20x_D8W) && !defined(CH32V20x_D8) && !defined(CH32V20x_D6)
	#define CH32V20x_D6              /* CH32V203F6-CH32V203F8-CH32V203G6-CH32V203G8-CH32V203K6-CH32V203K8-CH32V203C6-CH32V203C8 */
	//#define CH32V20x_D8              /* CH32V203RBT6 */
	//#define CH32V20x_D8W             /* CH32V208 */
	#endif
#endif

// Default package for CH32V30x
#if defined(CH32V30x)
#if !defined(CH32V30x_D8) && !defined(CH32V30x_D8C)
	//#define CH32V30x_D8              /* CH32V303x */
	#define CH32V30x_D8C             /* CH32V307x-CH32V305x */
	#endif
#endif

/////////////////////////////////////////////////////////////////////////////////////////////////
// Legacy, for EVT, CMSIS

#define __MPU_PRESENT             0  /* Other CH32 devices does not provide an MPU */
#define __Vendor_SysTickConfig    0  /* Set to 1 if different SysTick Config is used */

#ifndef __ASSEMBLER__  // Things before this can be used in assembly.

#include <stdint.h>

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

#endif // __ASSEMBLER__
	
///////////////////////////////////////////////////////////////////////////////////////////////	
///////////////////////////////////////////////////////////////////////////////////////////////
// Code in this section was originally from __CORE_RISCV_H__

#ifndef __CORE_RISCV_H__
#define __CORE_RISCV_H__

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

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

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

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

#endif

#ifndef WEAK
#define WEAK __attribute__((weak))
#endif

#ifdef __cplusplus
 extern "C" {
#endif
	
#ifndef __ASSEMBLER__

/* Standard Peripheral Library old types (maintained for legacy purpose) */
typedef __I uint32_t vuc32;  /* Read Only */
typedef __I uint16_t vuc16;  /* Read Only */
typedef __I uint8_t vuc8;   /* Read Only */

typedef const uint32_t uc32;  /* Read Only */
typedef const uint16_t uc16;  /* Read Only */
typedef const uint8_t uc8;   /* Read Only */

typedef __I int32_t vsc32;  /* Read Only */
typedef __I int16_t vsc16;  /* Read Only */
typedef __I int8_t vsc8;   /* Read Only */

typedef const int32_t sc32;  /* Read Only */
typedef const int16_t sc16;  /* Read Only */
typedef const int8_t sc8;   /* Read Only */

typedef __IO uint32_t  vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t  vu8;

typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;

typedef __IO int32_t  vs32;
typedef __IO int16_t  vs16;
typedef __IO int8_t   vs8;

typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;

typedef __I uint64_t vuc64;  /* Read Only */
typedef const uint64_t uc64;  /* Read Only */
typedef __I int64_t vsc64;  /* Read Only */
typedef const int64_t sc64;  /* Read Only */
typedef __IO uint64_t  vu64;
typedef uint64_t  u64;
typedef __IO int64_t  vs64;
typedef int64_t  s64;

typedef enum {NoREADY = 0, READY = !NoREADY} ErrorStatus;

typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;

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

#define   RV_STATIC_INLINE  static  inline

#include <string.h> // for memcpy in ch5xx hw.h files
#endif // ifndef __ASSEMBLER__

#if FUNCONF_ISR_IN_RAM
	#define VECTOR_HANDLER_SECTION ".data.vector_handler"
	#define ISR_HANDLER_INITIAL_JUMP ".word 0x00000000\n"
#else
	#define VECTOR_HANDLER_SECTION ".text.vector_handler"
	#define ISR_HANDLER_INITIAL_JUMP "j handle_reset\n"
#endif

#ifdef CH32V003
	#include "ch32v003hw.h"
#elif defined( CH32V002 ) || defined( CH32V00x )
	#include "ch32x00xhw.h"
#elif defined( CH32X03x )
	#include "ch32x03xhw.h"
#elif defined( CH32X03x )
	#include "ch32x03xhw.h"
#elif defined( CH32V10x )
	#include "ch32v10xhw.h"
#elif defined( CH32L103 )
	#include "ch32l103hw.h"
#elif defined( CH32V20x )
	#include "ch32v20xhw.h"
#elif defined( CH32V30x )
	#include "ch32v30xhw.h"
#elif defined( CH57x ) || defined( CH58x ) || defined( CH59x )
	#include "ch5xxhw.h"
#elif defined( CH32H41x )
	#include "ch32h41xhw.h"
#endif

#if defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE )

#if __GNUC__ > 10
	#define ADD_ARCH_ZICSR ".option arch, +zicsr\n"
#else
	#define ADD_ARCH_ZICSR
#endif

#ifndef __ASSEMBLER__

// Enable Global Interrupt
RV_STATIC_INLINE void __enable_irq()
{
	uint32_t result; __ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mstatus": "=r"(result) );
	result |= 0x88;  __ASM volatile( ADD_ARCH_ZICSR "csrw mstatus, %0" : : "r" (result) );
}

// Disable Global Interrupt
RV_STATIC_INLINE void __disable_irq()
{
	uint32_t result; __ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mstatus": "=r"(result) );
	result &= ~0x88; __ASM volatile( ADD_ARCH_ZICSR "csrw mstatus, %0" : : "r" (result) );
}

// Is Global Interrupt enabled (1 = yes, 0 = no)
RV_STATIC_INLINE uint8_t __isenabled_irq(void)
{
    uint32_t result; __ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mstatus": "=r"(result) );
    return (result & 0x08) != 0u;
}

// Get stack pointer (returns the stack pointer)
RV_STATIC_INLINE uint32_t __get_cpu_sp(void)
{
	uint32_t result; __ASM volatile( ADD_ARCH_ZICSR "mv %0, sp" : "=r"(result));
	return result;
}

// nop
RV_STATIC_INLINE void __NOP()
{
	__ASM volatile( "nop" );
}

// Enable Interrupt (by interrupt number)
RV_STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
	NVIC->IENR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

// Disable Interrupt (by interrupt number)
RV_STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
{
	NVIC->IRER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

// Get Interrupt Enable State, (by number), 1 = Triggered 0 = Not triggered
RV_STATIC_INLINE uint32_t NVIC_GetStatusIRQ(IRQn_Type IRQn)
{
	return((uint32_t) ((NVIC->ISR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}

// Get Interrupt Pending State, (by number), 1 = Pending 0 = Not pending
RV_STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
	return((uint32_t) ((NVIC->IPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}

// "current number break hang"
RV_STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
	NVIC->IPSR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

// Clear Interrupt Pending
RV_STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
	NVIC->IPRR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

// Get Interrupt Active State (returns 1 if active)
RV_STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
{
	return((uint32_t)((NVIC->IACTR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}

// Set Interrupt Priority (priority: bit7: pre-emption priority, bit6: subpriority, bit[5-0]: reserved
RV_STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint8_t priority)
{
	NVIC->IPRIOR[(uint32_t)(IRQn)] = priority;
}

/*********************************************************************
 * SUSPEND ALL INTERRUPTS EXCEPT
 * The following 3 functions serve to suspend all interrupts, except for the one you momentarily need.
 * The purpose of this is to not disturb the one interrupt of interest and let it run unimpeded.
 * procedure:
 * 1. save the enabled IRQs: uint32_t IRQ_backup = NVIC_get_enabled_IRQs();
 * 2. disable all IRQs: NVIC_clear_all_IRQs_except(IRQ_of_interest);
 * 3. restore the previously enabled IRQs: NVIC_restore_IRQs(IRQ_backup);
 * 
 * bit layout of the IRQ backup
 * bit		0 | 1 | 2  |  3  | 4  |  5  | 6  .. 22 | 23 .. 28
 * IRQn		2 | 3 | 12 | res | 14 | res | 16 .. 31 | 32 .. 38
 * IRQn 2 and 3 aren't actually user-settable (see RM).
 * 
 * Specifying an invalid IRQn_to_keep like 0 will disable all interrupts.
 */

RV_STATIC_INLINE uint32_t NVIC_get_enabled_IRQs()
{
	return ( ((NVIC->ISR[0] >> 2) & 0b11) | ((NVIC->ISR[0] >> 12) << 2) | ((NVIC->ISR[1] & 0b1111111) << 23) );
}

RV_STATIC_INLINE void NVIC_clear_all_IRQs_except(uint8_t IRQn_to_keep)
{
	if (!(IRQn_to_keep >> 5)) {		// IRQn_to_keep < 32
		NVIC->IRER[0] = (~0) & (~(1 << IRQn_to_keep));
		NVIC->IRER[1] = (~0);
	}
	else {
		IRQn_to_keep = IRQn_to_keep >> 5;
		NVIC->IRER[0] = (~0);
		NVIC->IRER[1] = (~0) & (~(1 << IRQn_to_keep));
	}
}

RV_STATIC_INLINE void NVIC_restore_IRQs(uint32_t old_state)
{
	NVIC->IENR[0] = (old_state >> 2) << 12;
	NVIC->IENR[1] = old_state >> 23;
}

// WFI - wait for interrupt (like a light sleep)
__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFI(void)
{
	NVIC->SCTLR &= ~(1<<3);   // wfi
	__ASM volatile ("wfi");
}

// WFE - wait for events (more like a deeper sleep)
__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFE(void)
{
  uint32_t t;

  t = NVIC->SCTLR;
  NVIC->SCTLR |= (1<<3)|(1<<5);     // (wfi->wfe)+(__sev)
  NVIC->SCTLR = (NVIC->SCTLR & ~(1<<5)) | ( t & (1<<5));
  __ASM volatile ("wfi");
  __ASM volatile ("wfi");
}

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

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

// Initiate a system reset request
RV_STATIC_INLINE void NVIC_SystemReset(void)
{
	NVIC->CFGR = NVIC_KEY3|(1<<7);
}

// For reading INTSYSCR, for interrupt nesting + hardware stack enable.
static inline uint32_t __get_INTSYSCR(void)
{
	uint32_t result;
	__ASM volatile(	ADD_ARCH_ZICSR "csrr %0, 0x804": "=r"(result));
	return result;
}

// For setting INTSYSCR, for interrupt nesting + hardware stack enable.
static inline void __set_INTSYSCR( uint32_t value )
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw 0x804, %0" : : "r"(value));
}

#if defined(CH32V30x)

// Return the Floating-Point Accrued Exceptions
static inline uint32_t __get_FFLAGS(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "fflags" : "=r" (result) );
	return (result);
}

// Set the Floating-Point Accrued Exceptions
static inline void __set_FFLAGS(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw fflags, %0" : : "r" (value) );
}

// Return the Floating-Point Dynamic Rounding Mode
static inline uint32_t __get_FRM(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "frm" : "=r" (result) );
	return (result);
}

// Set the Floating-Point Dynamic Rounding Mode
static inline void __set_FRM(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw frm, %0" : : "r" (value) );
}

// Return the Floating-Point Control and Status Register
static inline uint32_t __get_FCSR(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "fcsr" : "=r" (result) );
	return (result);
}

// Set the Floating-Point Dynamic Rounding Mode
static inline void __set_FCSR(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw fcsr, %0" : : "r" (value) );
}

#endif // CH32V30x

// Return the Machine Status Register (MSTATUS)
static inline uint32_t __get_MSTATUS(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0, mstatus": "=r"(result) );
	return (result);
}

// Set the Machine Status Register (MSTATUS)
static inline void __set_MSTATUS(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw mstatus, %0" : : "r"(value) );
}

// Return the Machine ISA Register (MISA)
static inline uint32_t __get_MISA(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0, misa" : "=r"(result));
	return (result);
}

// Set the Machine ISA Register (MISA)
static inline void __set_MISA(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw misa, %0" : : "r"(value));
}

// Return the Machine Trap-Vector Base-Address Register (MTVEC)
static inline uint32_t __get_MTVEC(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mtvec": "=r"(result));
	return (result);
}

//  * @brief   Set the Machine Trap-Vector Base-Address Register (MTVEC)
static inline void __set_MTVEC(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw mtvec, %0":: "r"(value));
}

// Return the Machine Seratch Register (MSCRATCH)
static inline uint32_t __get_MSCRATCH(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mscratch" : "=r"(result));
	return (result);
}

// Set the Machine Seratch Register (MSRATCH)
static inline void __set_MSCRATCH(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw mscratch, %0" : : "r"(value));
}

// Return the Machine Exception Program Register (MEPC)
static inline uint32_t __get_MEPC(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mepc" : "=r"(result));
	return (result);
}

// Set the Machine Exception Program Register (MEPC)
static inline void __set_MEPC(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw mepc, %0" : : "r"(value));
}

// Return the Machine Cause Register (MCAUSE)
static inline uint32_t __get_MCAUSE(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mcause": "=r"(result));
	return (result);
}

// Set the Machine Cause Register (MCAUSE)
static inline void __set_MCAUSE(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw mcause, %0":: "r"(value));
}

// Return the Machine Trap Value Register (MTVAL)
static inline uint32_t __get_MTVAL(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mtval" : "=r" (result) );
	return (result);
}

// Set the Machine Trap Value Register (MTVAL)
static inline void __set_MTVAL(uint32_t value)
{
	__ASM volatile ( ADD_ARCH_ZICSR "csrw mtval, %0" : : "r" (value) );
}

// Return Vendor ID Register (MVENDORID)
static inline uint32_t __get_MVENDORID(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0, mvendorid": "=r"(result));
	return (result);
}

// Return Machine Architecture ID Register (MARCHID)
static inline uint32_t __get_MARCHID(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0, marchid": "=r"(result));
	return (result);
}

// Return Machine Implementation ID Register (MIPID)
static inline uint32_t __get_MIMPID(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0, mimpid": "=r"(result));
	return (result);
}

// Return Hart ID Register MHARTID
static inline uint32_t __get_MHARTID(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0, mhartid": "=r"(result));
	return (result);
}

// Return stack pointer register (SP)
static inline uint32_t __get_SP(void)
{
	uint32_t result;
	__ASM volatile( "mv %0,""sp": "=r"(result):);
	return (result);
}

#if defined(CH32V003) && CH32V003

// Return DBGMCU_CR Register value
static inline uint32_t __get_DEBUG_CR(void)
{
	uint32_t result;
	__ASM volatile( ADD_ARCH_ZICSR "csrr %0, 0x7C0" : "=r" (result) );
	return (result);
}


// Set the DBGMCU_CR Register value
static inline void __set_DEBUG_CR(uint32_t value)
{
	__ASM volatile( ADD_ARCH_ZICSR "csrw 0x7C0, %0" : : "r" (value) );
}

#endif // CH32V003

#endif // !assembler

// _JBTYPE using long long to make sure the alignment is align to 8 byte,
// otherwise in rv32imafd, store/restore FPR may mis-align.
#define _JBTYPE long long
#if defined( __riscv_abi_rve )
#define _JBLEN ((4*sizeof(long))/sizeof(long))
#elif defined( __riscv_float_abi_double )
#define _JBLEN ((14*sizeof(long) + 12*sizeof(double))/sizeof(long))
#elif defined( __riscv_float_abi_single )
#define _JBLEN ((14*sizeof(long) + 12*sizeof(float))/sizeof(long))
#else
#define _JBLEN ((14*sizeof(long))/sizeof(long))
#endif

#ifndef __ASSEMBLER__
#ifdef _JBLEN
#ifdef _JBTYPE
typedef _JBTYPE jmp_buf[_JBLEN];
#else
typedef int jmp_buf[_JBLEN];
#endif // _JBTYPE
#endif // _JBLEN

int setjmp( jmp_buf env );
void longjmp( jmp_buf env, int val );
#endif

#endif // defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE )

#ifdef __cplusplus
}
#endif

#endif/* __CORE_RISCV_H__ */


///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
extern "C" {
#endif

/* SYSTICK info
 * time on the ch32v003 is kept by the SysTick counter (32bit)
 * by default, it will operate at (FUNCONF_SYSTEM_CORE_CLOCK / 8) = 6MHz
 * more info at https://github.com/cnlohr/ch32v003fun/wiki/Time
*/

#if defined( FUNCONF_SYSTICK_USE_HCLK ) && FUNCONF_SYSTICK_USE_HCLK && !defined(CH32V10x)
#define DELAY_US_TIME ((FUNCONF_SYSTEM_CORE_CLOCK)/1000000)
#define DELAY_MS_TIME ((FUNCONF_SYSTEM_CORE_CLOCK)/1000)
#else // Use systick = hclk/8
#define DELAY_US_TIME ((FUNCONF_SYSTEM_CORE_CLOCK)/8000000)
#define DELAY_MS_TIME ((FUNCONF_SYSTEM_CORE_CLOCK)/8000)
#endif

#define DELAY_MSEC_COUNT(n) (DELAY_MS_TIME * n)
#define DELAY_SEC_COUNT(n) (DELAY_MS_TIME * 1000 * n)

#define Delay_Us(n) DelaySysTick( (n) * DELAY_US_TIME )
#define Delay_Ms(n) DelaySysTick( (n) * DELAY_MS_TIME )

#define Ticks_from_Us(n)	((n) * DELAY_US_TIME)
#define Ticks_from_Ms(n)	((n) * DELAY_MS_TIME)

#define TimeElapsed32(now,start)  ((uint32_t)((uint32_t)(now)-(uint32_t)(start)))

// Add a certain number of nops.  Note: These are usually executed in pairs
// and take two cycles, so you typically would use 0, 2, 4, etc.
#define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );

#define FUN_HIGH 0x1
#define FUN_LOW 0x0
#if defined(CH57x) || defined(CH58x) || defined(CH59x)
#if defined( PB ) && defined( R32_PB_PIN )
#define OFFSET_FOR_GPIOB(pin)         (((pin & PB) >> 31) * (&R32_PB_PIN - &R32_PA_PIN)) // 0 if GPIOA, 0x20 if GPIOB
#else
#define PB                            0
#define OFFSET_FOR_GPIOB(pin)         0
#endif
#define GPIO_ResetBits(pin)           (*(&R32_PA_CLR + OFFSET_FOR_GPIOB(pin)) =  (pin & ~PB))
#define GPIO_SetBits(pin)             (*(&R32_PA_SET + OFFSET_FOR_GPIOB(pin)) =  (pin & ~PB))
#define GPIO_InverseBits(pin)         (*(&R32_PA_OUT + OFFSET_FOR_GPIOB(pin)) ^= (pin & ~PB))
#define GPIO_ReadPortPin(pin)         (*(&R32_PA_PIN + OFFSET_FOR_GPIOB(pin)) &  (pin & ~PB))
#define funDigitalRead(pin)           GPIO_ReadPortPin(pin)
#define funDigitalWrite( pin, value ) do{ if((value)==FUN_HIGH){GPIO_SetBits(pin);} else if((value)==FUN_LOW){GPIO_ResetBits(pin);} }while(0)
#define funGpioInitAll()              // funGpioInitAll() does not do anything on ch5xx, put here for consistency

RV_STATIC_INLINE void funPinMode(u32 pin, GPIOModeTypeDef mode)
{
	switch(mode) {
	case GPIO_ModeIN_Floating:
		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
		*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin))     &= ~(pin & ~PB);
		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    &= ~(pin & ~PB);
		break;
	case GPIO_ModeIN_PU:
		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
		*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin))     |= (pin & ~PB);
		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    &= ~(pin & ~PB);
		break;
	case GPIO_ModeIN_PD:
		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
		*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin))     &= ~(pin & ~PB);
		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    &= ~(pin & ~PB);
		break;
	case GPIO_ModeOut_PP_5mA:
		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    |= (pin & ~PB);
		break;
	case GPIO_ModeOut_PP_20mA:
		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    |= (pin & ~PB);
		break;
	}
}
#else
// Arduino-like GPIO Functionality
#define GpioOf( pin ) ((GPIO_TypeDef *)(GPIOA_BASE + 0x400 * ((pin)>>4)))

#define FUN_OUTPUT (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)
#define FUN_INPUT (GPIO_CNF_IN_FLOATING)

// For pins, use things like PA8, PB15
// For configuration, use things like GPIO_CFGLR_OUT_10Mhz_PP

#define funDigitalWrite( pin, value ) do{ GpioOf( pin )->BSHR = 1<<((!(value))*16 + ((pin) & 0xf)); }while(0)

#if defined(CH32X03x)
#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC ); }
#define funPinMode( pin, mode ) { *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); }
#elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32L103)
#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD ); }
#define funPinMode( pin, mode ) { *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); }
#define funGpioInitB() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB ); }
#elif defined(CH32H41x)
#define funGpioInitAll() { RCC->HB2PCENR |= ( RCC_HB2Periph_AFIO | RCC_HB2Periph_GPIOA | RCC_HB2Periph_GPIOB | RCC_HB2Periph_GPIOC | RCC_HB2Periph_GPIOD | RCC_HB2Periph_GPIOE | RCC_HB2Periph_GPIOF ); }

RV_STATIC_INLINE void funPinMode(u32 pin, GPIOMode_TypeDef mode, GPIOSpeed_TypeDef speed)
{
	*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7)));
	GpioOf(pin)->SPEED = (GpioOf(pin)->SPEED & ~(0x3 << (2 * (pin & 0xF)))) | (speed << (2 * (pin & 0xF)));
}

/* Helper for AF */
RV_STATIC_INLINE void funPinAF(u32 pin, u32 af)
{
	volatile uint32_t* afio = (uint32_t*)(AFIO_BASE + 4U + 4U * (pin >> 3));
	*afio = (*afio & ~(0xf << (4U * (pin & 0x7)))) | (af << (4U * (pin & 0x7)));
}

#else
#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD ); }
#define funPinMode( pin, mode ) { GpioOf(pin)->CFGLR = (GpioOf(pin)->CFGLR & (~(0xf<<(4*((pin)&0xf))))) | ((mode)<<(4*((pin)&0xf))); }
#endif

#define funGpioInitA() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA ); }
#define funGpioInitC() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC ); }
#define funGpioInitD() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD ); }
#define funDigitalRead( pin ) ((int)((GpioOf(pin)->INDR >> ((pin)&0xf)) & 1))
#endif


#define ANALOG_0 0
#define ANALOG_1 1
#define ANALOG_2 2
#define ANALOG_3 3
#define ANALOG_4 4
#define ANALOG_5 5
#define ANALOG_6 6
#define ANALOG_7 7
#define ANALOG_8 8
#define ANALOG_9 9
#define ANALOG_10 10
#define ANALOG_11 11

#ifndef __ASSEMBLER__

#if defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE )


// Stuff that can only be compiled on device (not for the programmer, or other host programs)

// Initialize the ADC calibrate it and set some sane defaults.
void funAnalogInit( void );

// Read an analog input (not a GPIO pin number)
// Be sure to call funAnalogInit first.
int funAnalogRead( int nAnalogNumber );

void handle_reset()            __attribute__((naked)) __attribute((section(".text.handle_reset"))) __attribute__((used));
void DefaultIRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute__((naked)) __attribute__((used));
// used to clear the CSS flag in case of clock fail switch
#if defined(FUNCONF_USE_CLK_SEC) && FUNCONF_USE_CLK_SEC
	void NMI_RCC_CSS_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute__((naked)) __attribute__((used));
#endif

void DelaySysTick( uint32_t n );


// Depending on a LOT of factors, it's about 6 cycles per n.
// **DO NOT send it zero or less.**
#ifndef __MACOSX__
#ifndef __DELAY_TINY_DEFINED__
#define __DELAY_TINY_DEFINED__
static inline void Delay_Tiny( int n ) {
	__ASM volatile( "\
		mv a5, %[n]\n\
		1: \
		c.addi a5, -1\n\
		c.bnez a5, 1b" : : [n]"r"(n) : "a5" );
}
#endif
#endif
#endif //defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE )

// Tricky: We need to make sure main and SystemInit() are preserved.
#ifdef MINICHLINK
int main( int argc, char ** argv) __attribute__((used));
#else
int main() __attribute__((used));
#endif
void SystemInit(void);

#ifdef FUNCONF_UART_PRINTF_BAUD
	#define UART_BAUD_RATE FUNCONF_UART_PRINTF_BAUD
#else
	#define UART_BAUD_RATE 115200
#endif
// Debug UART baud rate register calculation. Works assuming HCLK prescaler is off.
// Computes UART_BRR = CORE_CLOCK / BAUD_RATE with rounding to closest integer
#define UART_BRR (((FUNCONF_SYSTEM_CORE_CLOCK) + (UART_BAUD_RATE)/2) / (UART_BAUD_RATE))
// Put an output debug UART on Pin D5.
// You can write to this with printf(...) or puts(...)

void SetupUART( int uartBRR );

// Returns 1 if timeout reached, 0 otherwise.
// If timeout_ms == 0, wait indefinitely.
// Use DidDebuggerAttach() For a zero-wait way of seeing if it attached.
int WaitForDebuggerToAttach( int timeout_ms );

// Returns 1 if a debugger has activated the debug module.
#define DidDebuggerAttach() (!*DMSTATUS_SENTINEL)

// Returns 1 if a debugger has activated the debug module.
#define DebugPrintfBufferFree() (!(*DMDATA0 & 0x80))

// Just a definition to the internal _write function.
int _write(int fd, const char *buf, int size);

// Print a hexadecimal value to the debug (or UART) depending on configuration.
void PrintHex( uint32_t n );

// Call this to busy-wait the polling of input.
void poll_input( void );

// Receiving bytes from host.  Override if you wish.
void handle_debug_input( int numbytes, uint8_t * data );

// Call functions with __attribute__((constructor)). Defining FUNCONF_SUPPORT_CONSTRUCTORS 1 will do it for you
void CallConstructors( void );

// Functions from ch32fun.c
#include <stdarg.h>

int mini_vsnprintf( char *buffer, unsigned int buffer_len, const char *fmt, va_list va );
int mini_vpprintf( int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va );
int mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...);
int mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...);
int mini_itoa(long value, unsigned int radix, int uppercase, int unsig,	char *buffer);

#endif // __ASSEMBLER__


/*
 * This file contains various parts of the official WCH EVT Headers which
 * were originally under a restrictive license.
 * 
 * The collection of this file was generated by 
 * cnlohr, 2023-02-18 and
 * AlexanderMandera, 2023-06-23
 * It was significantly reworked into several files cnlohr, 2025-01-29
 *
 * While originally under a restrictive copyright, WCH has approved use
 * under MIT-licensed use, because of inclusion in Zephyr, as well as other
 * open-source licensed projects.
 *
 * These copies of the headers from WCH are available now under:
 *
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * 
 * 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.
 */

#ifdef __cplusplus
};
#endif


#endif // __CH32FUN_H

