From 6f7cf059ec2ab2b424f07a49d73f38f2dca46354 Mon Sep 17 00:00:00 2001 From: Zhao_Jiasheng <18535861947@163.com> Date: Mon, 10 May 2021 21:08:25 +0800 Subject: [PATCH] Add board k210-emulator --- Makefile | 2 +- arch/risc-v/k210/boot.S | 2 + arch/risc-v/k210/tick.c | 7 +- board/k210-emulator/.defconfig | 238 + board/k210-emulator/Kconfig | 81 + board/k210-emulator/Makefile | 6 + board/k210-emulator/README.md | 164 + board/k210-emulator/board.c | 207 + board/k210-emulator/board.h | 91 + board/k210-emulator/config.mk | 17 + board/k210-emulator/img/menuconfig1.png | Bin 0 -> 64346 bytes board/k210-emulator/img/menuconfig2.png | Bin 0 -> 84936 bytes board/k210-emulator/img/menuconfig3.png | Bin 0 -> 25012 bytes board/k210-emulator/img/menuconfig4.png | Bin 0 -> 161994 bytes board/k210-emulator/img/terminal.png | Bin 0 -> 42816 bytes board/k210-emulator/img/vscode.jpg | Bin 0 -> 57472 bytes board/k210-emulator/include/atomic.h | 253 + board/k210-emulator/include/bsp.h | 31 + board/k210-emulator/include/dump.h | 150 + board/k210-emulator/include/encoding.h | 1336 ++++ board/k210-emulator/include/entry.h | 90 + board/k210-emulator/include/interrupt.h | 56 + board/k210-emulator/include/platform.h | 108 + board/k210-emulator/include/printf.h | 218 + board/k210-emulator/include/sleep.h | 45 + board/k210-emulator/include/syscalls.h | 54 + board/k210-emulator/include/syslog.h | 151 + board/k210-emulator/include/util.h | 207 + board/k210-emulator/link.lds | 118 + board/k210-emulator/link_userspace.lds | 70 + .../k210-emulator/third_party_driver/Kconfig | 45 + .../k210-emulator/third_party_driver/Makefile | 35 + .../third_party_driver/dma/Kconfig | 1 + .../third_party_driver/dma/Makefile | 6 + .../third_party_driver/dma/dmac.c | 802 +++ .../third_party_driver/gpio/Kconfig | 11 + .../third_party_driver/gpio/Makefile | 8 + .../third_party_driver/gpio/connect_gpio.c | 331 + .../third_party_driver/gpio/drv_io_config.c | 160 + .../third_party_driver/gpio/fpioa.c | 5439 +++++++++++++++++ .../third_party_driver/gpio/gpio.c | 89 + .../third_party_driver/gpio/gpiohs.c | 228 + .../third_party_driver/gpio/utils.c | 54 + .../third_party_driver/i2c/Kconfig | 17 + .../third_party_driver/i2c/Makefile | 6 + .../third_party_driver/i2c/connect_i2c.c | 596 ++ .../third_party_driver/i2c/hardware_i2c.c | 371 ++ .../third_party_driver/include/clint.h | 323 + .../third_party_driver/include/connect_gpio.h | 36 + .../include/connect_hwtimer.h | 37 + .../third_party_driver/include/connect_i2c.h | 36 + .../third_party_driver/include/connect_rtc.h | 36 + .../third_party_driver/include/connect_spi.h | 36 + .../third_party_driver/include/connect_uart.h | 40 + .../third_party_driver/include/connect_wdt.h | 36 + .../third_party_driver/include/dmac.h | 1552 +++++ .../include/drv_io_config.h | 55 + .../third_party_driver/include/dvp.h | 279 + .../third_party_driver/include/font.h | 425 ++ .../third_party_driver/include/fpioa.h | 1014 +++ .../third_party_driver/include/gpio.h | 178 + .../third_party_driver/include/gpio_common.h | 61 + .../third_party_driver/include/gpiohs.h | 277 + .../include/hardware_hwtimer.h | 171 + .../third_party_driver/include/hardware_i2c.h | 482 ++ .../third_party_driver/include/hardware_rtc.h | 443 ++ .../third_party_driver/include/hardware_spi.h | 494 ++ .../include/hardware_uart.h | 364 ++ .../include/hardware_uarths.h | 302 + .../third_party_driver/include/io.h | 60 + .../third_party_driver/include/plic.h | 467 ++ .../third_party_driver/include/sysctl.h | 1088 ++++ .../third_party_driver/include/utils.h | 357 ++ .../third_party_driver/include/wdt.h | 180 + .../third_party_driver/plic/Kconfig | 1 + .../third_party_driver/plic/Makefile | 5 + .../third_party_driver/plic/clint.c | 229 + .../third_party_driver/plic/drv_interrupt.c | 41 + .../third_party_driver/plic/plic.c | 219 + .../third_party_driver/rtc/Kconfig | 11 + .../third_party_driver/rtc/Makefile | 3 + .../third_party_driver/rtc/connect_rtc.c | 184 + .../third_party_driver/rtc/hardware_rtc.c | 597 ++ .../k210-emulator/third_party_driver/sleep.c | 49 + .../third_party_driver/spi/Kconfig | 67 + .../third_party_driver/spi/Makefile | 6 + .../third_party_driver/spi/connect_spi.c | 472 ++ .../third_party_driver/spi/hardware_spi.c | 1523 +++++ .../third_party_driver/sys_clock/Kconfig | 1 + .../third_party_driver/sys_clock/Makefile | 6 + .../third_party_driver/sys_clock/sysctl.c | 1870 ++++++ .../third_party_driver/timer/Kconfig | 19 + .../third_party_driver/timer/Makefile | 3 + .../timer/connect_hwtimer.c | 155 + .../timer/hardware_hwtimer.c | 406 ++ .../third_party_driver/uart/Kconfig | 77 + .../third_party_driver/uart/Makefile | 3 + .../third_party_driver/uart/connect_uart.c | 653 ++ .../third_party_driver/uart/hardware_uart.c | 424 ++ .../third_party_driver/uart/hardware_uarths.c | 184 + .../third_party_driver/watchdog/Kconfig | 34 + .../third_party_driver/watchdog/Makefile | 4 + .../third_party_driver/watchdog/connect_wdt.c | 172 + .../third_party_driver/watchdog/wdt.c | 125 + kernel/thread/init.c | 1 - path_kernel.mk | 13 + 106 files changed, 28284 insertions(+), 3 deletions(-) create mode 100644 board/k210-emulator/.defconfig create mode 100644 board/k210-emulator/Kconfig create mode 100644 board/k210-emulator/Makefile create mode 100644 board/k210-emulator/README.md create mode 100644 board/k210-emulator/board.c create mode 100644 board/k210-emulator/board.h create mode 100644 board/k210-emulator/config.mk create mode 100644 board/k210-emulator/img/menuconfig1.png create mode 100644 board/k210-emulator/img/menuconfig2.png create mode 100644 board/k210-emulator/img/menuconfig3.png create mode 100644 board/k210-emulator/img/menuconfig4.png create mode 100644 board/k210-emulator/img/terminal.png create mode 100644 board/k210-emulator/img/vscode.jpg create mode 100644 board/k210-emulator/include/atomic.h create mode 100644 board/k210-emulator/include/bsp.h create mode 100644 board/k210-emulator/include/dump.h create mode 100644 board/k210-emulator/include/encoding.h create mode 100644 board/k210-emulator/include/entry.h create mode 100644 board/k210-emulator/include/interrupt.h create mode 100644 board/k210-emulator/include/platform.h create mode 100644 board/k210-emulator/include/printf.h create mode 100644 board/k210-emulator/include/sleep.h create mode 100644 board/k210-emulator/include/syscalls.h create mode 100644 board/k210-emulator/include/syslog.h create mode 100644 board/k210-emulator/include/util.h create mode 100644 board/k210-emulator/link.lds create mode 100644 board/k210-emulator/link_userspace.lds create mode 100755 board/k210-emulator/third_party_driver/Kconfig create mode 100644 board/k210-emulator/third_party_driver/Makefile create mode 100644 board/k210-emulator/third_party_driver/dma/Kconfig create mode 100644 board/k210-emulator/third_party_driver/dma/Makefile create mode 100644 board/k210-emulator/third_party_driver/dma/dmac.c create mode 100644 board/k210-emulator/third_party_driver/gpio/Kconfig create mode 100644 board/k210-emulator/third_party_driver/gpio/Makefile create mode 100644 board/k210-emulator/third_party_driver/gpio/connect_gpio.c create mode 100644 board/k210-emulator/third_party_driver/gpio/drv_io_config.c create mode 100644 board/k210-emulator/third_party_driver/gpio/fpioa.c create mode 100644 board/k210-emulator/third_party_driver/gpio/gpio.c create mode 100644 board/k210-emulator/third_party_driver/gpio/gpiohs.c create mode 100644 board/k210-emulator/third_party_driver/gpio/utils.c create mode 100644 board/k210-emulator/third_party_driver/i2c/Kconfig create mode 100644 board/k210-emulator/third_party_driver/i2c/Makefile create mode 100644 board/k210-emulator/third_party_driver/i2c/connect_i2c.c create mode 100644 board/k210-emulator/third_party_driver/i2c/hardware_i2c.c create mode 100644 board/k210-emulator/third_party_driver/include/clint.h create mode 100644 board/k210-emulator/third_party_driver/include/connect_gpio.h create mode 100644 board/k210-emulator/third_party_driver/include/connect_hwtimer.h create mode 100644 board/k210-emulator/third_party_driver/include/connect_i2c.h create mode 100644 board/k210-emulator/third_party_driver/include/connect_rtc.h create mode 100644 board/k210-emulator/third_party_driver/include/connect_spi.h create mode 100644 board/k210-emulator/third_party_driver/include/connect_uart.h create mode 100644 board/k210-emulator/third_party_driver/include/connect_wdt.h create mode 100644 board/k210-emulator/third_party_driver/include/dmac.h create mode 100644 board/k210-emulator/third_party_driver/include/drv_io_config.h create mode 100644 board/k210-emulator/third_party_driver/include/dvp.h create mode 100644 board/k210-emulator/third_party_driver/include/font.h create mode 100644 board/k210-emulator/third_party_driver/include/fpioa.h create mode 100644 board/k210-emulator/third_party_driver/include/gpio.h create mode 100644 board/k210-emulator/third_party_driver/include/gpio_common.h create mode 100644 board/k210-emulator/third_party_driver/include/gpiohs.h create mode 100644 board/k210-emulator/third_party_driver/include/hardware_hwtimer.h create mode 100644 board/k210-emulator/third_party_driver/include/hardware_i2c.h create mode 100644 board/k210-emulator/third_party_driver/include/hardware_rtc.h create mode 100644 board/k210-emulator/third_party_driver/include/hardware_spi.h create mode 100644 board/k210-emulator/third_party_driver/include/hardware_uart.h create mode 100644 board/k210-emulator/third_party_driver/include/hardware_uarths.h create mode 100644 board/k210-emulator/third_party_driver/include/io.h create mode 100644 board/k210-emulator/third_party_driver/include/plic.h create mode 100644 board/k210-emulator/third_party_driver/include/sysctl.h create mode 100644 board/k210-emulator/third_party_driver/include/utils.h create mode 100644 board/k210-emulator/third_party_driver/include/wdt.h create mode 100644 board/k210-emulator/third_party_driver/plic/Kconfig create mode 100644 board/k210-emulator/third_party_driver/plic/Makefile create mode 100644 board/k210-emulator/third_party_driver/plic/clint.c create mode 100644 board/k210-emulator/third_party_driver/plic/drv_interrupt.c create mode 100644 board/k210-emulator/third_party_driver/plic/plic.c create mode 100644 board/k210-emulator/third_party_driver/rtc/Kconfig create mode 100644 board/k210-emulator/third_party_driver/rtc/Makefile create mode 100644 board/k210-emulator/third_party_driver/rtc/connect_rtc.c create mode 100644 board/k210-emulator/third_party_driver/rtc/hardware_rtc.c create mode 100644 board/k210-emulator/third_party_driver/sleep.c create mode 100644 board/k210-emulator/third_party_driver/spi/Kconfig create mode 100644 board/k210-emulator/third_party_driver/spi/Makefile create mode 100644 board/k210-emulator/third_party_driver/spi/connect_spi.c create mode 100644 board/k210-emulator/third_party_driver/spi/hardware_spi.c create mode 100644 board/k210-emulator/third_party_driver/sys_clock/Kconfig create mode 100644 board/k210-emulator/third_party_driver/sys_clock/Makefile create mode 100644 board/k210-emulator/third_party_driver/sys_clock/sysctl.c create mode 100644 board/k210-emulator/third_party_driver/timer/Kconfig create mode 100644 board/k210-emulator/third_party_driver/timer/Makefile create mode 100644 board/k210-emulator/third_party_driver/timer/connect_hwtimer.c create mode 100644 board/k210-emulator/third_party_driver/timer/hardware_hwtimer.c create mode 100644 board/k210-emulator/third_party_driver/uart/Kconfig create mode 100644 board/k210-emulator/third_party_driver/uart/Makefile create mode 100644 board/k210-emulator/third_party_driver/uart/connect_uart.c create mode 100644 board/k210-emulator/third_party_driver/uart/hardware_uart.c create mode 100644 board/k210-emulator/third_party_driver/uart/hardware_uarths.c create mode 100644 board/k210-emulator/third_party_driver/watchdog/Kconfig create mode 100644 board/k210-emulator/third_party_driver/watchdog/Makefile create mode 100644 board/k210-emulator/third_party_driver/watchdog/connect_wdt.c create mode 100644 board/k210-emulator/third_party_driver/watchdog/wdt.c diff --git a/Makefile b/Makefile index e122478c..64d4d442 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ MAKEFLAGS += --no-print-directory .PHONY:COMPILE_APP COMPILE_KERNEL -support :=kd233 stm32f407-st-discovery maix-go stm32f407zgt6 aiit-riscv64-board aiit-arm32-board hifive1-rev-B hifive1-emulator +support :=kd233 stm32f407-st-discovery maix-go stm32f407zgt6 aiit-riscv64-board aiit-arm32-board hifive1-rev-B hifive1-emulator k210-emulator SRC_DIR:= export BOARD ?=kd233 diff --git a/arch/risc-v/k210/boot.S b/arch/risc-v/k210/boot.S index 2d3922f5..306bf66f 100644 --- a/arch/risc-v/k210/boot.S +++ b/arch/risc-v/k210/boot.S @@ -49,7 +49,9 @@ _begin: li t0, MSTATUS_FS csrs mstatus, t0 +#ifndef BSP_USING_QEMU ZERO_F_REGISTERS +#endif .option push .option norelax diff --git a/arch/risc-v/k210/tick.c b/arch/risc-v/k210/tick.c index 3148145d..f3ba152b 100644 --- a/arch/risc-v/k210/tick.c +++ b/arch/risc-v/k210/tick.c @@ -42,10 +42,15 @@ int InitHwTick(void) CLEAR_CSR(mie, MIP_MTIP); +#ifdef BSP_USING_QEMU + tick_cycles = (10000000 / TICK_PER_SECOND); +#else tick_cycles = interval * SysctlClockGetFreq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV / 1000ULL - 1; +#endif + clint->mtimecmp[core_id] = clint->mtime + tick_cycles; SET_CSR(mie, MIP_MTIP); return 0; -} +} \ No newline at end of file diff --git a/board/k210-emulator/.defconfig b/board/k210-emulator/.defconfig new file mode 100644 index 00000000..6e5ef10b --- /dev/null +++ b/board/k210-emulator/.defconfig @@ -0,0 +1,238 @@ +# +# Automatically generated file; DO NOT EDIT. +# XiUOS Project Configuration +# +CONFIG_BOARD_K210_EVB=y +CONFIG_KERNEL_CONSOLE_DEVICE_NAME="uarths" +CONFIG_LED0=24 +CONFIG_LED1=25 +CONFIG_ARCH_CPU_64BIT=y +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_RISCV64=y + +# +# kd233 feature +# +# CONFIG_BSP_USING_AUDIO is not set +# CONFIG_BSP_USING_CAMERA is not set +# CONFIG_BSP_USING_SDIO is not set +CONFIG_BSP_USING_DMA=y +CONFIG_BSP_USING_GPIO=y +# CONFIG_BSP_USING_I2C is not set +# CONFIG_BSP_USING_I2S is not set +# CONFIG_BSP_USING_LCD is not set +# CONFIG_BSP_USING_RTC is not set +# CONFIG_BSP_USING_SECURITY is not set +# CONFIG_BSP_USING_SPI is not set +CONFIG_BSP_USING_UART=y +CONFIG_BSP_USING_UART_HS=y +# CONFIG_BSP_USING_VIDEO is not set +# CONFIG_BSP_USING_WDT is not set + +# +# General Purpose UARTs +# +CONFIG_BSP_USING_UART1=y +CONFIG_BSP_UART1_TXD_PIN=20 +CONFIG_BSP_UART1_RXD_PIN=21 +CONFIG_BSP_USING_UART2=y +CONFIG_BSP_UART2_TXD_PIN=28 +CONFIG_BSP_UART2_RXD_PIN=27 +CONFIG_BSP_USING_UART3=y +CONFIG_BSP_UART3_TXD_PIN=22 +CONFIG_BSP_UART3_RXD_PIN=23 +CONFIG___STACKSIZE__=4096 + +# +# Hardware feature +# +CONFIG_RESOURCES_SERIAL=y +# CONFIG_SERIAL_USING_DMA is not set +# CONFIG_SERIAL_RB_BUFSZ is not set +# CONFIG_RESOURCES_HWTIMER is not set +# CONFIG_RESOURCES_I2C is not set +# CONFIG_RESOURCES_LCD is not set +# CONFIG_RESOURCES_SDIO is not set +# CONFIG_RESOURCES_TOUCH is not set +CONFIG_RESOURCES_PIN=y +# CONFIG_RESOURCES_RTC is not set +# CONFIG_RESOURCES_SPI is not set +#CONFIG_RESOURCES_SPI_SD is not set +#CONFIG_RESOURCES_SPI_SFUD is not set +# SFUD_USING_SFDP is not set +# SFUD_USING_FLASH_INFO_TABLE is not set +# SFUD_DEBUG_LOG is not set +# CONFIG_RESOURCES_WDT is not set +# CONFIG_RESOURCES_USB is not set +# CONFIG_RESOURCES_USB_HOST is not set +# CONFIG_UDISK_MOUNTPOINT is not set +# CONFIG_USBH_MSTORAGE is not set +# CONFIG_RESOURCES_USB_DEVICE is not set +# CONFIG_USBD_THREAD_STACK_SZ is not set + +# +# Kernel feature +# +# CONFIG_SEPARATE_COMPILE is not set +# CONFIG_COMPILER_APP is not set +# CONFIG_COMPILER_KERNEL is not set +# +# Kernel Device Object +# +CONFIG_KERNEL_DEVICE=y +CONFIG_KERNEL_CONSOLE=y +CONFIG_KERNEL_CONSOLEBUF_SIZE=128 + +# +# Task feature +# +CONFIG_SCHED_POLICY_RR_REMAINSLICE=y +# CONFIG_SCHED_POLICY_RR is not set +# CONFIG_SCHED_POLICY_FIFO is not set + +# +# Inter-Task communication +# +CONFIG_KERNEL_SEMAPHORE=y +CONFIG_KERNEL_MUTEX=y +CONFIG_KERNEL_EVENT=y +CONFIG_KERNEL_MESSAGEQUEUE=y +# CONFIG_KTASK_PRIORITY_8 is not set +CONFIG_KTASK_PRIORITY_32=y +# CONFIG_KTASK_PRIORITY_256 is not set +CONFIG_KTASK_PRIORITY_MAX=32 +CONFIG_TICK_PER_SECOND=100 +CONFIG_KERNEL_STACK_OVERFLOW_CHECK=y +CONFIG_KERNEL_BANNER=y +# CONFIG_KERNEL_HOOK is not set +CONFIG_KERNEL_SOFTTIMER=y +CONFIG_KERNEL_IDLE_HOOK=y +CONFIG_IDEL_HOOK_LIST_SIZE=4 +CONFIG_IDLE_KTASK_STACKSIZE=1024 +CONFIG_USER_APPLICATION=y +# CONFIG_TASK_ISOLATION is not set + +# +# Memory Management +# +# CONFIG_KERNEL_MEMBLOCK is not set + +# +# Command shell +# +CONFIG_TOOL_SHELL=y +CONFIG_SHELL_TASK_PRIORITY=20 +CONFIG_SHELL_TASK_STACK_SIZE=4096 + +# +# User Control +# +CONFIG_SHELL_DEFAULT_USER="letter" +CONFIG_SHELL_DEFAULT_USER_PASSWORD="" +CONFIG_SHELL_LOCK_TIMEOUT=10000 +CONFIG_SHELL_ENTER_CR_AND_LF=y +# CONFIG_SHELL_ENTER_CRLF is not set +CONFIG_SHELL_ENTER_CR=y +CONFIG_SHELL_ENTER_LF=y +CONFIG_SHELL_MAX_NUMBER=5 +CONFIG_SHELL_PARAMETER_MAX_NUMBER=8 +CONFIG_SHELL_HISTORY_MAX_NUMBER=5 +CONFIG_SHELL_PRINT_BUFFER=128 +CONFIG_SHELL_USING_CMD_EXPORT=y +# CONFIG_SHELL_HELP_LIST_USER is not set +CONFIG_SHELL_HELP_SHOW_PERMISSION=y +# CONFIG_SHELL_HELP_LIST_VAR is not set +# CONFIG_SHELL_HELP_LIST_KEY is not set +CONFIG_KERNEL_QUEUEMANAGE=y +CONFIG_KERNEL_WORKQUEUE=y +CONFIG_WORKQUEUE_KTASK_STACKSIZE=512 +CONFIG_WORKQUEUE_KTASK_PRIORITY=23 +CONFIG_KERNEL_WAITQUEUE=y +CONFIG_KERNEL_DATAQUEUE=y +# CONFIG_KERNEL_CIRCULAR_AREA is not set +# CONFIG_KERNEL_AVL_TREE is not set +CONFIG_NAME_MAX=32 +CONFIG_ALIGN_SIZE=8 +CONFIG_KERNEL_COMPONENTS_INIT=y +CONFIG_KERNEL_USER_MAIN=y +CONFIG_MAIN_KTASK_STACK_SIZE=2048 +CONFIG_ENV_INIT_KTASK_STACK_SIZE=8192 +CONFIG_MAIN_KTASK_PRIORITY=10 +# CONFIG_USER_TEST is not set +# CONFIG_TOOL_TEST_SEM is not set +# CONFIG_TOOL_TEST_MUTEX is not set +# CONFIG_TOOL_TEST_EVENT is not set +# CONFIG_TOOL_TEST_MSG is not set +# CONFIG_TOOL_TEST_AVLTREE is not set +# CONFIG_TEST_CRICULAR_AREA is not set +# CONFIG_TOOL_TEST_MEM is not set +# CONFIG_TOOL_TEST_TIMER is not set +# CONFIG_TOOL_TEST_IWG is not set +# CONFIG_TOOL_TEST_REALTIME is not set +# CONFIG_TOOL_TEST_DBG is not set +# CONFIG_TOOL_TEST_SCHED is not set +# CONFIG_KERNEL_DEBUG is not set +CONFIG_DEBUG_INIT_CONFIG=y +CONFIG_DBG_INIT=1 +CONFIG_ARCH_SMP=y +CONFIG_CPUS_NR=2 + +# +# File system +# +CONFIG_FS_VFS=y +CONFIG_VFS_USING_WORKDIR=y +CONFIG_FS_VFS_DEVFS=y + +# +# Fat filesystem +# + +# +# IOT-Device File system +# + +# +# Lwext4 filesystem +# + +# +# APP Framework +# + +# +# Perception +# +# CONFIG_PERCEPTION_SENSORDEVICE is not set + +# +# connection +# +# CONFIG_CONNECTION_AT is not set +# CONFIG_CONNECTION_MQTT is not set + +# +# medium communication +# + + +# +# Intelligence +# + +# +# Control +# + +# +# Lib +# +CONFIG_LIB=y +CONFIG_LIB_POSIX=y +CONFIG_LIB_NEWLIB=y + +CONFIG_LITTLEVGL2RTT_USING_DEMO=y + +# +# Security +# diff --git a/board/k210-emulator/Kconfig b/board/k210-emulator/Kconfig new file mode 100644 index 00000000..42dbacd6 --- /dev/null +++ b/board/k210-emulator/Kconfig @@ -0,0 +1,81 @@ +mainmenu "XiUOS Project Configuration" + +config BSP_DIR + string + option env="BSP_ROOT" + default "." + +config KERNEL_DIR + string + option env="KERNEL_ROOT" + default "../.." + +config BOARD_K210_EVB + bool + select ARCH_RISCV + select ARCH_RISCV64 + select ARCH_CPU_64BIT + default y + +config LED0 + int + default 24 + + config LED1 + int + default 25 + + +source "$KERNEL_DIR/arch/Kconfig" + +menu "kd233 feature" + source "$BSP_DIR/third_party_driver/Kconfig" + + menu "config default board resources" + menu "config board app name" + config BOARD_APP_NAME + string "config board app name" + default "/XiUOS_kd233_app.bin" + endmenu + + menu "config board service table" + config SERVICE_TABLE_ADDRESS + hex "board service table address" + default 0x80100000 + endmenu + + menu "config hardware resources for connection" + if CONNECTION_COMMUNICATION_ETHERNET + config ETHERNET_UART_NAME + string "ethernet uart name" + default "/dev/uart3_dev3" + endif + if CONNECTION_COMMUNICATION_WIFI + config WIFI_UART_NAME + string "wifi uart name" + default "/dev/uart3_dev3" + endif + + endmenu + + endmenu + + config __STACKSIZE__ + int "stack size for interrupt" + default 4096 + +endmenu + +config BSP_USING_QEMU + bool + default y + + + +menu "Hardware feature" +source "$KERNEL_DIR/resources/Kconfig" +endmenu + +source "$KERNEL_DIR/Kconfig" + + diff --git a/board/k210-emulator/Makefile b/board/k210-emulator/Makefile new file mode 100644 index 00000000..12f41481 --- /dev/null +++ b/board/k210-emulator/Makefile @@ -0,0 +1,6 @@ +SRC_FILES := board.c + +SRC_DIR := third_party_driver + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/README.md b/board/k210-emulator/README.md new file mode 100644 index 00000000..a646410f --- /dev/null +++ b/board/k210-emulator/README.md @@ -0,0 +1,164 @@ +# 从零开始构建矽璓工业物联操作系统:使用risc-v架构的k210 emulator + +# k210 emulator + +[XiUOS](http://xuos.io/) (X Industrial Ubiquitous Operating System) 矽璓XiUOS是一款面向智慧车间的工业物联网操作系统,主要由一个极简的微型实时操作系统内核和其上的工业物联框架构成,通过高效管理工业物联网设备、支撑工业物联应用,在生产车间内实现智能化的“感知环境、联网传输、知悉识别、控制调整”,促进以工业设备和工业控制系统为核心的人、机、物深度互联,帮助提升生产线的数字化和智能化水平。 + +>注:最新版README请访问[从零开始构建矽璓工业物联操作系统:使用risc-v架构的k210 emulator](https://blog.csdn.net/AIIT_Ubiquitous/article/details/116610203),如博客内容与本地文档有差异,以网站内容为准。 + +## 1. 简介 + +Q‎EMU 是一个通用的开源模拟器和虚拟化工具。‎从5.0版本开始,Q‎EMU已经可以较完整的支持RISC-V架构。目前XiUOS同样支持运行在Q‎EMU上 + +| 硬件 | 描述 | +| -- | -- | +|芯片型号| K210 | +|架构| 双核RV64GC | +|主频| 400MHz | +|片内SRAM| 8MB | +| 外设支持 | UART | + +XiUOS板级当前支持使用UART。 + +## 2. 编译说明 + +**操作系统:** ubuntu18.04 [https://ubuntu.com/download/desktop](https://ubuntu.com/download/desktop) + +**开发工具推荐使用 VSCode ,VScode下载地址为:** VSCode [https://code.visualstudio.com/](https://code.visualstudio.com/),推荐下载地址为 [http://vscode.cdn.azure.cn/stable/3c4e3df9e89829dce27b7b5c24508306b151f30d/code_1.55.2-1618307277_amd64.deb](http://vscode.cdn.azure.cn/stable/3c4e3df9e89829dce27b7b5c24508306b151f30d/code_1.55.2-1618307277_amd64.deb) + +### 依赖包安装: + +``` +$ sudo apt install build-essential pkg-config +$ sudo apt install gcc make libncurses5-dev openssl libssl-dev bison flex libelf-dev autoconf libtool gperf libc6-dev git +``` + +**XiUOS操作系统源码下载:** XiUOS [https://forgeplus.trustie.net/projects/xuos/xiuos](https://forgeplus.trustie.net/projects/xuos/xiuos) + +新建一个空文件夹并进入文件夹中,并下载源码,具体命令如下: + +```c +mkdir test && cd test +git clone https://git.trustie.net/xuos/xiuos.git +``` + +打开源码文件包可以看到以下目录: +| 名称 | 说明 | +| -- | -- | +| application | 应用代码 | +| board | 板级支持包 | +| framework | 应用框架 | +| fs | 文件系统 | +| kernel | 内核源码 | +| resources | 驱动文件 | +| tool | 系统工具 | + +使用VScode打开代码,具体操作步骤为:在源码文件夹下打开系统终端,输入`code .`即可打开VScode开发环境,如下图所示: + +![vscode](img/vscode.jpg) + +### 裁减配置工具的下载 + +**裁减配置工具:** kconfig-frontends [https://forgeplus.trustie.net/projects/xuos/kconfig-frontends](https://forgeplus.trustie.net/projects/xuos/kconfig-frontends) +执行以下命令下载配置工具: + +```c +mkdir kfrontends && cd kfrontends +git clone https://git.trustie.net/xuos/kconfig-frontends.git +``` + +下载源码后按以下步骤执行软件安装: + +```c +cd kconfig-frontends + ./xs_build.sh +``` + +### 编译工具链: + +RISC-V: riscv-none-embed-,默认安装到Ubuntu的/opt/,下载源码并解压。[下载网址 http://101.36.126.201:8011/gnu-mcu-eclipse.tar.bz2](http://101.36.126.201:8011/gnu-mcu-eclipse.tar.bz2),下载完成后,执行以下命令: + +```c +sudo tar -xvjf gnu-mcu-eclipse.tar.bz2 -C /opt/ +``` + +在VScode中将上述解压的编译工具链的路径添加到board/k210-emulator/config.mk文件当中,操作如下: + +```c +export CROSS_COMPILE ?=/opt/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.1-20190425-1021/bin/riscv-none-embed- +``` + +若`CROSS_COMPILE ` 变量定义语句已经存在,将它替换成上面的语句 + +# 编译步骤: + +1.在`VScode`的“命令终端”中执行以下命令,生成配置文件 + +``` +make BOARD=k210-emulator menuconfig +``` + +2.在menuconfig界面配置需要关闭和开启的功能,按回车键进入下级菜单,按Y键选中需要开启的功能,按N键选中需要关闭的功能,配置结束后选择Exit保存并退出(本例旨在演示简单的输出例程,所以没有需要配置的选项,双击快捷键ESC退出配置) + +![menuconfig1](img/menuconfig1.png) + +退出时选择`yes`保存上面所配置的内容,如下图所示: + +![menuconfig2](img/menuconfig2.png) + +若执行 `make BOARD=k210-emulator menuconfig`后出现以下界面: + +![menuconfig3](img/menuconfig3.png) + +解决的方法是将终端向上拉伸超过当前界面的三分之二以上,效果如下: + +![menuconfig4](img/menuconfig4.png) + +3.继续在VScode命令终端中执行以下命令,进行编译 + +```c +make BOARD=k210-emulator +``` + +4.如果编译正确无误,会在build目录下产生XiUOS_k210-emulator.elf、XiUOS_k210-emulator.bin文件。 + +## 3. 运行 + +### 3.1 编译并安装Q‎EMU + +**QEMU v6.0.0源码下载:** Qemu-K210 Emulator for XiUOS [https://forgeplus.trustie.net/projects/xuos/QemuK210](https://forgeplus.trustie.net/projects/xuos/QemuK210) + +``` +git clone https://git.trustie.net/xuos/QemuK210.git +sudo apt install ninja-build libpixman-1-dev +cd QemuK210 +./configure --target-list=riscv64-softmmu +make +sudo make install +``` + +### 3.2 运行结果 + +通过以下命令启动Q‎EMU并加载XiUOS ELF文件 + +``` +qemu-system-riscv64 -nographic -machine sifive_u -bios build/XiUOS_k210-emulator.elf +``` + +QEMU运行起来后将会在终端上看到信息打印输出 + +![terminal](img/terminal.png) + +### 3.3 调试 + +利用Q‎EMU可以方便的对XiUOS进行调试,首先通过以下命令启动Q‎EMU + +``` +qemu-system-riscv64 -nographic -machine sifive_u -bios build/XiUOS_k210-emulator.elf -s -S +``` + +然后要重新开启另一个linux系统终端一个终端,执行`riscv-none-embed-gdb`命令 + +``` +riscv-none-embed-gdb build/XiUOS_k210-emulator.elf -ex "target remote localhost:1234" +``` diff --git a/board/k210-emulator/board.c b/board/k210-emulator/board.c new file mode 100644 index 00000000..0b9f6fa6 --- /dev/null +++ b/board/k210-emulator/board.c @@ -0,0 +1,207 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 board.c +* @brief support kd233-board init configure and start-up +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: board.c +Description: support kd233-board init configure and driver/task/... init +Others: https://canaan-creative.com/developer +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. support kd233-board InitBoardHardware +2. support kd233-board Kd233Start +3. support kd233-board shell cmd, include reboot, shutdown +*************************************************/ + +#include +#include +#include +#include "board.h" +#include "tick.h" +#include "connect_uart.h" +#include "encoding.h" +#include "fpioa.h" +#include "dmac.h" +#include "connect_gpio.h" + +#if defined(FS_VFS) +#include +#endif + +#define CPU0 (0) +#define CPU1 (1) +extern x_base cpu2_boot_flag; +extern void entry(void); +extern void SecondaryCpuCStart(void); +extern void ShutdownCpu(void); +extern int IoConfigInit(void); +extern int HwSpiInit(void); +extern int HwI2cInit(void); +extern int HwRtcInit(void); +extern int HwWdtInit(void); +extern int HwLcdInit(void); +extern int HwTimerInit(void); + +void InitBss(void) +{ + unsigned int *dst; + + dst = &__bss_start; + while (dst < &__bss_end){ + *dst++ = 0; + } +} + +void Kd233Start(uint32_t mhartid) +{ + switch(mhartid) { + case CPU0: + InitBss(); + + /*kernel start entry*/ + entry(); + break; +#ifdef ARCH_SMP + case CPU1: + while(0x2018050420191010 != cpu2_boot_flag) { ///< waiting for boot flag ,then start cpu1 core + + } + SecondaryCpuCStart(); + break; +#endif + default: + break; + } +} + +int Freq(void) +{ + uint64 value = 0; + + value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL0); + KPrintf("PLL0: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL1); + KPrintf("PLL1: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL2); + KPrintf("PLL2: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_CPU); + KPrintf("CPU : %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + KPrintf("APB0: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_APB1); + KPrintf("APB1: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_APB2); + KPrintf("APB2: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_HCLK); + KPrintf("HCLK: %d\n", value); + + value = clint_get_time(); + KPrintf("mtime: %d\n", value); + + return 0; +} +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),freq, Freq, show freq info ); + +#ifdef ARCH_SMP +extern int EnableHwclintIpi(void); +#endif + +struct InitSequenceDesc _board_init[] = +{ +#ifdef BSP_USING_GPIO + { "hw_pin", HwGpioInit }, +#endif + +#ifdef BSP_USING_HWTIMER + { "hw_timer" , HwTimerInit }, +#endif + + { " NONE ",NONE }, +}; + +void InitBoardHardware(void) +{ + int i = 0; + int ret = 0; + + /* initalize interrupt */ + InitHwinterrupt(); +#ifdef BSP_USING_UART + HwUartInit(); +#endif +#ifdef KERNEL_CONSOLE + /* set console device */ + InstallConsole(KERNEL_CONSOLE_BUS_NAME, KERNEL_CONSOLE_DRV_NAME, KERNEL_CONSOLE_DEVICE_NAME); + KPrintf("\nconsole init completed.\n"); + KPrintf("board initialization......\n"); +#endif /* KERNEL_CONSOLE */ + + InitHwTick(); + +#ifdef ARCH_SMP + EnableHwclintIpi(); +#endif + /* initialize memory system */ + InitBoardMemory(MEMORY_START_ADDRESS, MEMORY_END_ADDRESS); + +#ifdef KERNEL_COMPONENTS_INIT + for(i = 0; _board_init[i].fn != NONE; i++) { + ret = _board_init[i].fn(); + KPrintf("initialize %s %s\n",_board_init[i].fn_name, ret == 0 ? "success" : "failed"); + } +#endif + KPrintf("board init done.\n"); + KPrintf("start kernel...\n"); +} + +void HwCpuReset(void) +{ + sysctl->soft_reset.soft_reset = 1; + while(RET_TRUE); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0), + reboot, HwCpuReset, reset machine ); +static void (*pre_shutdown_action)(void *); +static void *pre_shutdown_action_arg; + +void SetPreShutdownAction(void (*func)(void *), void *arg) +{ + pre_shutdown_action = func; + pre_shutdown_action_arg = arg; +} + +void CmdShutdown() +{ +#ifdef FS_VFS + SyncOpenedFiles(); +#endif + if (pre_shutdown_action != NULL) + pre_shutdown_action(pre_shutdown_action_arg); + + ShutdownCpu(); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0), + shutdown,CmdShutdown,shutdown machine); diff --git a/board/k210-emulator/board.h b/board/k210-emulator/board.h new file mode 100644 index 00000000..52eaeb5e --- /dev/null +++ b/board/k210-emulator/board.h @@ -0,0 +1,91 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 board.h +* @brief define kd233-board init configure and start-up function +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: board.h +Description: define kd233-board board init function and struct +Others: https://canaan-creative.com/developer +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. define kd233-board InitBoardHardware +2. define kd233-board data and bss struct +*************************************************/ + +#ifndef BOARD_H__ +#define BOARD_H__ + +#include +#include +// #include "../../kernel/include/xs_service.h" + +extern unsigned int __bss_start; +extern unsigned int __bss_end; +extern unsigned int __stack_end__; +extern unsigned int g_service_table_start; +extern unsigned int g_service_table_end; + + +#ifdef SEPARATE_COMPILE +#define G_SERVICE_TABLE_LENGTH (0x1000) + +#define MEMORY_START_ADDRESS (void*)&__stack_end__ +#define MEMORY_END_ADDRESS (void*)((0x80000000 + 1 * 1024 * 1024)) /* 1M SRAM */ + +typedef int (*main_t)(int argc, char *argv[]); +typedef void (*exit_t)(void); +struct UserSpaceS +{ + main_t us_entrypoint; + exit_t us_taskquit; + uintptr_t us_textstart; + uintptr_t us_textend; + uintptr_t us_datasource; + uintptr_t us_datastart; + uintptr_t us_dataend; + uintptr_t us_bssstart; + uintptr_t us_bssend; + uintptr_t us_heapend; +}; +#define USERSPACE (( struct UserSpaceS *)(MEMORY_END_ADDRESS + G_SERVICE_TABLE_LENGTH)) + +#ifndef SERVICE_TABLE_ADDRESS +#define SERVICE_TABLE_ADDRESS (0x80100000) +#endif + +#define USER_MEMORY_START_ADDRESS (USERSPACE->us_bssend) + +#define USER_MEMORY_END_ADDRESS (void*)((0x80000000 + 6 * 1024 * 1024) ) + +#else + +#define MEMORY_START_ADDRESS (void*)&__stack_end__ +#define MEMORY_END_ADDRESS (void*)(0x80000000 + 6 * 1024 * 1024) +#endif + + + +void InitBoardHardware(void); + +#endif diff --git a/board/k210-emulator/config.mk b/board/k210-emulator/config.mk new file mode 100644 index 00000000..bb977c76 --- /dev/null +++ b/board/k210-emulator/config.mk @@ -0,0 +1,17 @@ +export CFLAGS := -mcmodel=medany -march=rv64imac -mabi=lp64 -fno-common -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -O0 -Wa,-g -ggdb -fgnu89-inline -Werror +export AFLAGS := -c -mcmodel=medany -march=rv64imac -mabi=lp64 -Wa,-g -ggdb +export LFLAGS := -mcmodel=medany -march=rv64imac -mabi=lp64 -nostartfiles -Wl,--gc-sections,-Map=XiUOS_kd233.map,-cref,-u,_start -T $(BSP_ROOT)/link.lds + +export APPLFLAGS := -mcmodel=medany -march=rv64imac -mabi=lp64 -nostartfiles -Wl,--gc-sections,-Map=XiUOS_app.map,-cref,-u, -T $(BSP_ROOT)/link_userspace.lds + + +export CXXFLAGS := -mcmodel=medany -march=rv64imac -mabi=lp64 -fno-common -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -O0 -Wa,-g -ggdb -Werror + +export CROSS_COMPILE ?=/opt/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.1-20190425-1021/bin/riscv-none-embed- + +export DEFINES := -DHAVE_CCONFIG_H -DHAVE_SIGINFO + +export ARCH = risc-v +export MCU = k210 + + diff --git a/board/k210-emulator/img/menuconfig1.png b/board/k210-emulator/img/menuconfig1.png new file mode 100644 index 0000000000000000000000000000000000000000..1d9f2b5a3d7614270388f3d07bbc91674b9877fc GIT binary patch literal 64346 zcmd423sjS5_C884Q|q*rDYRM@Nn22=aw#AnNWxgP5dl*Leodn>Xst zpNiQ@{X9jS9QOHJcaC3geSi1|^Lsl~Yg=|E-l;{UKr7Gxvh&9XHY_s{?xgs6;HN&@ za`cb}{rq9E+T=7{sAM~Mc+za;8)CBvZbV3d(QW>K@{faFUSa=kgL`@P$18!Wue`Xt zzr}HQ%gZ-G*Z-#vn#AT*i^QVwdHJFHTRgYF`tp*V>iqi4t9Wtbn=h|=m@R*Md6koz z@KFR#uC{kP|t%kxUO#mO==9iZcEI7v5-n01!RDIkl^^1EfBl3*cdEo*}ud4Qf^ zr<{QL2e1d8bJUzQ!bS!pMBC#nd?2@lZQl6rw~_Uh`vjw^K$VsZH*8y`FW04{opjoI zT?TWm^FFg|B3h8phuc1uBml~yM{?;xL_<~)iUp9X$_hAfNhkn1;p=( zQ9P|HY&Xn~d(<`X-!-k34UJ1NO8HqEd}t;81eK9E?QEfp$HpM}&-~VQJ+j>#!u5Ia zN3dT$`{F|8D;)W400PHUTly6YV}@T#@%m*jd=9 zOQOX>vkcIed`yP%eU=9nv*mf5jgM)K7Wgz>VMzf8-gq=TIv3@^%y~5O;{=!LRjeFr zax}(nk@8u}VE-5H%46?2uv|>gORmr>W%Mf#%{vct79U=0h!NTFF*dk~w6U?`^kK@y zirxt&hU4gpFg5Sps#kDHDk1x0?nto}eeE8sx5Ry)tNLA{J}mvn5%g2}r>&Q4NF_-H z`poHY+HTr+>iRj;yx+gfUE|*n?vu#T!98<`j#my8b_T}Hwv%;7ZabaXv@5=bMNI5^ zg|bdJ;NLzo8#unYQlw%U4b<;-m4 zCm&f@rZ~RKoRl&U$0u@e3+bZUYT4au2gT8}ThzjVV+`Iho~e9BZ5g8AGAm6I8J1Kq}!%_?!R{J2kW!2)6^#+BeMl#lh+r0c9YKfOx)D_{*iyL7oG3H|Iz1szX(R$ers%r)a-Z20;o+(@tY2B($ZxLVv&c_*W=xBOe&?j_X zKkIPIPWpH4y-cs+b~(0#nO4U@Q%!gD1vSf9LGFviY5%1&_8a^|57_%NpI=D(cCPL` z=O|@2n+2!ywyoTQadQ3kmHA}UC^9r&+A%uO!RJVmNwT~3vQ*!GFDtW43A=jH8C87P zr#f?Tr;(b9bwtTnh1tn%mxBC_cBi#xv=frn#pvl4WVdvHl6F^q7)d2M7(Ng%rF>Fi zoSGtoiF5m@PH$?u40d3PAdF&fp{d>I2ts+KA1K2VsZ%Nw_}bbqlc+=T5NtdQ%t;T- z3D-PwSdrVtgkUV!JdIr_$P5<7DMAUjHwpExM=uyF703x2e$MF2Ns_;G_K!-#3JQLo zbgWAIe(uK$tF8B%D)UD|p5RAX(|#{IKq-3Fv~c49Z*bs%_+ypPo5Y;Fu98I-2IRha zIV$`3)S4t&)C>0DFjROAHs57=G4t@tg&v-jdfLb&saj9hI~Cce$?x?D8Sck*;qs`V zf<&A;pn6AmL`$c9BPLXZ*$9$K!=$#KfoTibGlr*eVl~FMi-?)K)gK^3{UKQYLfF0k zQi~qjQAZ#26i$@oKr&dHtH}!X>2`9n^b1y&?UjXdoRV;pM|#-o$hI*TpCIJaadsjP zk~Z~|q_qH?Oo#~)cR)E0da?!(x}k|MP`FfhqBJfDk``s%d6``Ky!6V?J$U*>IOrI- zGI(+pRr^kf2}5l18drYl0738X;GF|x_q2AC|@4XRJ)`-iRH;{y+FrLE%R z+R?cR7vtgFJw0B`7_rLKUS%EROK&Tff5Jd$x@!l$F!IG=<>p3fmGe!@9~V3GqJ7?M zhpgMOq*ok##Epj8f+viXaZKA4k=`XncgE*-@ttyo)YzNMac4cgS5RXZoIQ0iHRPSg z65mQijl$SNjNGWq2?sw)xH)%EJCW!4pI|V4NpVF zIArOa*dTvu`kt!xbVLe}WMhaf!r#rWy;ZzlkQh{nU_R26|7n1xUKzQ*a`Ktk&gWe5 zT0i|;Ui!>UMMsfU3?>6{SzQ&fxsKyY$HrH(skvg;%qs|S5ZE{8;x-qpET-RmmE-O` z(OvgH4dX*m+tNeS*OFdp3oHA!8=|R5eGPb*9t{atXX+;3}&5C|VV3Gin0$F&M$u43y=3A1UrP8AlgAbYY_?~R%4 z-lx~8U%Jrr9+AxfZ|#;Kfv9ORtKDIU-05sSeyRNG0g8^)+6Whvvei9gQEXcx2)daZ zvJl-EB9&$vs0i7r6$u!fQ%~nASed$c?F-1@e?Kzksz3N|p>Ywg&t{|u*dA1%V6@=z z!lhKp`^mi2bL+#q%P`1S-BKr@<~KQW9r;Hp>eaLeutmF3V>O{-3E z1_*NRm$@8#f`4XKs*7G_A9XB9PkX{LZJI93xPR!3Ft6FfxTu=x0|uW?-TQ;&SYdtd zPM#yLVlzzYbCACEOL3Voy7X1QaW3;(B4>L~#BF-7`(qDbu}B~i6((n1sZPz4dkWv$ zwCNvK3D1w3dZkpSwp{V#;%TFQ)b-uXH-saDkMXvLeLiV|aiV;u2AaESe4O=?*W*Rq z#L45dnb0)$TnFatmlOJ$zR8Ol=#SH=X}l1%%knkRrHci7dv6HCAu76)t&Ooky7ED? z`Kgagsq{7Fu3UyaO%74Ht>h+W4&E?B`5dpYBtN$rerB9gE2rp=@{q1UTBZzI;EoX6 zbZAHP;U`&$fE(ju?k8-{<)M3}#?E)l3h&&{4yM|4|9n1xqRFk`u(;=hWo*{9kBmHX z6C@!%#!XLa1BQ}B{nxVjE^X>itilH*bT-a>p3J%2UDCBb@2nPzj9lv6Iw?*YHpb@% z(v>*K&*agY7sh1*N?)fFInZYH(fzXu!w6Qts)QNhMu;kVuxqHlaJ40vma3dzZ?7|i z$P+tJ)sfu-yH0jVjE2%lHtac*ck6OMVtH8Bo(-Om1zSy+x8a!0@4f$Bym!=*p~NC) z&;}`?`~o|vddimn=TR!^W=md=Dy}4TrpFL8%@=of{v#mO$;UCXxJB9#Y$*xxIanjw z!#Y2KY^6=Dx#%aa7c6WonG7@c`JD4~^WqAN?xQ>*8h9oe>8}j@h26X2mnbCPY(Oy= zN%c*2sIu0{n|$|G$PM2f28X35_( z!rsoEm=UF4^5?B34USH(sz%LaOj;X8wtnqjA=4MsKlp4iETrf{<5l8}z?S@J`koiK z`>Wp1;!j)NN1{JVOnwb?g8X5lQ@&%$ct7d|0{`;7^UURyi=ia=F%mo^(x?652n>5D zs%_ot`*jon{c#grz94*c1*H_;|N7m@t+M(F*2&Ng0t`G0>y$sbC~4CUpgt(+=Wt{|`d;1hi0 zpR7j0FR8~Q{QqL`PKI_fmGC0_SXn`;_UpA_3D5KDe)*@BnkqBkFt6?8ul~A8UxA;V zuK#Brxer~=4=~7(cv-e(u~KR_1?*I!ape!C8&JzerPRO**rPRLkgaf-TON2h>BOHDN_N|>>K(-i7~ga z<&Wc`UjTbxaOb;mKDG6)hrwc}PHi~88<|?~7`Lhl(Y7!P{7Xk|Q9%7>{1dJA^wF92K_I`^d7@lD;ROL*(^=vQaR$KlKvl=foms#AGg zy3QbR%j2E0qy0bQW;QrRp++rnPxVD|_IatH!t$I~t^V-(^D3xv*;?JzIYqh9sl6wC z7o6wu5?SJ$N4Bjwjy1AD$HLGy-mIRB7920n$^Ahqi7pS$ z$_DAr7iULwLm3B$ckF~R$`$3|14C8Z++7DDr=F(pDiXS1(zHdNKdqXa@6C6j(!P%P zO%{ED>eO6Tr%OLH++Oxbc_6CXUBBW-+vtBBkN?pnkhK2|UZfyWqU5c_fn_y35QeO>pbV7p(lIupP5JPkZ{W#$ci^k=^`8B#3K6K8v)Rk>*J zwhua=2kf1erq%l1#+04BM;yzk-o!ZAt1~Fh1gE4cCh)r_(alJen=Hl{ei!Gu zkA)=8Zs+0loZ+HeZuQK~`-kD+oFHM54=~>BnVy1EcVGr@3?(K(Trn@sgv7@9jEH&! z_@~C+;T#A80Q>jL>n4Sv1wS}dd<&#DVwjJ_!Kb3$8zD&3Wt-{@o8hN&;nDWm8=1zz zjfEc#QCm5X9~mnBMPVyV&tKNpPv(C6DZL3MjkgKwd_qx;j$CdDz7rdY%iZW^b9!i| z#I&N5foSrnXn2EXP^3|l+9@{mjO5hx`|VA z?)=N}k0_RP%4=5l8y7rh&U9Xm^~pC5YFwC;&xW=w#H2Q|rC-roSJkQAY*k|S@QB+4jj!0VyKthaD-4C>`iS) z9ehuA(ceOE??t$k&CZJOQr<9b($hK|GMEi-3l|9cwvYHNW;BmwH4-6(m-lFo=eluF z5XW;3l^3>S_*W4Ik$>hUjC2t4-W@Rlk_Vi~(Fx6>kP&&`&Hoitr-J|ShSfJ7xF7u$ zf)PhyO6P+qcH`|3i+j+z11Jnr3WX3+%I6wrL*{YcUPmEl9X%Q zk4|??k5Sbhhf1X-&H1MctIN_|^6g`muU@^BUt{b@vTwwSlKLC*Q4t2VW)oAE;U-V@ zQB!4t@wC)-y)*;jJliwmecMS$8&sEh3m2=~pmdT;oqng4727`a0`juKZfEF{vZ41k z+mNGqe_aX#R6}*GG?w=LD7oIClRP7D(yM~ShLrsY)T~e(snR@gZcmcATBI5ysw)^B zIx`x~SSZ@)5J2(<8#&v%m!geqPE4*vg3SFmCI51_np#wXDW231Jd8%)c>$T!6;YyA z;;Fv9QQ$H9=1_Hx2Bv*X5yrG-`@Ya-9x%?7e**N$W4F~m?*HT?K+L>9QM5_Cns)c0 z9v81rd}etM!qm#CFrLi&Hot%5K`!YG{oU)S*2J=Bx?yGg}s^p%_N5)`=oVwj| zj4CA9S*4PS)u#8qK{Wn}Z-w5D(-Mg2=n-2EMwj`5GH-JAKT+n6((5r|fC^5DmLv&H z%Hu`3p`WpssMNIfd!3imRp8vs3;=dCq}}}1W>fX8Y6t)qIfXR#IDwgtD8L@^;)p2B zit^m6b$X>wZ*g!{+8T*H<&yV(jBek)GM$dU9B$kn^_1|#bH?E-WB8vlM{Pp`>lV=p zs$o`2O;|{dMFif`Uzatc_j){Oog<^~uGHjJVuX`rxS7DwWY0k~A(}?gx40xs(Ep+? zoo`AHZW++tVKSJ^8j)RGQq1)Fz$V7kU;nr1>L$M$DtPYyZu`0R**d+Ta)2?|H}Y-g zKR~7k1=)=1Si%-6F z(L^-zOHTd-;pfFr9-e%P+GQN2^P%x{m8W5ORo0BN541nsIwgWRW}$*_d>?*+ysXDV z<+l`d32OHkLFrW;5!vfbH`E#d=Yk=o{RU2|4!hKPm84uI6>&F$Mr|l&7 zi-ZZnSkeGOIV(Xi_mY>J|9fI(09i`AQ{SvG+WNAv`RqZ*t+^Mz+>aWu{T^!2I+@RbM_ zwXc*obZiV1GPxL)$x>}+sTrM0)IVtydGzO>kGfSh?~!{1iuam%Ey3>6wxOjwd7A)0 zlz$GFof)>BX4+Krg?)-k*fhMbK#ocK8VcSTW+e8Uo?tj#YPC!b#Ort?;Ugi-C9}QQ z!dv>h$&(y_80E$airy`T(4J6J!((%&Kjc=n?sr8zWg4WX@Rx#lzRf0AN|sV!NW>-X zIUOkRpjP%-I1#PPi|{-+_%DM0dzQp^*C+6lj>5D8Px+UWwny~on8Y*g^NGa>Zuzpa zjN%oVIno|#j1hGWEfvT;|7%KC{=ZS3{LdHNi3A`UBNPnK4BwNhQ=k52uOm?1`KE1l z>+RgulfV5)HPE{TigQDE0|+Pc-|Nsy?E+hz75;5bXqwGyJ|%dxig;zcE0J|&9aXjd zJ{3202de;Vh<(Qf=M#K%YaRsnIx9Tm(t=1TlqtQar9~H|7)!x%;BD=n9;-hWSn&c% zpCJEk*hJ87&y@noWd24)gc2w>v0eXtyG=At4*XX}+kAQ7bL!M;xTz+%lj-v!2fujk ziw`!~q=d$;I!-$Lzw^Iu=v+R*tU=D0W#gEv^Y;bKfpQ(!#?|#8hzCSLNldM}9pW=Qo+2PlDaJ=Rr$oxkoWn;!E z0W80(`J{!Sc%|@eB`iqN7EoB>skX+x9#wCOwza|e2T_j-VMB*-0>cAq{HIJ)MKz9c z>jFoPCGh!A=s8&Wz684Lrb530-g5Xh?R{YC$|wJxdLHrmd=uqR!N%)?(H~JZI10@2 ztK)?J@cSC##)E31fG&&)7C)0M|7A_q7 zpU#RTA8c}fz472-68vD>+iCrE%mKre0AwBIVLMw(rNA zLSM=;PCU{*Rd$z{A;D*XX2IfIbkp2`@ilrg91eLns3P`jH7-IJ`6J=|Xbi}-CCSLZ z0n$DPMFy<%T#_m^`mO`}?E4asht99C!ECP|lEy=2>wnc)!MkIGw;Bm0`-QsR$ei2z zKUr4fv121`f8Tg?+4UaUR0A@7mBL#bM%Go)DLd$Eq2mn6(ApmxWL=@A#%>2Ff)g)i zxmpN=fSlT_7G6hFJ9E^&c$k0}GyMSig|v2M_gVkPdVksuWZo8j5#oHDZM}hbn~+td zNKm4)bhsa>vdB!ed?q4*jWKerE_V02k4a_2(#&KyMuxrz`U9`!w5tuAFe_m{fWBQB(UnMp>bh7{>1f{jIG)!en>2aZc(vzLCfj(;$sKuW!W=x)ueMmq8<<-BD@p zI1}Aqx1Eu}tEq9u%g-ORGTWMY-Yc&s&E2xRqg^2rLhmrkJDdR)Rgc<^OZ~jJe0kq# zgbysEnK9J>Ip8`G?*^w0)7mR9+Skbx$_o=o>Sb+eYRe)VP`GNA_9T@iL3GWe4BhgH zxrW}GnosDSgs3g$!sx4)+nG|9tT_uaR0G+8W;N4geH>mF@e}UN4+QR{NA+CoxmenQ zi8*jgD%{ROwkNTi>4{z(-mK z)96PM)6~y6W^q?^dz_ZHi?8)|Z*ILuf!L1eAV#fWSYuY$5bgCDI&Cu~;gU4eQ~{P| zPS2yv;6-0h@|3-=CE19O53gX=^53_Qxf!Xg3%kxHr+Lmbn15o)RbXMBg4EfUer~bJ zbY+pja?nJ?2IR$L{_*ZAYO|&(uUeSpA+m(xkPLQ+`~hP*46W|y@G8?vwQT6B4^@O0>KV-(6gH2$a=U8%RGjN?tezmwy{MrC9UO%)fu>d-My}p;4ROzd@JDusUI47x;Vk@0D0WFa5=xmD$LhowtWX5Yl^$*#D(uLv z3MX6dV8!`RNzgs;(e?I8xUR)H2ETU1Z>Uk4X|L_jei)P+8x zkCzhb9X1&!!&n zuwEo-Z$w@S3D$y+!jnRAVK~|_3yU6H%I&VL(eG^RnTC|JVWb%O=+h<;Jb>(CU{B9$ z7e&k37B}M*LcO5^vw@0gufMbKk|@R0Qv!51B*#cJrsvVvx`cd8p?bb+F0)~sthi0j zgWmjiLaLf?vOTinrvpva0wH^GHUA64TtOq-S%2po5D#?D);V6FW$Pe)5`Ru+gx6d zimn7*TM9S!w>ZAT;F#-5++B>b1@*-J%O|l1_N}*b&YU2GHldetC(~G$waXz|;JcM} z$5K6I^9j|=^qI9TQChF>nA@JHB=vdq;U-*fN&30BJp{Yt_u}o*SQBFhnEY7dG+$n}0rr zjB|s^(4#j@watbZ6g_`)iI8qO;TdEN(h@wbj}iw___-|nY7ZeS@91319IZ#FbxtM= zh86OCRE})4yxF>4@j)5lPMC?R1j<^g8W-g~8rXM7=IJr?q12jwC01&{b*&~mQ8o;E z0eNA}BJc-jiD5=trkntCv*|2NHegakw--4P$-(qaBovuy33DH#5EPOJGTi)={%W&~ zt+I>gjpCLO5LCBXTmeeCJY@@m5TjrF?=2%_b@t;k4+gfz&6+|QT;B;YeU_m*W>~q+ zYKMbltIvA~?h6T2>s3be2H_$lyo?}Zc1Hxz?0NG$1hId|#09Vun{V?^;0}M{TXwnf z%nlX8oouMSrSmD+i@X`mX^t65@L;tFcCV~HrwMq6%4(xQ?qg7p|*jWLL0C@N7#nK}CW zX0g6&2+AO=8jWONH!v}jXSFd$0@{W`DSE?!N@j$(Q!qzHotq_g#Yb?U1DJw@rX+3m zzD!In;QXE#{seodt~1U^4mEUj>ir0V!F*>qJdW*bp&Go?+``^~e-8Q&9%Mq(+VxEPXXM zi@!XD;BQQ2vRs7*cw0TND=xa1OW=((WOu*)via+f0476SfFY{EbJhG?bLjud{Ed0+ zQ-7b$f7(ieEIL(kn)C4=MIk&V#PoKGYx4dkgL!1D_VHoluj>{&nCqA8&vxx^vThlh zv**eBElK{`$Di8BW4{m@T$HD9Z$|bW-QF|SbtUr-xrJqzh6mqVALlJp|ap$-Awg-nF7FG~;>p=i=` zNRfTW6+NYV;Zk91pVnC@Mg$f=m9<`S*%!`9vhPBeNK0`-mSq@4G0jy(BWi;wy9*Dm z;IANKZzCOmfS#Q<=W<+>8D~xH&7>T_oh*&dW3vd=V4yy(fn;jgBf8`xLXlmy{w^Lv zv(-PEy`hPhjVq!|`|_TY3)}9dBEd<<9+)t%BphcUhvr&pgzGMaWb5~d8!?HDYD8*o zHzQJz&05TEoo&Q-5O>mBkaG&oLj>%zb1ztrarQ z%#IvpE*b^CC?3!Z#V`kfx9iy!R7@{=l)Qc<7aOOQ+VIn091M5DNZ-SK>L3M`=_H^@ z3|8M;%&!qV2-^{E`6QI4DtJ-Sm=3qaY5xIn`a16TDVDpIqEH%s_y{mSG0T*3rV|j= zsv6ZhSh=!hA3@L1j+qj9PUtyq$85oD89uhS$2T}&>o8GWHhb9EqR&U_LT5)Hq34j% zannUUzb-fxE}aomreihl@w%?HSsXPNMVAN;i|J88R&;jcw-aIdBLerH&qdGdHGpPzO+p?V$BNSi01`2_E?Z&T(MQY4Uoqgs(S78_j ztoc1o$+@ELV#^QP3JuqOPoxI>R1*DG@T>N6BYE6z3a-vx#i2w?UPL@0pp_HT!pVwj z#3PnZuD7c1u|z`*Z_q-nsSnL(d$6hGF*;^c>r5LQxkGQeyiwlWND+h@VwIM7z=ikSo-$54h%-zZW6RB@&;s||b#S_`hc$E$i;OG5 z3mwby5EsB>gx7rq(I8;|HUTab2r?p+-Yu01I*^w2RnWKq0X1`yWmtYO9i#MytXoK4 z@0RDrrH#=iM%0pY`=}8Bp8d3_o;N*UarO3^A^8^?|FIMBxBko!y@pAZw?e<{zE^Ir z@BE?{yyKS!lW4~?1<7YT_R}UpX?@5Z3wfEoz#Y?mkYvZh>*K#v_MWi(-lP5Q%GBCT zNsmNx0iRmA=?HS9c0BP~Ij?UwqLg0HHeJLFKZmSXZ*Pxl^JXs1Z|T4g-2mtDu@2Ji zDTFHYoR+mQ%#F~H2~EvR0(B59i#r*Qn;L>_XJ!e9YBQQF zch~_Jr^2EHyw*i90I~M)UueS^z-jww6uHP_3!O%9Yk)9mg(okulzVGL78hA@Iv2MK7270{tylO#yi?UKp$UGs?N@BT~2 zcyw@|A>*U+Z~e+$--Ei9V2oN_=Y3ZtU_MiQMiboi`q)0Wp{WOC8Q%T%lqg-h5_<nSLzGYayU;Joax&ryJ8fANj>BBk-$l4e*=Zr^zOypfd&tK&)k6DnW1r?(O zrF|u>LVQ@cb|I)TL+#hiC8zf?bcki_>M~#;JK^XYIsF``CcQy<%%@=4vu_GHz0lQ1rYXm z>|mt2^_evMm%#;M=a&0=T8m@noxWa%3@IR%}iFKQfYBUQ_ zNvST`?E)1e71;AMce_!ir&bi)Y^vof@i9wHm?}%RXC#>m?couo_D5~v&3IbMd*YSE z3Yf$Yz6MD8?o9-<<-ZY3@aov^Ae-}{xKWsMFsQFE{u8~9_rpCA3|VBlv?SVb%MJmF zt?OY5Ifo-CnAjsU!^gWOko0`Rv&#J3-u7lr?c9E2;M>V?sOxxV-WR6!0seLdYaygT zaDH_qS5{@1>7b>yg~hIn96-e~-eE@WjuFbUD!R?De0hK)Uuzr`UFFtdgcD~l+$dFj z0>|5l=+9pG&X^G!T6x%SNMt5&hS$m)=Q-z6$}6j&?qjS*yMznHh@%{GTz9@=+ac!E!@@T6&NN?QG2W$O zE=z?uy`Y?1TnA@Bg5~E5^wE`)Gy|=|B+Rj?NyLR&_S1wta(!b>Y(QKv(bgjsk_^Hheallv)Yx|zX?6dlvD}>JJw9}FVE6A~Aav--%BnS9SIv%o z2a}=lB70!=wF?HF8)u~Q*jO!rPS>qx`!OA8dm=2~y5pi$pwBZ}LMGb^imW?%saXwl zvscmx{*-P94s@fnYn*%K*z=!6lGVCVB8#M7Z%CgRbVAY?WQ)pnK|e#wzUR$! zO>gp^fZ=?HZno0x`4Tm_kWRPYz+Xv>@Abnrn`Y80*BYrQ!lbCj=P(}2=K*4RD( zG^lIoQ&joGD`{iiG{%Cem2O5Kw&*fHURId;CCa2gfWf=ZNfFYfLca`27rqORKhF5v zhTnj1;A=8MAfbX21&GbgV)tNeEl3sy!V#jnW7M9M5>L)q?dXb zv$8S}1}Eu}Ba;#4k)Yz*fnbBeH1+e~eP5CC09I7bs|A!-zshgPrj_AF-d{f;C9 zR2J(uXAd+X`zzKIyPmd37&`=Yb~}^CR0TnF<;rsop`-A!cvu{gVEk&ySK5@K_Ah}} zwTD)wsr=U79$70B0J$10wN*C2gEg2dgm%N@QMbbQ0Q!sgzD$79gIHJ()j>^B7bIZJ z99_BcE=|b74q}Fm2xq&)ALF{}-1e-KJsHZOt|2uTRF~N#iU)W|A_XCQFsg-2-O!82 zjV#4ow#kb|K`IR`@Frz!0Hq0TUGH1nqtF+cP3Hl3s=0=FBhbVjI$-Q>Y*2o0;52@`5?N;M~AX03l%FOIOp`!nFVbp6#D{T9r`j6nVX^MZrqHs-VK?a%*P z$&J2^JoPMO+Coj0{^zpXzbx6YEJMfqnLD&!^81p!Yz z9Plid`;>ENPRgMC);FFJ%b@mIq`9v}#s8wI^JVbxwxoq^UM+)JX@igB8K(UL00AY& z2^KQgp6uwi!tD{7j>P~*9^f!%qkLoD*sr{1S(NdxG-|nD5(%IpP!-^t5H8k*Jo_#; zLRe;gP_N6RhO`616v5GT{raT7*zNc7Vu@Q_Dirr7k%8brGx+QAiO{)QRXB;x5Xc-8 z2k6SrN$dU2VF8&v@IJ?+=#+QoLPd%O1zxj0R zHLE{5XX=7EQK1z6)Ta})Y452%-0RY&FFCO?#pM3Z?WY5Ny^n(!ac}6)SPey}$NqCK z2P#`bCDudQqn}8OPCsS)m&E4TUj1BYo&>lrG{ zx!dM8Yq@+tAp3JY;pFNvdF3zn@YP4zKMAh>@<;J+MAB}nIQ)sv=5F!x zD}jDWc>Ts-?_#%OYvITA3WewDMBb~?re~&^T_i*t4IK(Lj+%a0nOO3~>SV9wpitE6 z|KS1Wll(ry?!*;dc0C2T6K|}Z0m^nU+9<=~af&+pep3Z4WY%*s>1JV52l3Uf*`*kR(wf(4(zSC;`_qnF-N&q;r)8Q>`Ay;m_}N4& z+onlPuox3e(9q0)u@hqf{Ur#X;S*?IEV({^#C1o-uKN5T%_=&w{|DC{z8Ve5P&p@D zyVWAS)}wpnAgGz6r6O^c^{0ftL{xDij2{Z*IgN5E-ZY@iNDkG~YTA845T-qSZGw-_ zYT#i$r(&Gg9mHlIL|ug{rLjxr|TbnsZj4<&V(o4%NSpZcb5m?oF2m?` z!}snoOCcwN4cg7~Ndz^Yjgtc1LC@W0H(*sO>M+Z@W0Nq{874)R<1hb)|6SV)O-VA$7vuzK-X4LzW}$FKo3odH-UiB~oD zL0zsyk-1%Jl<4ubA!A^~>3{?Bhujg_`zCCp`QlO&E5LuGT)FuEixp%D*V?YF>%$Yy zA_mZ=^i{-nY63qq)qdZIH>Ad{sUtRGIen^HW%6I%DT{LdDR!iIwJCESWw>c+4F8MF z0lPHeuuO~G?B7ze%my|`fSBEm{#NbT+faDT%G-Fql=1`>TRikj@5dyr%MLs=Ir9@8o zfeck+TOQ4dIAZ|)RJto(%r~Ze=<3fAX&;Qz|Jn~bDIn>p9Do+ylE=avNLA-h{B!^5 z4x$Ias}~=y5iy&op7aoSKA7SFU$;}sutfdk^iH@+h|=S*k8&h_#Iz^Y>38@g^Gzyn zZXBT`lR(4=Z^}RzI*0!O-wVpWY9R0G=;ro(0Q^pqbu$V1DhPK;yT*d2j(XukM4 z$>eIpzTQ4}exk15!zp~b_LcLU5}Of5z@;vfxvNI=^&Q}#NOz)`CUQ)}@Hx%=2GgM} z>iuHa+sUB4M#`K+W~l+6M%!!UAfD%j4{a>mOd5dSfpEuwV_=La`Qc5?^qja^GdhOu zJVb3vspqCBb`brMl)WwE8IV=L;%^W%@luMp0Vgo9Ny{SKH6( zck%&y7dFi~Cgz=qPjVTJz0+ez+ztM5wpnwF_>tziu>5NCcU9c-hb6UBhlm)6Q#M8z z_4w13F5!tiP;;E1G)5e$;B@V?A*BRlc4VdCHqOYNOloC=Sl0k+S7R0{PDorRYan1t zG+FA6QWh7$OZtJM&D!e1{l<_uYE1^;?;t2q0y@tVDN-93YX%>-&AGMkm?R@FT`!yT zuog~cV$0j86hObi4fRU^AN$g{7xORgh6ZpZ6Zq?RzP^w}agsQY`K?<2t~wB5s5D;R zhhmL#ONF78wJc?B=efcjqH36Ud6VUg*BKntl`TGGmde8(U7dMFp%31v1j~;J2qJk! zz*v9=+YwQKYRt#`|7kY|IzW6});wJLW8bVl5qnnXR%ZIG<%Cp7%|A`3feWO&l1@LJ zJ>k3KkI~uNv<%>!BWF=Ruh9(`R$1fhS1j*S*pNniMLm>k4VAlr zF4P;YQRlo;b1BokNw?(EvmY#9~1QK<_RdWmc17%w-D$Ztgo^}}(yWlvkx)b*Gny^EfxP)bIseWB1j=8lnyA9_YU90* z9=@DpU+hw5LRJ$RlyW6&v*^#scBY3+wWdz)=0lHU*i#qeC(Ut{dT6t<7UH(qhg#UI zoQ)2AJHwgPETle8YI+gnxLyGdxd-0sQw>c-`ZuKtqFM3Lc%R%KAI*Y?uBOxv{gAjw zBBw(pn|cqAod_uWa{-n-&$~UC7rCRpYLan1^8s+$6qL5|Mnz@mLMXB$UG-WzqZ3v1 z2=KkGxa(SWl#p94^ct#KL}7iO=TZ=P5Bt0u@#vPt9YWyy9GZ08bP{OfVFIV?R&(5x zxt0NpNN|G2^`|%SZ>;CnX#R-TkYr6NfPRZ+B3la)1eRrGgIA$MG2XD{J-Rz>!;+rC zz4P(%=@c67i^xWw&H-`BTKC@cDEpXTkVN{hT(g4(X$g!?PSxf(4e{7Od2~}305U@t z-jyx{RDS&1=(u!WWe@HSJ_ThLGj#PD%P?b6`p+Xe6eG<3eT>sXexSl3_>kOBXzZeU zm31vtWkawy`LRLt<4(wtefEs3WY?!meOx0dqj&v_gg&OH5VvQ>ZV7?!yp)^bQC7k6 z6EyILQDv%g=$94VC3-ibpw$FnPrN`H4OEQ;sH{V-py#=`u-)Qn zkZ{vr2>@F0c9tG6|D>+oR)>}hS#SQf$`)WG#% zlA*L?*jTCPt)sO16|1AZmRe1HsS??Ox4@Q1yW%_81^J#G#whz0$ z3E4rDSfUq`X-nmt1JWbbP@@aA`bf~&rJtda@9R=mR~9xD$Yx%bLvl>HxaUkrYFdNl z5I0ILD9a@5N8ILm*JbJbGR+xpqsSL&D;5^SMviD0u5}$DLx(|i z+FvJiqjh|Yn;U{sOavN;lwH75p&BaUV{CEo7>M<0Lo7@yj5RL(4fMQ6egmopLVV*bMZL*YYZ`+ECwBWj zY4mqOo+dN!ysoo8A+1yK5+ZJ*{qzd<=KL(nRThZ5(85#`FI8MEN}%SW?<}6PB%015 zIoamIp@$ft#NOE!ma3~Ftbbk9%5Zau(X+xIJKB({vPaMaUd9p3bOqB_t{gXJ)#*09 zYv_X5aOcH0hZsxe#0>3~E7e*PSOH{+8u>9|Q0W*Zl1kb1X%g95KL8Izr`9wxRK`pQ z7T78uH%(7)z7h0<4JbDvGw0Sn9mJ$sqAMZlQ2(<)IVE%D9&j+$Puxc9juCh4(~uxH z*6*sC2jiqd5#xCoBXaVoFj}A-ts|;ys@ib_Kn~xpw}S)FAOR?tC~u}wl@bEaPpJy% z?+N(Lqj23)lrZQXf$LAx!Ub+x9kJpnbVxd^AG9X{&i?I&OlcH*uo12Fn9cZ(kg3wq z){H5ZaB5*~b2u8_85{x8!qMVORz#mqWKj2G0$^ccmu2j|8u{?q$Bts4Y~c(}j?*)W zfwYpL?piYGo2e`Sc`YdE`Xjma+Ek!_ysn9fkRRO(Ym+vZ-<2q_eHC|Ai>6nuLaVLy zjp-q%VXpbje;0T?0XegB;mW&x({uyF)^ZM)t^Af$e9`da`-Kp~V1}LP1HfvX2DQ(ZL(+e7KHe&Pu{h95{YV* zI3RyAIaS}5IJXZZuKM&X80(}VI9v#&Z@~=J#-t*^v(g5v`bETk z1s%Eyu?{bj4O-+kHI{G=vjAGP>D~yXlTA}Y$YGGVUw8!))>D?gbYKplTzpr4tl$=K zCK(XaDEj?x0Cib4H$p7x9x9|MmjvErtq_t1kk_*@dM`j@^4ggxxMY~|kM7>N@-ANt zc4z6=3WqR2%Rt(m5h{x1v~SrfmQI{c@9EWZR7)ni&b@_GfcG?CudeCY07>zcA`!+I zTDNJfE@$qhK1E%I8Pd}v)*mCjN^aXHrm{m#XBjx6Ea2e{%~uT?j1zMHopCo=8`VIA zU+FTm+OPk@T+CMgg?@SfYt`I}osTICQ9L3;{L_5rBJO!x-;fO~#~bg9jmXZsZ0>Hs zFuEh#{IpI4)6R;#fhGaup{RUTPs;zr-kZlYeP#XQwsqQZrma()YTck!mZ~g8WK)t% zTiO@_Q&~i0NfnSnfD{pdgd|Su)WHR6SRw*R1p!%8!6dRIv6V%Lkg_F`K%#5`0z}A0 z5|aFGu7NLn&;8tc&bjBj&pGciqIs)85>MPrUM99D&)KmVJw(P; z(Aa)efuHjc;0~CTk5U&JI_pVJq}Qr)i4}`1*=&Jyu5=Ethj=Ly#!r3Jb^2kDL^=(Y zjC+WRGJ*{F`nH}6oJH5-^>5Rni<&Q{!`k80_5Ijecz_N|@yBBT45}HcPM8aifeTVn z(ObiN292A&6ju}A;r%66q0AT*nt$@PExMw;$XTtrt6VuD2)Jv1KA`}0VbgMR%_WF) zCT$waf@hEUXSsCX=7jpIlTUgTOesDYv&{~dMdRJ4@Id`1)WK0+t)@r6p&2V2El8Rl z5<7t69QY(nh@Z=3*Gs*QcMVs_YtOfW7?YB05~r|YP?{-yfw{HFLo((i#9d}G$cu3< zgD_#Q;si2`l5Td!_5){(@*8K2x~o^P2?u>g)pRgqkjC-^S^U4<2tCk<)hcah0;|Tq zddxA|4<^0C8K|5MQ0HmXS17GD%B3wbn`OZ1cPf}?&RAwCMY{H*X5+|Aj0eZVvdEc0 zc7zoQY84XECs~SKnCkT8vTE!AHY_x9GgDYsTTv>jk;~0T0wPsx7?xA>*IX4FZ5W+Z zJb_HovMRZozO77xkk>GjB0K$IkA=VmKU<9InAj_UDV$51Pac zG;kmK0;B^ElK*gCDXZgHf}rQ?Lu~2s{e!T6isA-QT|Colc|UF394#vXL2=w~vI80A z-YDprAgywuin>;I)pWLZ8pd)7zoYmYG{w`|Wj@;AkavYgIBid-?cDT}@x5_= zn~T+9b;e)P&!ZLJw_P=YQuioOoPg6k^H_LVfnfR1ImWiAkkoIAHf=`t_M0kk zY9y=3lXygi<-XB@;Jhl)-T2y4Gx6FLf?sIFB@k@T&WNExA%InGFp(L%Bl;I6RHeKN zxJf7Zl|fk2gS)c3e6f2q-k1W7SM>5OG(jWuuU~7rgAnb;DS?AKHCA&Mh3*$b{l-ZV zC0h=9=!SEPr1auSs4gwLPICNX=fPB0aZPb8RRR;HH@la^v*hCR?6~9vhkSxBoUamJ zYi*E@XgD0@A*loiRMZ?^ac~>+?%532_1aV!E|GCnEjIvV>KIIlZ=6^2UdBN=!=26)%tzn80jR4AvCGeFo?Go~nl_#dty3@D?cuZh7qaUX2UDZej?a{6%_1 z`Ob*W@=t?q=-3c)!eE+(DB4hcHwAi=o#i55$JLd^kA(m;IODOZ3LdE0Cc`Q3!(!{9 z`tS9hED8%z7=a$neyrTEGkVaCra!CebPtcxIS(L$^_6%B<`8HF6})yK7G|Tr#Lhk# z51fdCX2AI9=iYWfd~s&MVvFV7hF@{b2- znO)WP=u`VCvBaJWJUleew+?^UH(Yo#ArGR{M1zO^tmc;Mp9ApIif=uy34L{HE4?gK<@tSo@T{WXPBB( z!z&W#A(q_hF+Dg*s`>yu{hMv@D|^6K3bsv~rqVrx@^}Np33S~JETHldB}`C4Oql+kZ#Hl*!J5p2XJMkw9CEektVmB3kJ@AN@$ zhv#-U=N1w~rJc_99R-&r2i&mDt^!?0h*ima3fdCzHn}nxDN)Aqvp)S^zH|Bc25cB( z3J;Q|+EfQyR^pJnAghkr0Esk?@|&_MQJt=*XEtybl()}lf9j*T1A>yRkN+NZ1ViX|u_rM* z(5%R55ukhmW@oi>Gcr|PU1W8o-}v49$VxUVzMk=^UX^@lr=c7VleIuftYpWxkwL85 zn=S{3cxl3oOHUc$+A>EKHRK}Usc=^=^*b`dFjIrSosU|_N+zixAf0CQs#<`_HmZ0(kxVm-c2FPvHechw4-_T z4j5zlhR#kZbdba7bA5&tDB;seDb6l7eJ7m6IuWFBEOOuT&5 z%JO6aiuWZrDy4@nBOVl}uBfX&BcA9d4~+&D&_z29!(7?$`Nlzc2)3x)1Ih&eUA;Uu zJm!s44&wbL#f?%;Eg>L-oS{a!|_k~@n}7iE7R zW5m9EQuo0y=1(;Iu?P{kK4~Da;9(UP=Gk5e^(VV=J=1P(`PfRjmjWDdW%6Qg%GopF zsi1KDa!h(y2s!0pkR_c12xUV14R@IyeR3h&tb4uLDLklp8){pDrmQtKff}Ocs&Rr8 zr^5J59_4O}pha)gR9iZ)=Xqf?58lZiYcAKZIu>fXKV}ppz>--Pxo)1~*cz>Ax(TNQ zZ~%X_z=T=>p09$iugOcBc`}ITHaLWhGxvC{sK374aRH* z3+?2~Ukaio-K^`_M-#LQ%KTIXGt|oV{4tp9y5>+~_s73YQl$-g1Gb9M{NHK1FlYai z9?3i2UDy}6o*I(4=9EGD%1q#T)CTD*Yu0#Cc@r5MLppBT++a@T@h%)Xn~2CFyy{9_ zoor=i?;6q{Dr&`<23~Ec(8WHk8Ei>9obcF1@$u%T!A0vq)-?n8>>*LxJ0O|tUjoCcdv|7DVF1}xs_v=uK(t7^b91aNBeX?01uuoDYC#@eQcv!T>5hSM-|jieW9%yM(mlQM7KI{k318=2A(|*w-t~NON%Aw0h$}-{-%h|MEY6<~jW0 zg>;Y_rDlm0+3LgkPOINjgg-Wz7Yle1*5`d*I8$QxWX5j$6`#0uQpl4D38sr~%!_vV_wz(~lbGlS6k{B7(DU)|x1aaxURhB9PU%xRf z+*ieW8nR(4eJ-Y$2=cN{oLT)!V%7@n+}R%*FK$+srIm8v%MXlr+j4c!XqrW^SHFB=N2e$v@C?JIcJ!0 z=?Cs=^5FB$rQDp1w;zF~*aIjd%qk0%phIbn?q7n=P7Et#pN~1i$hLl^!blC;u8(QC zk*7M|A?1#omE-S^Lk7s|4*5>B5I0Jg&xg!-Ug|#Xa;rb9b(|c_k`szy^+UFTN;DIbiHMDMD-QkneMxS0)_Dp(zmP%Roe8R+3bkyZmTu-+*Adt zGK&juS>RQzp+r6@n$9A7qATtSOy&+-^R3m>s;1?if(N$91=aC85kK(M8Ypvr zvKaNm3;Rth-ZC10oJtL9W23S)9}w595e>wYuku=|?Q~GtYoq(iOHqG@R`a%PLd|D+ zD!%DFqOsmY8g7o+KHMM=jSI7ySU!L~jK4FMkrGqa8A@rC2P^&{cg|)BPS&rj8`m@=9xvGDSnx zBaLjqa&rBe&kJ=A_dTD_U%H&h&PeKh?dkHFGpbsr>-{tz8R|hv;yaUeNAzxs{grZ6 zZn&Ygywu%J(Uy^((fHmS^(Resn|A1V?1o}G>OGBR5<)bf;rOK_)C}6{Bj)XButnr+ zoDOm`OJS)^`D?&7eOfu;b}DhuQ6xSTZgryIz&?_s|4Pn~EY+;aJ%TBNCUWc+c`Jp`Ca2 zN&KY^((5_7HlL;!(?3hTx;R5lP^RTJP)cSZZ=H|g$4uJDBUKSs&-Q!G8^R*gJ-Ag# z#^k7Qm`@g(tMls8-GOS@+0m4$@SCX7ZrY!sDTtWZv@^&}aj=IY1xOpCS&8EWVOq`e>u}d+PcgkUk36zx;iW>8oO=S3_a5 zlKt$3qOXLs(%ny1Yu{&t5c zFV{A^^{_YQ8=8hcyLDEONNTwdPm~d6iaM9##OR{*;`;sV4yZ?(SsZOkaQ1|MyHG!T zTp(y~ZfQTmW#okF9a$qA``xlUuo;7=j7up}pH0BLrKz+|Z7FXNO=S-wgGv z;_qATpEmA|;nq*!T5Hph=BFh^i9se~0swjd*MlFZhsvYzgko8Pl_^RX1FI`TN7lFr zpiT}_ulW%Ph1WR(zXoh-@MqLikiMX1{^pWuIbI?cz9#Qn{P?u#^wsrG8aH2eGrXb| zZo0*mXS~$SnDP07@DXh$(Qrq+vHvyAWf}j1k&uxd-a&Tq0B5k6@mD}jVeG5BiPr^F zmk;2tUb#cVCtmRp2Bo*>7@`ks#=ySGI8p~aGO-yc9K6=YY`=b21-1GlI}*g3eC4$X zRem~e6K5vp+Tf-i9)>fH7)mskcIq#I?!yq?AdPlmVtK@+r%oQ(SSJ?c7dqQGS0{Y} zlcNvVbbOFdDr%6k;u^Ak%P}$$JvWIfIs>=KY_2wjg&qSqM5g6$=q9ll91B)dYZW@~u@~to zc6F7$Ep6(Vyc;(+5C$s02lr1qXT~STao|_p6CIw_w~RNSPztVVe`JFyS=$Rb9?dxV zF~IyR2&HYv9_TnWHdGIl45Lskp5kc919nySY2O^nh88H!xMoenC-_&dKVSH^g5Z1`43M=-;u_le$#98A zd82VAaU_0d_gMF)Vqs$EqY5VpfM=bRPLu!>Lf$ap)0uxasz^1l6IEaCbZAI$ha)^X z@_0r^?uZ_N|1|bUFy{bD*J-t}EREAW*0Q+`uYdpaSjZlUOAms*)E=mzForMh$~=;F z+p5DKL~Y!rN9JSjLW_D@%Gr`@&E^wG1tbN^qAF;=E~07y%KzLXG0{ zH6PDv8%WHKh1fGe8d)Lca)r{xQUw8o985;}q{ zIe=4D2z62|SR)uU)c6sJaGM`Br#YBnRtkS=@+wc2mOm9LRQ&ZWvlv=rZo8;h#G2sN ze>}vtp7e>tZ_aFqAbcSoD`b0pf^TebGse4%E{39ZfQnMA9)g-I(fLJAyT6*BV)bFR z4-j%&mV}bdNxAqyn0-Zd|+qX+yMz$!f7sf8r?EfT)M?{G=X}~-=#t3m7lcN- z8(yr*aHKK@6GCEe{1q@7gH!Hb_&r=8#nnS$Cf%&QIR-zcrC@6vcZU>?70rx6H17Dr z^VrLPBsBml3TCqb&(RI&YktoMCD4EpC#%ymdiNWuDk}6l`H*1q;(O4sF0%OY3GD>a zO5(sBW5xc${Dfjn-573@VICP3P_F97mtY~ zy-Co1U=4gcIkG>dCpHbrK)U*Ogws)y(CB98Zqz`S5)X3Fxc27Mx@=0oV9cCHGvSpl zKoLr`Y$1H>$~G3D7xNp`cwWl))eCJx@VzVgjCJyMkdJT||6XTs= zF+u*(3DCG@u1D(IU(-|a4gBs2M?<+)+<}tzpE^SHjr?++{?A|2c@y+n)-UqN5~Pg2 zl~u#j0C5b`*3w(7|CtN;&eX&@)o-du}40{`+1 zetWT|>BQ4pTkCHhwM6SdYky3Yvs6+^=;P6gHW^xmb7l{K8j!e*{^hni@=yRurfGUq zy~$NT;G`i8O9_2p?n>{@*@7|6Sw341>OBpwYWUs~F>o3H0r}urhq@r+Elpmj9#@{h ze|T3H5O~$Z1GReiD<+|?_8sNjsI5c%(^lz7gjQTQ%N%$|=YggQgvxX(zred|Y%YWf z522!@K&(UxC?B>S&i6a{CnnpxA+e4sh?4|moX*!{-#0979TVJn&z$9E0NO% z^+V8lRft~jYT|&t)Jgf22X&f%jg0kGw6VHy{=}wJe(HH#_7?6wVq;RU`=`3@+F$ml z7Eh~$_9szdSINvRhIHC zCgH*-ZQr5RW4)?DYi&c@zV&oDIzi|0s|rGTCirK^fT)1xla$c{v!jX)+p)lSridaJ zi6#TdI=V@9-)-n@UNN0R2RHm49*9KtRPsK2K2XjC<#gQFX5$Xv5i_V$73hk?VK-sM9_Ow#NXQ&$iy4>2t-!6mftL90^3oppz{Bv`fm| zH!}^x4eYFkI3g)(CP20$KLxJdL}!7tC(nay=_(IRY`32X~vnkULUDLS*dMI}L z<)WQ~u;hGIf#CMp`*lL81n6coPy3~^W#w{a!@L4cUQhYf4zAM^i+KV*rgnh28q{PWvj^W+jT-B! zl~)Fl>CH9V1%8@ND%U)c1Txj0jW`tumDAq-=lHI`0^bXZl75U&{H_9Js%NNw7bjV*L2_NZJ8Eykl`7_K50@VcKQro$Ze`)iWY5Vj$pT;DRtBMiZnH&zeQ@QMozNXXHI1SM)|{o z8bVSO@dzGt6V@h8a`gk4Y0y|LeMm2Kj`0MsI0s5Bpb`vW?F`AC2gf^8Z19Vi$%Yx7 zDyCbwrLmk3SC836vV23L>Pjpzh?#1vo7*G(kQJepS$fKcj62mXD|_pTc6ZVZpKUDYmDVLCcfz$u&eK`lvsl5h&<4rLYZiwtWV;lxT9+%)(>UJQ$3xq)YE99 zvuY2n=K?#w2`x<+PG+&~C^@zA^|Y$V$H02JvWqzIDv;W61VRi_8{Dy}7OQZU3svuq3#>XuXn4eK)M@T3_N2%ml-CJ|JI@ z_UhxD9Aq9r?Zpm7`GoP?3!EagC;ef+3#}sPO8Pq*Yh*LF1be2*H}jJ#L{P~!TcCOH z#s#P*y;$|V4F#tOR>3DR2}O{^0M6orbX4;R#pBumV}A;AU9AZhxoB0k3O; z*Iv0jsx?>_# zEqD+UxbI>G18k>w1Mjq4f4{oQ0~N}lw^zu1C^cU|{O>Pz zz3x(xls6n??&cOC|#-X#-SYZ<)GL%N$2JI=~>90 z`Y}cUaoN<^YHgf08BF?ajvS^XZWZ0HzE*byEdE~Ppy6ia{Oim`IG`Kqhg^C_FPj-$ z`2IQC$eA}JAoY5-L=H2I!L*Y^BgbIMP*j*`CP~={m|?f*#8&E4jTcN#k<^16Q?F^% zWUxUTHPm0pHNXi9>J|Lx7aYyE_yH)nT>bP=IeI5}<!ua{ zKQ>Lb0iRy)fE-dS`e)v@Hsq(IkH$M}4nq96yuT-Uq?e%Sl1QrGvEM+Z-E4oqSECL3 z>cG0Em4v-Ni%gZ?Jz!*W;zYKYSQoeP7v@p7BY@C#dJFq+-Vzn3H+8O)fgQzQMr(C` z>wZLMsYN>wc^5wfm|w()SB{j(6*BZ*gz90sMPGpE*9XfL|Jj4vVh$+{IMW7`$j3k& z1t*e~vVyJ?qU)qi4RnB=i$JbpUvt9A-l4sWp5Jhsn%c z>&u$QCx-a^xfbzN9bqH}V2TCX=9nE~ZM0Q|%Ki?bG zK1ifb*Voy-pWXhqluSGyU;K)ViIdTVX>v0Ug2@h&j8rta40l-p%4MZ~OX)KTu3rUo z$v2Ztlo2%&y}u^L#Dir7h^ae#EXpk$5P!1nB#--m@K|7dBLH7#@N2f7CLOH81KvJw zVJ{(c&hI-14ImRwFSe`cv%P)G*$&JF@E*-SYcr?cHZGxfgjV5ge{dO09U{ucRtdwz|#56_J z!O{W*)JYlAlxtkeuTS(N&Y*>-rZcG|Z=R55X%E*Y4CWjQReFaYPaj^#q#PU3DUZvO z=iaIAHs3j?>t^EYV_GL(PZz_wESe@Sc-Cgq9&$4*f#t;~Tkh#}o| zVwwzNR81{JH9t5X2eCT2d!aqn9n!m2Gm6jFR4Va=5+pOm^xjR*BWgB@jfUe`jShhXw5yg>H*EsI>VZn8x!}vfv~q(!*PZ z=)!=)PVh2i0?j70tM~lTY}B~m#Hqv*lP)k5xR zU!OX#Wz#7L0Jw>dLyA!2EHKWeZ#o6_tfNC4cw>c58 z?#2VgJYw+^(_kKsk#a|}5tnluPKmGaKq8u28`T^eF#V-SrgL`K;EmWP7V<$wEY548 z6Lshz4Z?CS_~l3qxxXIizqq(Y8?1FkmMPOTS2j;IpiBoaGuR((*ImO3cXxhmJ+Gs^ zItvD^?IL}_W!Q4Py-9Gyu?ftjphB;=ALU#O_-gtK4lWu-H-H|zGn*snv?$*z%=VVy z!|lat&-{zQq!WlAqqhc8JwtqEl~FMfPGbZ5XwjgXh)3viG^x|n3uj_O6F_C#izOQo z5s3)pCvCAp>7PrjO;}OuUJ(FIR;um56#)I!FR+UGPetlrCiEQomtVHPEAW?o^%x)1 zeZl2mtvkm%`Lib2^twx!cYpO!fs0^vX4Ws+|93qAod5q1Uh)#>(S3{fwVEH6u8RwA=o|0VQ!AN=VTFvBzw!?p^D*h0684&-YP&w&c`;sZ=l>-~WYuK+oA2>Yjoku7Q!NvucVUlJV z!8oprDRU>vI!rT#l9dr?sO4TOPHZUlBgaK|fj`AAb&>g`$_uGjHj~Qd8MXR&R(OQ; z9nix-^sluzW=PwU^b=PHRWx;tg-UdM^1@^#la9iq%NIUjNJO^13kFczcE=kIGhXc9 zhy!Ux3O+2f=I6flZlw0_3e9GlqmXaf0tjHi8MUkTMRooG7~910RT{pAEyrLi@Zlr^ zVy#*Y#xhwCCz(h zP+~3}FRr$VX&b*@ItJRL(Q|fYCrx;LO8rocw+DbKN=yRFPM2YjfltEGi|{=v#5GJmYy6Rxx6Dty-vuDByRp%A0=v9E8>{! zA`97)UE15jF~sW_?8OQgVvxJ%Mu4c(1XqVdYuyw0B&ZK$`mP$iR%3~>2;YCI=>G&Zh(9| z=u0Z(SJD%@S#OTEse)Km|lvpi-d4j&i%quQA2fRZ4fv zSGQVIJc&5v^Ii}!Ww%+RPp#I$)5!+D{=-4d+D}LsD(2EC#>gTXx+S^=j&4*y&^txg z_6D!JrbPDLPzO)M1`rk1**g>Tl9#zT=Y~F2qBb<;-xBCUB^@I2OV4lY}F1++Y{?cSe3u&q_b$D24h z@!6v#7zgK^+k{uoBe?4A3N%xr(`YI<2tZWML-Oyx{sf(lXcwj{gX{^ z8amV})(9X6`tOGA@f&MWGVV-E{AR z#460Lbwya#tUv^uvWU*I2QqO5Y#RLDXUG}vwsNvxq7Algd!&7b)>60S(e=Lz5A>8S z%#w!vUan=zNC#zeWRX4M51N}NGR8r|6_^s(>f?fRnp>uva-0zALE6*H9IeKvBHJx3 zMoBhjvaeAdRM|CG#Sc~3DRs`un-6o3b)D6-N$(z_dL`WP-N6bjdB4wAKaJe=sS$?E z^uy2hMlz!_qU9dht;xHPlG-^JbmS1UlOuLp$BrL!0Y$yw=(NuZD)mY0AJlXp7<_%6mtDa@pOWLBkfJoxj#pqCJ~bf2j1 zHqR){a31WyEYDN%m8MXbF*wo?qx{3OqVlnKPR5ym#d}ig)%Mw^#AzL980r<+GzQBH zvJWXI5Nx3|75FwzCMq5tfy7%nbpG_SXOnSswG{(%=?I2YOO2)K5asF=mnMB^T$DQz zwcOj?4MDzyl>&P67PhQkEmWZv_#jiEX^NVyqK<&zTC2y=IcCnS$im>yB6Fwo%k}dd zP^pGj8 zx29vK%oBAA*+Jx+_v`Ty60GnGo<}p>PMkH5kuTV=2i?rI@c4r4_!wQvjo&ypwHHqF zu)E;WVh-t;>Ya^9t@)~qJop^!dk)^5Kc)W~wM=zN;izy#-5wRU}86#VQR6*enM`k@YCa z8C6-!EHlX59KAa z)mn!P^_36rF9&FfgRG3nv2%>kKgeXax*|VwWER*huLKzPl2$7fwgls6JSwS2k#-uo z)z^2ub!N|kOCy6t_XcwiF7J$Fb%4nY$r*_G34#6L1nzNPGj+D?+U}5CB01$YAP%rp z7=I7>p{cDwm!jHpfSmMjScNJ!Cqr7SR;wWx)@7$%Tq{|*0}=C}AvuuhElF1c2KNP< zC;cYIal-af7OqE-O%8hdgcWiE0q~UHUsOgAAc=fLb~yjDE}7iMj2%k9U3Gi8frh$8 z^PNg=x+6=0ERb#i%+K$zZ+*yZSa)oY2t}@hGnW|BhG`k;3_Q&-HzCf#O6HA10gt84Xc3D}O zAe}C&?8XVV76OJ(2)6qN6{_avIB$Odf22Vq!)8W_?jWTDk}DwQ&4*|Qu!-(0tQ=ftdE!vjrXt2-X@~5 z1MC1{j%gYVp2_+B45rD4Yj>yIZG_(HLr1(E6C%jj52}L?^psiut(@R|MQWM(VFC`l zBMz9VUGDTt)*`G|1SzIEVCC6i?01q8AZXw;&-sY{TtBI~3EKB+}pesl_NrE1?LIl@(GKKp?0CsT;r0VZU;PB|nQu*u`NkwXyYaGDJOc4eu9*|`HW=jyqKMVz%4J!_(RZI(87zMH$`qo79z}gd zf;zhjBcPl(G*#OOt{6U(osy2}%)y(%G*+BbZz>S8F*9ItY{f1Cv83EpBz;^|@vsK31(W_za z&Ii4SaK1qUhTByW1s33|{<6xY`5Men{OmUH06cV_PrnwGA@J}LxcdJ*>DC2csa`aCZS^wWtUw#^bJ(Qtd9gR`E6D#3|W5)Q9r{bR;P6- zPfD$Ii>apan+Fj;?&>VBl)tsPKQ~@R`e_Eg`z<${g+mE0ne`FuRHDXKm(|*kg&A^6 zAV))Xb*AJ!uJw-XG~v3;`~EL>4P`2ZnI^54pTM^I8S+80s|qD7obnmHC6uO6(hhOF zt{z=ik6y=MVMli(t_e}hjG5g?Mi6yC({xZ@g|h9RnlEzkGUyD%%>VFqE^WiWY$%pYy{=!$9oNVGXS_w-ABm-czO$%W6@nY_znYml!M+2Hxvnl<_}!T zSY=3Dd^1^Pm6E=KOg3=+zpeCxyhXO_1I@;}Pmt}ZXVx{-@u`qExoUd%1Z{3M1=O;| zQGwG4AM>w|f+F2eVJ?sI?84-?fl#%w zC$uvhEcCJL-RHeo$`in#2@0!Y@4^u$Z8Puc==shzk>!!qP{d<<5p4+6OY0mm!H~4v zDI5xKx%<@0)wm{q^|qRi+WIJ6LR#($I2>DeGgx;x!P2Jl+7_J6V*bpoTCZXOu~>T5 zdm`TuWZ>1VGG0E0N$ci@as1*wz?hbZUF>}RC9>*g?3*EaA*Tr z$Z-?R=128|e$3|kxgK0F5Z4G=&>c3!qB#r&OHBslkEiA^oViT%v(^9l*^d=hm&{h_ zvE}n$a*nr?)6@X#Wlm&znb&k|Ra~DDhL|+~JXgEO{9Vpt8Rr`Xi%|By`8QFkJhXcq zd3I{uYv1nZG)F+@!Pd`Jnpg#c<~-)o4y5`YCi32@D9!xX|E5}&$FyZIDwmZJ0cN?G zPyAlYs;U^uoEht4Ye7c2(8)L{(F-CAr`BC7TLJCO_SABS@|Aus@gpGGEVt}!^D?wzJTE44YO^!x1yVal}Gh2dCh z76TMnZF4{q2u!e&8@k?{;vefi)79=<`2nH zhvSR@cQ?Z(Pluj|EY8K~R1&SisguP~tT(l}a~7J3>Isz@bvzx9+w)S+`4F2qa|$7> zD_h+RpL5D=t)vK2(5&x~Czn9jD<2_EnRje;oEW3q3e&lxNH~r`Ph9LKPFR`xooJD9 z%{DLPvs0F>_1SUi&J00KsD!vTu@9^9PN9~OSvw=c=bfVaoh`4# zSbcnjF6$uS?PckE7G@S4pT(zwRS+_zj1UxKbVKD$2+o$n zK;lAi79Vn314)UH$~!f(&RW7{pV(&K>z~-@@)6hWpz>|f1$r>bbg|r5U(T;=mw(}fsU<_(D=8r-spn7Ie0!;48EnyG*VQMfrAv&LoDeMQ<*He;jF|k@ z?j|vZ(C?OL^ZAZ-l@qvbP}OoPA-Z`;8a1=2vf79^r?eZ#l6KLmk)%MpC>^-Hqd-dj`5(;dHH5pUEk7z9Y^_+m zjZ3wlAIPb*W!aA%9Zs3_38&1t%$F>u0Ypzx+S0xO$w_X zYtGNDZuLV_f<&NEXQ|$>TRtO*S1$yAMzeKwbE1rmA>p^taRe+M#@#3jz?n!i{S1yzgzR( z^NxsRt!XZ?!SZq#F9Y;&JIIp{P9knN=(`KhE4gdW0__&uamTH>yv2Y?@!c=AJ4&aGW zE8``fq2n)4=9e1gkLYpUB{Yh#P(7FvBL@*B7N8Ge9dkyP6m38BX;(ii8gfFQ55n7b zyk!W^7h_A3eE=1eoOAZ{q5X^179T&0<2zQxK$f+}S5d~pl0YlO(=tEfH=s?#?@{ir z?;|A{K-Ejf;y|EeR>-UsazXs zfkV_s>mi-YZIOuPIF~E2)5rC#w3)@Ile9>N>szmbk8jzy%27PXSt^AYN%t;EbSyAN zzSWF3g$WHmI2jl5@t7aWx6P$y3ndh9lq#gbO>MLu_9vZ!?Aqj7zAH00Va8P9R%R!$ z4WLF)jX@Fm5E(h@2&B=YfMQ=HOhGTS&?B&3nuku{#rNPlRvm0Cm`787{&DTvhu44k zYA4dHEc1J>gnaMgBvg!zZbxJnp`J6dRcrE^V8)|Fmn;h@`@$}TZ09a|1h_$5k0$VI z+7x_jCwnHCJc;6DnIpKR%g?J4_|gBy0@#&h|Cg}-Q|8(NNlPR78Cs7fXt^kY;=Yyf zX(4bE?7)Z(%}};E>iMT!{l9W}V$yitC<#Bt_ZvKzu>$^TN%%ba0ep!SWEjCF)mP5B zn4$U;a0@)hv@-#mGA)Pjsk z_N1qm?`M=Enu1|a^Mll@qXFf!gg0(QXE7_9%$0Er8q>rhb-}!!lGU`|4LNq(R%XOW z^b}OL8N)(>R@&cIK0oy(j=@cnKBrgkd$yLgJVw+_r1&OK5hdBQaM){X1Bm=X_JG6( zuY&;|aIa&v=NNrxR@I8agwEit5f{8da#3%GM5nXV?vq*SJve{~d=;oKt2FqxU#qCl zN!UK8C-f4N@miR62>3CltftAFMl)9M#d6SfLmK0l8ced=OHs;`Kg%qoqx2zj{7Jbm z;8dnyg@-30>+S}J;8=I=EO&}JS=Cade0g*~|w!Rcy7nHWyG zS0(TX7%iVstM_F4Dx7C07<-Z~;y=ZM|GxIc^ZfcjfE6A!6_40LTF$cv z-McyU4r)5{Hr-92Y<(1n!ZuqUCOzshl3Hih-LpQ97IX)H@;-WsXRVgKP#LgEn){*Y_;*W*Z~-@1Vqof*jAn@k@* zH434dV>9TRt3>?uXRuiT86_#O(={!3vj-;RDhK_b{=xB&;vA-v!NDM^K#^ToGFsnj zG7c|hGD1niGGwbCKMSy#HlC6%_&Gmx4mOz)!;?RBY&b3fI`q{knT??iVNV7tDM)8@lu!IoF2Wco*nz(5ndG@!nWk?wGVUe@gj z1~?z#G$oVH2Z5XZJ5nH1rTycxyIZ;{46p=DEgBx%dI3bcfd7xvuQ4ZR(gGsnJJYLf zk>M5|s;E#B$}CRea>msPaybwuzfT7}7Ulf$0Gpa}>thskwZTlQX`SveC;@a`*w-rz zN))8YOTC+#bpjnvCf%$ez)4J0Ve5lu1q7;9s9g3@;@3{Z3gEI>FZJ0H@6*Tv{XvU2 z)BixTcvH)S-JoZjoc+S=+MQrrMSWb*3b*b(v**Yi*Uf{XAb*?4D*S|M?@->&5TV9S zM+)@Wu?M6B2*W;*&U^u$>dB`QfZh$}v%*y73 z1q67S_uX@qzX;c@XxrL|6kkH0K~U29Bgla>l`>IN1xjFQANEK7 z#pdchdPu+KEy!j@ITKkQAGZNvRCym$-p-$pXhXYh2a9l7PMsx`W8sHJazCrm#m*X* z@>7Bc-B<1QnPYJ1fmM=r5WTLYjDG%eRwQrS(;{1z3Z<9csw>S3 z!ODJy5!_2(CD7)FK5M}F(sI=YUmei@{TbL^v??nPUcY9|zq?&$2==cBkc3QsB=ocFOyaV^YS)=cnI4u1iZ`bl< z%aq~s<0b3%jja9f_xSf3H=p>+t1fS@BQ-uP-~QF6uY%(&UUB<<-%l2nH{SLudi=>B z)!)76COldFh46NV?b-fOkHcv_l>ySC3t{h^vFKd;@mDU_4r`+8cI%sE%LE=quB*|d z@-eXLs)$WaJ?U(;sZvoLEx0bh@g3h;hi_!2BzYV;p1b4cw(1Wobf+=0(JxExy#L9R z8B|%b=5uT1gqYv<#5?xL#h;#aY2Q0I#bwoAx}Vus^5+{r+tsT-k#V7$E^H|KWY
    leYuizw+uT=^mrU-JSY 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 CIXWr; literal 0 HcmV?d00001 diff --git a/board/k210-emulator/img/menuconfig2.png b/board/k210-emulator/img/menuconfig2.png new file mode 100644 index 0000000000000000000000000000000000000000..954d38f4126de973058d20bbdc273d0988a35a3a GIT binary patch literal 84936 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%0Dod*D}315INS=6|G@1Q_=Y51aIu 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 literal 0 HcmV?d00001 diff --git a/board/k210-emulator/img/menuconfig3.png b/board/k210-emulator/img/menuconfig3.png new file mode 100644 index 0000000000000000000000000000000000000000..b5d7f7bb7a94d110f4d2da0cd89f8002fcfe7d34 GIT binary patch literal 25012 zcma&NbCe|8*6!WiWt&~LZFbqVyKFOyUAFBmyQ<5!ZQHh)xAs0~fA_oZJ?|aw{39~g zh>R60W{iwjzxg~XR9;pL4jLQ!%a<>365_&&U%q_n`1}rl1pnM_-V@1xetZyRwK1)up@XrpjiZ^Z(8%BYC7mqEYZ$1mN{*8?B22W8 zU`Vt`$Rfh%NCIqFNmxI3M1}u} zJ<7p8L=1(MrChrT{kj{KNK={3(jYTAB&66l`QcOI>iRM(#*s<#QT3Vi=9&V;5Y*&F zh^f{{DPtHS0}^OsXER;^=c((Z$>ff}6RK*1a1SH(B^b2v#hT6{OgSn=q0IoJwDHu< z7mJbz&t@!>Fe?&c44()H8)u2rdma`?P%UbL@3|<16qwO@p*?hk!Eb04w#({>twxwE zO#a5cZa6BKFW{mg_#UdJ2HeiUlrnX|>mfNenofnvn=hQQ7bMXapm66uV&Q{jx2u7w zl!_XN+;uQ@x1a#{fWX~`vu|Y3y|j2}BPWQR&Fo8QKi)RoVEHv`XxyJ_XByyLgX@D$ zoLL^lC4J*D?12|)NGlmOeGTj1CPilL)^QvpDT~-D;0~CiZ!U7_iW#n9>7pxNpan?1 zV*3O(e?9AXcD|;JwKjvdIP?=$TmQ;VN2}pZqz#oH`*Z$;ZMy+)C>L^dt&)F&a>@Sd zQj;3$#S>M`0a}92_(eGqrUJvef2q$pLf1R2JPf5)d4zYDTEV2Z9Y~rxa?|$^L@3O zgk5PDe~Z9?EoA!9*4Ri!pmN}!&JCz61aEc8vi7>DJb}yP5zvK{;N02+ZQmfcpyu~q z7lX90@K49k4NV?}{kH2_h{ApYL8HZ1j<`G`hz|%jq6UqBqY?M|qT#Awe28^5f+i-J z7oE~*0WUPR8)D5HR>l8#7^n%Zk%5Lp$7HWk`Yql zw>KN;F!?0e6g`+yFG`K@D?af@iF7FL9134CoYup3HUGmkKZFih!+bbH9&t5D{MAz0 z@7u((!j4IJ_vKpbT_hJgvP_>RpmgIwew8~~rFIuFMZwzst`;wXEScRkDqihJuKbDk zTT92(J(%*V4N?2!Q?H2c7);CjSL1J$D33qmY-H9-eW%_4Gv9*@P*QC%`?&$%ucz~0hriKn;z zI)S`LPIvpeyhpX3T99OYS_n_z1-eW59RrVB4}!t$hmO7aRKsJsn-1(xvuRijfnGMJ zn)-mTQYJmJ8yY1gDxqBEyj4SEcy@$x{lHjb@@CR*ZU%5 z=x;u{okfEXjE;v&ukzsJ!3;StbravQR10KH)uXviES4|4V8;jFP!s)h{swD_V1th6 zgL23j9J5Z%cZ$7w#)-Lry;lC?`pZP%PRl)Xp=MGKzOEh?6gU2lDzcx%zLp9c5N{f1 zFYc>)NI{_nXgk*0_?_w5nEZL zjM1~d5-Z!(*w-4H?WzEvY5xSE<@HBzehpQj+s@~RM9I~ie}{OKYI zj;vy7=<2dL1G_0-Q?c#RUgI3Xe$BE}de~yPEq>d|metBZVR?SH zuIY)B0_vVl{??!_CiVB|X5n~%1GrvV(q?Zl`uR=R{<4-CY7M`Q+I$8R`8b z;2*T`K~yx1w4BtB@R1?*vDnjiuvwX?7PihQWq5uz!fM^H%ZcFweVYnS`IRI6Cgj0? zb98UIp&^;g+7h7=W4W5q(fc}EQNr!e9O2`7OW}7g!1Kl#x=rv7>J`g?4nv zaU@d{tyWrGtU*wd{!HKh1T0M2KaOI+k$2{ihgG@%YUJ!APsY2GeZmZ4h4{|eXX@L? z?l~X5RM|kPrziHB5R7^`kQSU9?vsplb*jx*Mqy`Hu5#yFUR){NJ>KF5D9UvR6FWG* zK;NIYpss>gmc7`rhF-K$BBuPh1M^!~2ij@`-98 zH=0NA4$Q8z0SDP(xbZX!fI^RqednKs+y;c&6CmBYEG>~)vpmg_QqYp?K#0n0+VB8j z^*TYNrti!8f~?5lb3k^2*ZbU-NzO!kyv=sSESjqObI`AOtkqm3SfLgwWg29aI9;8? zm4EwU9qZOcsq32X2zy9NY#UZrj>aDBo0~ z5TT;|9tm{=K$Fw8{_L_|SOn;|-G_t&zFVZ#)k`Q7c}#@f%<)iZPul`bb8X8oYqMxH97E zyYrDI%);dW*<8?_$~p@m`qz0oi-8YjNN>nVnQgzqms8hW`zyNYik2?5Nq-MqlDGc6 zcY(CLb`wzsO1#Ejy(tuP#RY}p%EtEwoPX@d@yKTtI9T_+f3jcMNW1se29rA|oSwB<4t7&DMT{~1x=pI?s z2|MVRfzWkNRWE>x4$<$vU7F9-b?x}GwmHlehY3(&mukRWY10Q?5 zb^b%}G_Bv{H`r~}TNn-r6<%5TiaGQ}uc5p6Ty;hkQ^M>QuD*5Xbl0X$Q|KX5qc3Zm zP_FY+b+m9mY@vzcKL(o$O5fYst|Z?&BKC#A@Gwk~PH&j!%0+f9eJKQqq~2x2y!6a= z!rnIEGa4a&?{sP?$BSm!Q65y^lq|q?Y5NVokGkP!hBL`Ut|*Jj`m)iZ(?v6Q3FJlz zc{?G5b$kRg0&yI${i$$nXT^#mtecM;@CBLG!x9rKR!erz$y)W5(rTQyJ(ysnAyz~DGhu$#<$q$;}~4|EQxD< z8Q9+L!B^XPtBE4G(>qK)I`tx&2h(6||K!<#ls9Rdm=w@lHfpdGGd8Np8E@*G`)UTw zmW^5E9YhbGa-t_AfWRTUi>uqb?{P}q6g_^ z$P=kUyJhn{qf}$*x^ugz9iqn{ibl>tnFvL~%u%koFa9UUSo+^~q-~cra)wuJboL=aSC!UWg`nfd#m8Gp7Y5PYe1H zBCf<*ebQ7h<2Co%)|v`V2TV6nPC2}Es7^*<>~Oq|BY(%2HrgR4cJ`@WF>n{Hs)S}k z{`T0SgXDCD6pZ0BcP77pX}+z!fRX8Z^^G#{^|L%%FY_dzwJ&VO2c^f*VtpGAWyY(c zrJ16VuEn=l_AN6$C+Dw$Nq>YDl%rLnamXKS8A@n$<$CTD1zNd&e64#RZqUskTL)D- zI)W1eQth`ID+$F)(fwM>RbO9gq)n?|MCHP8Isvlg@C0rNqc zXQR_r;B3Za3xkXAP1P@%CRnQd4P3H*QDrlth0cBW_UN9}==KL#*3Hf2Vv*akyd3r@ zes@b|Ozh6Seu8p@^DcD?Qktyj-kWoq0{za59+toT$XNeNo zg1yLR7Q64P-FRx;zW>{%Up< zz6|3w4+zgJEyzk5a2c>&?^sm28B&+gb6OiJTG6rhgX zq*o-Z9@(xc>D%U__FV4mU+!9ieT_7V8F#m_vuj@3^$J*CkF@ljRbA5VV#}SzE)%WA z2={pfh4h~~pVbQcWU;xue~S6R+sBM+C*&E`fv}<757FYmQgj zo02!sI=4Faf+}}c4nW8W!eqBO6zEHBYSlGi+`!k1uYJ6W_*tit7PBAuFLn9T57S0P zSY-Q>#T^!*D03f=+8aF5XhGgQ6!>vsnfswg^*j#=RJo8EJmL1Ws(&utqpVtQ!lxa^ zq;{hEurG&iQ_ejz{a0OUNEp&yKfdDJ(N*XrDdf#Uv;mGmJGq>Ve%j*uxr$oQmktRP zMC?orm7I;2ek;1e6vspHkJM5O$W*VQ)Z0i^?;WOxg`xyK=j<=qeZARl>6jA~*$Gwg z^kR`HLSxsVOmacrd;^#nK>@Y9cGGK{0nga21YYv$iF-TE5TKcAy7p?BCRC`M?4(m8^PDL~sqMRhvqY10m>8ZX= zDUn#wZ)x#o9C8ony)<3Y*$T?KdcShvHNo)9aM$pT3QoKVT`y=W5}>s(vA?E%f00nY zN%~UF(88hj;BF+T2*2f)W(S$NwXs6OO~KF72!AQ8UtqAOcMP^1ISP*B=4hy0`2CYy zY*ZH=T>GtjByzK4(0i<-G#2sd2^i#!gIsiw;aB+K-talnvkkD+!J1pwk3>8T_W`HF z1lD0CYLxUOhy(}(>YGjAd0qA3Yzkroas&M5d_uaT40*pLx#jT_)FhT5X9V;0C z05t>b7hEp6qO^|Vm-nrHsh~`sw}lO*BA6FnKoA_mW<76ebIcb`swgL9#iw+?oPxD zyioA(QGP(9l~uoEG^dW%V5@ zkxQ~w-3dW!o#-I;l4hzf<1`)`U$f8vdT>N+FJIlb&H1>Ha&Kv>bN)mjknbKjPR*zG zselmbYLLjmpTV-JcU1oT$kbOc`d;UmWvvsJ+y*lf0dz{F)IT+^`2IyE!TxF$_o*u} zprBnqL8=z%e8d@fZsTj2Jvco^8?x((8&3@Kj?E8dh)VuPF!jNyr>bQN z8%sUzs#H8-_a%?1ah>i%4%u@;i@=k zLtcpNht7;jP+bU6a`he?>uI*859&CJcs`#AP{?g^j~Z>ZSff8T(wKuj@R>>EKg6S3 z@E$`uRChV!eSpsxDvoeI3u_AhoKv@~4pv`2$>g0B!WoVd6Z#hi&{(ZH@7_C_3oqF8 zKW*q-4JnzA=f)J_nR*SSm*X>q#+KfnMUV7X8YAdVz9*uQhjp&^G2PSnn!49a`_OnX zHQ1B%C%jxn_jC@Zbi9)0uHAgcr<7&lgoiubbvx(MkYs&cUIym}Xuyz;+lpg%OJPvFSNff)9U-=|Uk0=++{`mCTPNn|RCK<)VdMnEDm+q%E6Pxy}4d_HfUrn!W zz__E4M9|fdK0v-sr`Rz?h16 zBsD>*3xVFPK6`m}Uw_$xrUgNONu2#O291(YxDzr0F zmFmqC-vVM%Z848S)@dXoC@6s)Q|6Ak)Z*? zE;t=Q_uP8OO#p6gm$RRbz9471jFF8z0i<3D?)V4@(I?5m8sPSkE4f*lUn?_uyeI$V8S1f5GtF!rL zPkz0Gt+s3s781g9+5|avS#iN*`H}=8VFZbBd7839LUe-~v$dMKIA&A5CpzKt3~8>A zAt67*ziG#uB4@k>vt`c`GIu0isk_?0Fm=y z?&*Vmx)>vFpV5|x4^Ly-G`m}5SXw=3yX*~rktRzXFX^^v!%Dhg`(;;?n)BnCf=}lO zWKk;BrzGTqxqV;Eld%OtcZba_wkW_r#^TbK;byg6MC{gwn~Jj1wnH|)xcBTuj7M5a zkn6ZRx!H+xdh0UU8@(j#A;OkB%z1VbmHVX#wb~m_E^8+Bu+@$4L8DN~qlI%%>1H%a zq)uOH5vi<6equwGl#{c4t_E$|$ApXRcVZR0s(}X*K#~IesRbN3B)1F)ctlhCl5nF6 zdm-=t2gE1t36{6+FtOP3?+SQ-XfYK^v5IZ!Z(i%{$izrf^v^TOTI@OR(Q5HOFvM;z z2Dw+WHxYLPY9q21Fp)^sN6|kQ|N2lW5X@Cp&HT_1&d)&ga7-_`!AA#Ti)7pIUcEc> zl5=+qls)>VV#Vnii2lL0)b@Zke6#$kwi%BNNNP`SaHOern^lqGIcl)@%IlNeeU+X2 zb*TQNr(DKMVH~@A#!`-r9wu#UeJI9oR%4GfW|*Fx$mgA+FhiQQ@g{oY@&ZU1uY1!k zk|i;g-QAb?gf969W`%*tN%eT_3`-xTl`LkIura0{{<0+AtBT! z!Nsog>VtW)fzvDau}DkFbn_v14jOD!w=(EROQCMNTN3XT5(gToc3$=Pdq z-&;*qmhl|W4Aa)=WB7n`_Q_KWl#F-aMg)N!MBK#lqwG$kEA1!ABF#J zL6I$(d5|uCwHU=aI=|zoV+u8#8iP~s;vByVt^;kWsQMpD^Ti=A z^9Z~5w%BXnvW9{cb}sapqY=bdO&W39q$7J5u(Uv@xjUew#NXs50-V&0F>(uMcmr&AhVgz&4 z5D4ABzlPA+r(a{s6c9s>U0dr7=w3wpCVST8}=1P2oiDGh{5^Ljk0UL~)ZR+q0 zc=(O+BQaVyG4cjW^BN7%GQF}tii+`kB25+<9CauZE_KG~UDXF;w0P0?^jVE+wkG{f zFB%_%C~!40e>Qr*zssJ6DK3o_1yIwd|A|jdRO!e)X!lhus|~l8yA`q1nbdMphnSJf zZ;RH0Bhe&fxlx+6xA7k@Kz4<&%7AdNJdoYRV|tO#B!@etc^gu#D%kNV zc(!kZlmv9l^t_qDMwfResPjT;bQOi#_wyDqxV)bPU%xc^Fv6^NkNpzTZt>2%TJJ=p zvd^h53+%3>PeixdapFMFT-nMEa_Yn|Lv)Gqms?`*Jyr>7RJa`syT@tGl+;~;qXYjK zD|oR6R3~&ztKXP@=5*+@?6=vHf=1pWE*?U7)}{I&wx6J`i|;d~;*Fxh)+`xAF;7to zm#rH^Uncjx>RTmP=7CEG_U#jj=Xc#-a#ELrY<2uWilK@nGmQ6w!ucmkJKDkH2%T5S z6(A>h0-zWPYe=8PoGn@z5}LD4awR2WRPsvG?XC0BOo10W($vPvgqBtny|^~7E0sZq ziyNI@J)A$XTsGr$H2U7@n&Pw-B_#!wV+p`N*Hzjlt`@#%G4hRY*0gz?*J{Vxs5$((wXTjn#pDgriX$I5XHvI8=b!o8Ooam?*x{lX0pr!{%erEXJ zWvu6)>v&oB_rYO*I_Xj<^EkZnV%&AK42l-=dD~{|z!~)$CE;sSER?D0Q+BCu=Hw03 zs7EEqMGAk-*?et_w@M3x#~m;eb~jS^2TjnFdb&OgLGR82g3tmUva##s^m>&rMu%@X zEL_!LRncULPq<}u6hyY9i8b3=!ujqB7o6a)DRxAk1%QWo?l%R%-K=2{OVUw?tgH?+Z*PUeG)AH)2~>8}N|bZLh6$Xm*ta*d8s< zO}QOtDi<0#B#(Ho))jkKJM%bC+-b_V4>V0Wyc64ZL2YwAffuwHq1Zhv`9|QtW|py*#DQv~;!yA{d`k1rXy#34hj zIR)AN_QHr}_^m15g-f)}mS=Q}M%6fd5JUcY`5lVg1WjV{8-V(YMd-gw%)H*NT#IQm z-IsT>35JCzv+cus(ke|NyOE*T0;}%;6W_TP!RzoDv4Nj+Y@n2I^$jvph~!XDgATi{ z?N(6oCO1vW6j*fI2$p~)S)kpPD4`5^#NIpE#Zoh$*kNcdpm%^FeRW3jh1t5NwXVc4 zT-hSBDjFrpd^kU;1w=QfZQmopY7r6wLJs>S+Efw+%=969ZsmFJi(+%VY^}Qq#Sa6S z+rkTV&6VBv5pndkvj|SoM^Ca7iiY5|BHf~BxAjxHL;q1tFb2HOw-V+t)T2D-LQ%V^ zbvdq;qzoG32~cnprhne3sZ;QZ(vpx*}1qso4Crk%;98#}i6NODXC2*Dq)%GPS999?-f%CbcfNT&f7?enqK$KM=SC z&*T3Si}v^4{vdQ2lz~9?~t*@7U2tH)Bd2F6Ky6g;k)d38q?C@JJNp0DjKG*p&>k^pEM?3 zf+|T{vOg8DD0-Ja-Ji{wp?;ry`!~&n5lhICSGzE8Sn3r~G^&NQ?IITPJ^q^Q3=FGn zCz=H9*VUjQx}mtv9H@3RLz$_>+fTnAEPJao{` zD}ho9>{q8NmIaS?Vc2kWy#nHf#}Sb`Iiy%qI9lH-)WKmbPL5ZZ%*}kIf1zF;|2d|b z9`o93gvnW%bEK2kt`gD%)~%=zvCifbW^4Q2GTU#VNd;-W#&Dr<@NJcWhxu=VE>Dvh zy$$QD%YWR+gwj{P%VX=`7Yqcd!mwYRKShap7~9Y1p47W0w((h$dC7D=te>r-4)y5M zZ=0*$*wY2paPjb)u#K`=n;x!!c~0j^u$H!-Y-WFgFk~+QbH}x{ShdYdx-tA8Ihe_` z4nd@IC9Z)6xgZ(bv;{_i9Ew-viO>7bm&TkF73z`7XF$XpWiq={d+d3p%SnzaDNfG& z#FR`&9%dS*3aw}n^_DSt_F*#qC;Eufnm9Qf&h#Xhk2Hz>7>K3EreOC}CK0iO9XS7M zSlY~3DMvBx8V-hi=+z5;H$(bwCdn$uu_1n=Pmb3-4*2~YR8k273Sq|<@#DR*oYPfnv`Y)=#X^2Z_!X)4 zc)pOZvPRk<%EoAW0kMKUM&2+|45J$7dg1))*aI7@c{u@>6tz9>;Fl zB~pt;Zp%h1^J|I)?uo10KOp(ZzaCZEDm+si@pJ8(`CFgp#5v4~M0ay$G$V$d`5!!? zW>tYUvz&YV8)hA!2?q;n%Vp^YoXmofdHjpteaE;lWs{O@As-+zPt|;!EHBZU_zjx9ZrNKNLhFyLB;fg{X;4P_;)gnxv zsv2X3fn$eWuU8jFyRbVpApC|2$6zirDWh%as!o`!>A$de|M1p?20DJ$JU22KFWJyM z*LeWs0}%kU(chdAI6OgEuODQLdK!X73JNbH#q-Cw8$)mLUH_0D+4U#+(Hhg*W${G! zPf|jr@#6ujZpbc7Yv5?I{n?BAok8#BLu8Ik{t!ik^k&fX9 z%vW_Bt!y}QIG!;zM{;eOe%P*yUwh?HqN~w4bYuw7{|bQh-gHdaOCG4U>ymP7ZZPyV zWroLZD%LR-)4~}hqpZOag{)BqweVx=$^t zN7_uze%qNz9vTr!cyNW?0X1B3O^q7{H-RNv#ncv=#;;m_xOA?3Gh<`-mknaxb~GIP z_{g!T_So_O=oUuJ2$iqP*Ovy9+O%N(+nKU9_f0@8U{x%oLuJ;-X^`^_)|7(9%N$E)Y5#eI%m!YL7n%#(Bp&d;S6I` zSsUOSAOmmx`FydFu|#yfsp?`J4uGt%Xs$Ba8_J#TbCQH1dJGH(a?MdYx%$@3<<-rW-*al_9HPzdNC^;OTx(d!b0qt(x?32-Vf6{o294xErd!L zru!Mz5#RYz0GT94Vp+zwQMYrKmX*%tt)(|+Kmx*a2&$_D421Q-7oq<7Dx33l>1TxR zz>)n|S=v9)AMrjX4LKFYEMh=O_7GICnwPt`8+462ogySM#V#li9X<5{iDI|GwL6Z3$!Ux*Eii-X+y(*UJ>}2RYdJ~+|je$ zJPeB9XVd6RtOBC+T3#HTFMU1>&HffBPuS5oijCtxr?M-K-wx8-*qML1`lB;_td45l zmQcYp!^-D)*37Ez z`#vC5+Ol3}E5?Z88I1P{Apr4TA8<_8;fUGv;N~fwyiie$q3%hW+LaaGljb%QkUY-5 zNn|(nPQGCx(Pj<4A5i)^!YQdibyUra5@o0iUiv~6`?)d+?sRQmUrw3N8b|S^%G%RM zdNdhW8h$GgIfiIpTQVt#NvjBQpy!e($q{?raVgtKIGU6b01^`^PGgd^PDz4^mk!B# zJF^W#|MA?*m~+w+vq-A8(L(fz<^N`S>+%EgV12WoLSmTLROGa5AkBuave;I{{yh}i zF)WIJXfrU$8(y^8HO>Pes6o}i?b-tV4OgZVUg}n57(ZY|4Bsoq;x!s^u8Co1-<>2V zIPNI{4B@wr2a;mvenH&>{Fci-NAT?T8$}q5mPR|Wi-ZT6DtE%hoCOqoiHmh&6c`!1 zS5W62;7+!ctLCdFh8IzPk%*2_lk z@4DWXe|`#L@Z8jiF__c7r?PG9tjtx5P}L7C4nmFA87WFFbt9nVRKWs9AD{BQh;eXu z%#Zl9C}mJHmVIiLl-inia7LpFws`G`@-#gREzLs{ZB5;sD@_q4#^itXr5(tuSJ%}I zz9z=fxGiJdDi$V3SZCw>plVz=ZX(HfKq|FWxx+7+Lza?~(k}R&BpIuvNt7&EpF|r2 zxEe{>Zd>ld{Uk#k{s+gG`KGZ-kZJIEF>x=f?>Qg8<=&yi9v|R;=0+KK40)Y6zl1Ed zUpVk_EdPvK(&OztPV;_3u<)-<4e)Fxw|(@+x@?jcyujF$Hz|Azjx@bc1m?*d9TM z5Q5hs&4Eulww+@?mG|(}#t5x#pxr_~Si4E(&)0`}nhMuw9jT6eMam?`jt)ti4*-tH zB9dpj1)*M@-xi=&9W%9}pd9+Xa9R3=7p#h~R-+YwTNdonJu7Vx^P`uKE=0s5F9u$- ztFg?4vHaTl+e1*C*l>HH{ds)v{_OUeEo%r=h10ZridVpi*8H1TBn)lm@<0?W_tOKM zoZaO>#-+<2(|tS7`tq}MirP@Q#-h=DTS#@LNTm864Q4|qaz{8;D(DJ&L*g;~yAr)^ zNb^hVnrIz@799w#b@+ohklq3gjlxW$<>c?p%ANR*4QB>wTNto(9OG}CuOZVXg;dau z^aip48Ht% z%Rx+*+F^Evh}%b;0zXF~=(ez8I6u?4Gib@WFn532b^EZ>W}qS>HU9rs&4T%g|F>$^ zz6oX%WIed(b_>`A>$vs?!CcfFzMd4jKJLM<>$v>Tn`@e~*aq*w-BcK4&rIFkFl8~^ zFf$`CAC>bpY32<-A|XUHeQl^juI9 zMIh@i$sLc~>hR#d(#)3duH)Pcv$m-3_ZC(XtJ>#ev}Z~>IJlP>ljg_cd8SGwqbR7x zcn0Nv>b=ni5e0@jx`ojxLlJq)bx&4Y_^ruaiaOfKz7Y+Rgi1tsXV>)e>-axXK1a8+ z8fCD4$A0ZDx;B&YA}JqNrs%I|{1hI3B&>oRP1S=Ru?*yad#@GWS2Ea2#|Gd6Mi-); z2e7=Yi!nU>xu4Mp(>~@BMn22Md&kOL!RZhSe|ChG>#f8;-(EK@`zkKBTmsteOcI@7 z4E#MwjT^R+Iz+WS`4#ZWwmx5SKJ>t<>&va6sL=CH(&Z#u!s^ao zi8qAuSxOh&j68i9Y=BCJ^E0}_$Qw?2;ATK|-e6>1 zutn?jHBx`rb_mvjUo;J=iga=^;?xZvO5-9Z8_LnUlvyndl0!E zPN(No$~B)u2L7k1hsPX?@i9U>WAtkzrQt&I)*yDkJ%7*sWWBZQ=JxyX!W?e1wrFJT zB$|NZap$&T^-arSmG=v@P=9+J3)Akb6AiG+>wmK51p4j}c-Hw}k#QoPR+0Al_i8EF z-J2J9uTK~_!D1;)E!({at0kyZl{t)0K%MLRyB@|fwE++ELAKz#0D=1*|4ZFwDU&Wx zYhxX#MAp6+9?lb=!tWpIA*xzdN=@og#Tv3_7Jx?I{#(M;ZEG&b^~~0esub~dP*QX2 z=PT@QM5yilWFJDiGcrNrs992-gz4g&jHbWtpDw@+4?2Glf!T-K+u($$ zkPY*IGynsGwjZWZ#&jxHn1ub2A;%WKFlqWIBAVejR-7?$G{&`JMrSo>#Uxr- zU2>?}!R@V9Eadj%7qEVEC%B8CGQrs^=jKS_+;!k8P=|wmJbgGVW`@hy_d!^4TmvJv$|3N_za9&ov6Foi9ga5b1n}Qoaae{{t!((erWn z&JhV!-?QBAM8_OuwDmBJxZy&#yy+xn=CL>lbWYq{+KsgX3e)>cp>4k;(R(xS^bBHz z$JT1RSkPA5zTu-3R&Kp|BBU*+SyIy|icnOCCrZL_*mL28%Uath2(@g&ut0JTb{muk zaIP)ivEKUd^e3i(D$?T{j0Z|Fm7BAo!2>$w>_9BFNA zw1x-5r%6bJ5!)PCUmd)jpCZXfJ*6IBX2d?kzc{l!FH0&L7ZRP!0*~l?{_VL(cS>7* zwiw%$yRvrs%17H?-$3v6LaqOD;xB2(Z-(CDpZYz@?%tgP!iPhqTw74E%X1+MX7^y; z-|Fd^aqp#p}5o+@tCI=YB~?llJE+jGV~3NgBRGQ&O_pYC5%1 z_b#tFnV2oAK4w5uNeNDa6jZ9v!8SbUx@$&}x1J-OS+$pTa*kDftMt}dnMh__ z-BA&fLLA^UOt#f0aE19FHk4)gGbR@Y6eq9R*{N`Y#-8u4MMTCwrY}q5|Ce65XSC$Q z%v?A^A*(&PgJLUpHm9$N=jK#Z6((Q?%xir!`P{Qfv3FZZTMff4B6xmqXRGO-(%x7H zf1*<1eJ}E9nQyYP%}kmANkk6Z;g9^6Wq!E$G&i{;T37EcVR4I+-dfGi2GaWS<+<~E z4^^m@I?q9`~v`N2Np)MdYB2wa8m3jlsF9Lg58 z`U~p}2DkH9;)6M#+(+Now=$eS$<58{5_$dVI(?s>GsXk#qF};??S4q$8v~Td?=k%d zycv#a9eJ)D;OpNjCp%gM9z_M9`aNXq%wBsvJLu?HE2W(6i_~j4V(1$(1lPS7+9iiB9sWN`<0jwU&H1p3M-*xsi3)h-c(94u6f>Nby2Czt<&V*t?$EeS?m2f8|J-Br; z#evat8|t3y79#i0J8Dm;?0TD%kLG3^y-TQ_)$y>VQcqN$sY7pokTaFmvo|CqsXx0E zsvWwwSepNI_)@Z_S%gE9^O>%k^|5^`%z2G6-mLr|2i??$LANF-u4mfcuilm>kJWaW zTH%FZW=co`MhvY2R+O^bGwumfS@1p$wdW_>TU(NOi@{761zg|>lK)Y9q-hv!Eq$&v zKGFC#X|!|BpTsu_Fg#rO^*}7TtG7$_>JwUwnmU7Wk>gM<=P|jW&b^f2PLu8Z9*vmK zF}%mYQXZWbi6bR7s<=O0Ctq?g9a)FF+L|1w}In^xHl?mxw@8iB>PWf(c5t&E$~8=9FBP(8_#md1`g) ztft)16o~H)CVtLG%-;&$#-{-A=_VZ^%Pv2H^j@_ZTDB%lWn|oIt%7QQE~drjOn0@uk%)xVKTjCPkz(B&#%S4fKjBVl=SZv`UA%HxqfC;~ z7P9ko@u9N?Dxo7IFWWz1zXy3qY;gm8VTB7|2{DSK8u=5KunAs;781FKi7st5m9Q(qkv#}jQ0 z$r9Y*7u?+?xVt;S-5rAaA`1k!;10oM6P#edgFC_9VR05`Kl18TeXr{NG1YZzX8QKr zo>TX9pLRrMG%~0UG44aW9%+<$BOdzZ3w#V;J|N*jDIWu!CIcSI|j3zZgPKu(ORxGX;{Q zVd}aqz(=tB>Uya8Ow=oLQUdFfqWo>1lBRd^vUo=!uD&Cv7-aM zHAAF|jd!=jw)a5n^rxcF(brm7r}T=XfFcFy%D!8b$YW@s#A41n zgV$1oBJ_%MAM4H0QT^+Ik50y1(Hz7s$n5{_B{|FEd(gb^t1$mV=;0&+&`dUA_mJU( zRcrIkR4jX7^t!vnemHaA#Wk`1sQSLjm2+6YKLJ<|f-EZ{c895xuN4k02~Ww7RdX*I z>!_%Tn2L=9INUCc^2hJLWsTkmJx{pIv={8u7QHgGKcw8Aq5Vg%&3}(?b>G#IJ}(6e zWDlUGU(f5!4NvF@H+j-7Iv$1q+rqJZ(09^{$ulpnK1{Tv5!1eP+{o5|^3r*uYFDK7 zB-;EBQcsH#1!f{<&)#ZFjgXm0wCfo(p0Y=NosT&Sx5Q(S7h%QE>sltuJIR!NH+5D# zj9Mb`b&4}#-}=*NcJAl)b=wIxU8)1%Z_^y}r;OJ8^^vhXu`i6{X_?9dXjDfC3^&J$ zR=V_PAATNJy+z3bm#51+g=kj5ou%Lp@e>7Rf>nhh6QbIDr-_9}%g1GMpDdE-={RT0 zYU|vUOUmxU)5Izt>OI{5R6eBE{n!3_g z*>b?6;I>6IU%$o>Oz14vOaEZbpJX$ax)aOfb7UPFaTFVhqdy)hyBcHF05LEPD?dg+ z$eql98jx*yZg{jj?pS*F7Vd!0Bz_n$3P$ROVnQ_!s&=3Tm!8H%MDL?!%D&6S>Zus{ zsep-YGfZ&wmuNqCi!^o>1C8I4!+)p3`X@78`o;Ta_^|}neZ<1IDkyM!Bgq|2E+l0w zWtZpDj!z?LY`}n+gR?^^OjFvyZ`4kPo!PEU3#f==zBv3gOp_b-(PCmpx?M&s(ISKk znxCJx4~DG+gVo^Xg?p>OWLwWwj2-uuL8eZp-4e2GRqQ+Y{&DTp;TjCPo>hLUSlk6e z3uI09#I*+_uYv5IRO~R?+z}q`%qI2?2?#MT(0Q%vEm@|#=LNQjKV9P6$OCs8WUlqy zREJr)*KOvBOEe%RL)#B40))abwr8;bqf63HNZtJeykj}zaRWlr=$XG`F&&*y3IlhQ z)7QTrTt}SL&~O29J5HeO0Gz8Xb7rK0NH zx*-X`f(kNBvd07D+`lC2&M$S%-XL^{EvIr9bd1L~Wc;XmmMvp{r7sCQP8eFauNDi+ zQ)uT-%3T>j-61pg?oUG-M) zCyuD-xCWdD6m0Pnqy{#aVUUxt*||M6x45oeHt~_Y%`8RERSkoG1zx%LYnqhHri1Z^ zaQW60AD<%vziFe;{D9sCEPh9pPKDaNz=KW& zY$H8^9OtYB++@jap-hj|EOJwmzWhc-iUR8D?!Cib?XB~+^eb23p#1(CT9*a9ZMf{C z`l3%yNMg3(Ad3W8%F4gU)gDL{new$K{N-6OwO;BvdWL=NKJcS@XH3~(Kij6*8FhV} z2Yml^2Aa!SP(KI~J)Vn%O>6=X4!OQIqSop`e zF`0hwj|AV{d!1afo?_?RpOploP-whR7j%&NZ8B~A>_yilYk9QyeZE0l?dP!X_-?Fp zIDA6^@tF-n@*lVMF92Y>7gmr|(B;*wc-d{uL*6Y!37?3rnYr#OC%Ha`3Q zX&w%3D>ApUB0N=U<-%d+p=-EPMpko>yx^qQV=b_+yNB#KDbt-f@qlIThUm@3j@EPx|N;hiOi2KZ{q@OcdOs&icGYq>%|aVIhaF5-evn^R(EC;-_^Wn* z)5@(vD})uYsi1$hgC7s>7%SZ+_&t82h~8qd7aKqtUM+esnevv@K-dJYbJz7lYAzQ7 z$B)E=y`idI%2kpw8u~p+Zsl}O7Vf+@;4_8$LRatgY}sXhqpfey=oT-zkCOfQknX>j zWYf`iO%RB0D{TBRTU`|_X$umJecet}>g-dJMWe@Xt65dPm}X^Bf?A%YPT%Vh(s*!^ zm@VZSeZn=h8Wcxo;^X@kBzrOS^-QP5i7tfFBfY_U5UF|vH#?(qXw(D;MM0Haf@jy| z?3hscurNUXrdNIrf1&#e;}y_me2a>TuDkz+a_wk_HtC|h>|)i~xVG766qYvMjaQU) z!IF40yNSD)S~P3JRWys-3_JfO^*GgGbw7;nc{KmtlpVpv#icQ@N5&bLzq-G-7g7BB z;5=T;N@kihhR(;w_s-fZeOSG;VT94U7JRagY<(!^8-FmUy!UYA>QSIe`=Ai@V7K58o#W&LvnD6? z*ly5s1s~_sblr{Y3^w*Tnf!`#ZQ85F(XAbJ7GHqsW_IlvDap;0C4jTw9=qGa^eHn2 zDI_yn9$a?y#W0uRa~pbidVTJSZShc z2j8C)Drz24Uo8p5iuD543|t z4ZZhz!mNT7_$;`h4NH;#fw~;|Kp_g5W527YNvo}10b!!mU5AfF=*fq-R=#pyU{iHG zO`TkLeRSOIrkr2ew;ki5is!)zK-SzoUwb0^$7a(J%71`Ph4KwjZvCQ?@_Lfa?*d{K zxugr;UDeF?J1_q}C?^fb;QyZ&a+Tg@{^uS>;fb^@*z!LYaBus~epJ6?a$06H;z-zu z6c7IU(%;HITCoQ}5||qhxlWO${0gIKRYGJbNpX!2$n?ktP-4{&L*uEn z={_j$-lga3KZl zRctM3G=&i`TX>t9GhNb~5byBIB-qMy(dxii-l+5x$Jr4Fh z9RlJ(lmLf(B$IiP1qwC)ZM`?F>n4?Y>vOw~I$SiN?#pl(4!0TTdl+2{IQ=1|;X;C7 z6J3GPOtbfU!1TnazODSS!d-7rXNd40??}p);(#5SC@(_s@@YLBO-ot;f)+M|*J3lX zw#XkN&i^8#LW+s%M}ALYlKqNmYzrrW3PL${&?SmMHYAQ5$jYbzd5uS=TMON~vHc54 zgZ-9jK**N1{=0_(^_1w!#-Q~G4!&n{7Cp|yVK#d^#EH#3U3#~Ms0u|qfSmo+S1?F; zZZdGr2?BqiwM>|X2l>uD_iNe2dsq<|DHrnIF)-@IM*HxoDLGkD0Uregpkyq zI(8dr4@+&G)tM>NUkudpAH7NHabiENhji%*n<%6u9Nk}F6=HRbf}Z@7dHNA=p-zZS zda4Vv)T|0#iti*Ee0HojQmc=Yj(Y75g#eI>h6>9o(hGy;>ThdEuQ+%Ci5jcwmZd&Q zAggxSeoI{-gn|c_;6G{%hoMqon7|x9^qMwBU7cAUC`K#(8Jt5<=N?|1vVftARfnpB zyAiv!r7h|izBg0eOXyiy@!E-cHz&4nhdc&If-X@PG7TOa#WQH0z&0Deog|P|db5z; zt4W2#qC7y&Gr&vPJa1AFwHul2CdwHm(Z_2A`?tZ&_6IR=8CsHo#M>8$AD?3IrL2Apb{6Tbmm$*-ho-DpARvS|4o3VbOb zp`2dvm1x!1q1 z!36At;rK-YsnMd=#h&w0K)H_vd>8m%iQvfG|Ac@kNG;U#qlkBITBYFMvP1>|+-9(}IJIrgs#dtYi`%28~2IAkvO# zJtG+Vq8Hta1!2|9OpI%zWB$wKQ>0m@5YZ>L!qG~xqo6H~%;k?AV};D{@gMdROY3#vkv^34fHwA_v^>$_V7c-4SJ{@d5fqclkQaw#!aAbz(V915g@rC` z#g{M%>WF?+&k;pLV|>qZ*)-kRhKaaBxTN>AOZT)UIiD18*z|&tpzZEmidORYC{`#D z<6w=YO1_97GFcq|QltLerH0pE^_%(X?l@W^(b*src_EYmo&y)Cg#0tSmc*J@jZKFF zanlDEV)*?Aw=J}LjGfc>*KS_bonp*JavHaH$c0=IS0)Te$xD_T6FN*PM7W6}F9=Ag zMi@tX+K+L)r9KQtB17TrfbpYwycWrqIzrc(Go$y^j_W4^ew#wM+?Id0$rhS)0s^4) zAs{1+S9gr-!*X9QdHHeYAp{9G8fNM)T2H?_)LiDPq@!_Nx~zMIlE3^yXPRXyRqC!A z5zPT#_pV@Po#-ZKHR(?hnbH-Q@c*m~a%~NHd{{fxmQS53C2F9Mp)8=m6Hxm|MjuYtpd8abH`QOxrPqOQ zD=PA#TmDLC13eq*rZd=Uj58^q=TZbPDQ0lKTUuP`_7w_mi4n~1GDzEr;(W8Q8NuP} ziPe8rwUgBhDJWxzPpI#hc(saZx)aEj%;!XNc|tX?g!4u03CSkBL}A|0vEnIMq}7E; zYmLXzwOO7;rSi2#?L~oN<)@@l$UYg%lOLKm0+wAew)wtMa()^AdCA6+g!uPH%3=YB z&k^Md9PjSh2XMe}fYpBtGWpCrLW-D4|8(s zlEfFRtpQlctweoW-~9_xSNuqBFr<@T2w!t_%(q7vs>4xpoE306m~m)Un_Dh$s^M@nUEtIwlD4W@%C;0^L<$ONM)%Y zpkV4uF-oI`($+*#F3Br_$OOy&@d*eDQA2&;L-kG0diL12;1zKLIaiC>1k_WbN&<>3 z8y*$*QcPpm{E=4wdnd7;?$5uASNYv{IwiXBB_>EHd*^3FLnd5INGk6Z}2RAS$bjkE+-FdK1^8f&J=E1hC) zVIPX3hP|ghtbgFBJ3?2vW|C*qlq%;Olx#dY8AiFWnbd~fs1?Bb4f+cWqb%B9fSg#6Guz$J zRbCMFXBrkM+y`d+=%RgoCa{6(nI@NgO;GOXIhZ8U6QRm%lcI60nstv(-aPYz1rU7D zhJIqjP);JgWpJ{%Tj?PCw&YGJ*Xc7WLVb6M+^PGOk(?%n#XISdOEvxYBXP+0j}FJi zLPA~Z_=Ppq*1cIhKEekkM8NU$Dq+F*2VlQ3_7fq`qdRp{{_I_QzU@4`*h%n7h28dD zeD%_bX~F6(fvTL;Tznzu$NfA(3`tAaSCN<(){^_zr6&gV`VO&YoVygSC#;LF())Bh zdj7P{gOEus_ip{(1~I7FpPO<&>sQIJ4Zl2VHtunz!jd%tO_wKGR~u8{c*an29zy z%sE3;RGELsFze{tY@+NJt_HII9J{l$&@o*r7;}{uluIdc5#WElCtXizliL;;Ke;GK z?xv!#@oIm1S*87`HzKEa(`v=nK@PD8CnQFdv(3XPO;2Q_5l{{&IxX=e`n4JRv9y+< ziR(UvFRj03f9sj5rmIXqX@_QPt%*a0nqt@>n7P8f&N3hUe)=3q&cy-h ztuWaAVh`5+3lhl*2Fr(Ff1P;t!={qw6a&42TtnRW_(`K4*QC;=eKj3H-f2qI3RRJ= z22;a!#UzZhiuA(q1BKwoi*-9WudpWv*?c^gUHe}>{bYwIiYs2gHLuE6*BaOH`E@olV|WNMy=JuEj3^kopdI&x z-%t+~T_Vp!Dy|;U={w76!@#<$;wa=eWz*4Y5W|4iC^n)`YX6ia?vL6pH?jeX}J{mws1!kG55U$1_1jjT^G#HYlxrB0RMg%3_%O|AFwCgKRi zl%LT={CuHUE{Ma&m9VXeE=Ox7ao6jtTVsp=L8M5!+$A|5pIdqtT63Xjx+l9xVC(g+ zFqISC+ZcrSUIBKe$Kk6-S4=9lACiK{h^Ao}tla9q_sS(d65$3UAORreq-5%Bwd~W^ z`>!EN1j%nq;i4$(reg^QZ)TT{)zutd@HFVYoL*q_alc{_iQ5gPe>gE_jZ5QR#KDa5t(dYogMmm{wqI4N`(fY`^HjF;F!egO8Kn&Z*>K0lnK1y2c| z>+6Q9&CpYN23>D6wcy7`@1$19y%5;d70uMBA9mL>uGlr0J3nUZoVi}9BbnM%D)*t%-0;_Zn$&7a%qH?4w z&(<_vnhSwM8H@a-LxWH@grgr20D%!}(D*{{_IQQQLfT=7f1m1NI^aIUmG*Q^ZR)wC zdEj%RLmRnt8+^n)2~2BAI#5M8C}5dusK$g1q4K`F5#M4md>Z-Lh>{t#IY{avSL!cs zo&LN8n`?eeiRORyl|CvWHrF0uIAUR13L#=3C_K4Wo-^$(?sMNP)*Uwi-jpSWF9EWu zsKae_XE#)dKlq*SllZP#g|Nb6-4fo>v57=azVGP?I5)OM*j0ak(jK=|1|LB70EaSm z_-R&MPhY0T1cyrlqVLjn6cNk!jhyCYbU@wVg}DwC7-m`4yI#;!2x1dW0)EY3DOV5N z53Gek&(zwsFq;GaQycgJUixXu!zE_;2&4{ zg0I0#!5YZ1AJOvr@&zyntDSd|VEQz+?&XKD$NV>EY;ue`MNNGI=@bJX6t9 zT9f1-Xsi{LeKF%kG8JW-(u%{}%H9aPB`ZEFSiUr(rHu4+(4V4s_{j0o%StVGNiHVx ze_Y@C!$RI(U$LtH@t$0%r{wMXkPsD?Pt@IV`5oD~UdG&}$ON+4S$MOb{Mgdc<@_aB z9tLeiw`C0Sr`8oC+E@WXz<>WL`tNJhS=BpS9*Sj4*WjQZd7itwPtK?rxu(QsYgj*f zhSF<)A&U_v_)Zj+?S(Qg>gZ>r6if#L?|5Noq)++S}G$G5h3~!X2krUedFD+dyl}JK)sB!qZLd_ntx=tbJ#92b>OhP9!N z!IfKD^3%FZtW15_U|hOgsw|xT(0-9jMQ+asP2vJ zx=f$K>q`kRS@@JJ=mN>;okfZex3z9pVRQhMsL*5Ktl!ZS-ctGS-ErcSt$A|W8KvYU#R$2?cA&PI+BXvplh z&q)*HyP|<=;qM2a*K*b)S-bo|=Dr-K6(bPI!WPGJuVc2>m%NhH#VX|PXGg-vO(v@` zUXz!0ecIC7A{uvEN|^!t4_2s1_pD0WT;t>%_RXfQ7R2(ME_9` z_Us>>;{i|FrDB7SlU2X*MVOu_6?E)g^tAn~;}9I&B`c&cK|<*;un6@-XkP=n7rf!B z;;h=Aa7x(b2QL6AJL0B7R^F?}}iIa5IMT zy(H0lQo_;8Uy{wnou>-WYewp_Py!^$b#5*U>uhZsZRh95j@{yOg~LRLM~n=7OnK`6 zKXwJ`sD_9?Vt*7ZV75+QrC~seH`4Ah-Lcsm6LKj4)v8`!O%~psv%)hsE{JGxs!9^h zx1nDq%y5_QQ$PKC&o3dww;#V7$r}z28_68~Ln`cYQc{gSZNU;ih(^c}RtdR?YQe?4 zBFBoc<+`_$V3Z2*7Ia?J!4h%2#SWO|q;bxPtzb@^7o`Rnf8nW)Tb8`wfrG&6kP%KZLM+*<{te7%pQs)l06$68 z?gpxVoye)7ql+5oW1<_Lby2WW=G+?joxuGkQ`YOD6&3qaC)>^&ZrfB&4d+wgt!XTy zrh7d9JpWTe8I-sg1XHxMALHC~srxZqw8XE3;VzeKFtV^<$`ex+2}Hi1Jg_{$^)%)?*nYv!P-v@tVjrG zrT16_R%C6Lyb&9&1^r4fl3OOB1v&A>MNwOPXxa9xdVbVm;BowVUmux8Y6%fe1Zapg z+QdkAJe*A!<(Na)?Y_mo$#h7TTm*dEcA)={ekJDT7&=F0nhSijdv~*21Mk~@aruEN z!LywhO}HXuH0uWy^{|=nskLx2ZFT6%{_Y$eJCP%f;p6;Qb>8Sdf2{qMZVcN?Z_%vM z+qV-Kiy|ILdp>6ZJM7LYCz#3o)}N(QcuYT87pM0Z_#!s^z=T%EP&-=3WH#fy6YRZW zR&TY%u3UhL%+3lW<^gP;k5#(XNA}PDfOBFn-UY}u6a<#GzZZ1=tJg;nh7Zk!$?x?Y zK?fFDV(xvyuUkoy0tL6%uIPvM#eUAJgwLxLP%X-l}tt#!j>$kSuIE*tqH`0 zXQ8n9xJ&f*G_Xh11B?5+u~+@~g;^r{J~Z0^Y+28IL=jc}4uuuX5j@ zH>gI!mk`4cu;=dC0veuMN9`JBOIBk;o$3w_qttEQRAMaDl6Xn1N>q$N<&`;;{mnu9 zyo+3=Zau0o++h^{f#D`g{BtVM$ZUph5=>0v*#{E_7bRLsNOJ1PEQerJ>^*L7S~UL@ zenV!VvmA`aGY5LwW2y2o;cZ4>`*ff>VI2#C$0H-+c72Li^T2TbX3h=+c#@Gt5aV|# zkKIyH+EJeCdW(GtO6#&Z#&b1CO+f(a&Dv8ZD6x{-Ptx$Z!0Fo&N>taHuICCHF?#x` z52dR}4gBnv%-&xn3+Q?5!o|gs>j>LRe$wZq658m}H<_?z1uy2lC}5#{T@`NV^D!1D zZ(gckE15p+J;|WkW7(|$H=~Qzs;APDwd9BoAB}O@({V+bIi0cjv;f?3@prY`I*V!6 z+Q;2YE{cWcV#nrMsl!(sj8Oys34`)QQ4KNnQjK}_BU^pT2|v`S$b|~%AC|q9E&bxf z*c-oCqA|IsM~THNknCOZwsyJZ7pIu$0DgCS$-F{DaUz^~TV^k{b1)f-f zkUU!9no#y-jRO652&#W#6PEuU-Bsby^nlU97v1foPOe>+%#BA30kDUS5`9r4?9(^) zsH^feq@#M>GR#+6XmgB>Rc4W-95EBl*F4Vgs`k5fBaD?>4-Oj;(A@aX>{mz9AjO{W6_}KR`apDt=B5>hb+@ z`xJH*g<{&aT41CDNak{F)my45IyH(jRjv6wNMI4@Yq_d_p=mi_^S|rar9q;ALt=&_ zenPBM$M_UnDIuFE&lw+{%9XF$fql*>V4U3rQfl58U& zw_JRWLrrN(dCupKG4*WlC8;mQvL@4X4iz4KuX1&yk|TnYy`9wcjBS{BINCEaGm7Yj zGA2W$FB9qhj0TLy&=2@sQcfpq`rn!lKyc-TZ+D?hmTW+}&MFxGNGYZWSGy z`FWKs)=-hpD^~IYo!f9Yw3>v>G=Q%JM%Z@tpD45fgkc?4D9>6$=F9kXn{adJU5J?31s`*VQ4cy58 z7W*k|yXV_|b^LkC-MMHhZ`eZ52p3o7_Ysy%di8rQA+$;V4H2ew*#8YU*ySfd>O(HR z5Ij_I44-~SivKaJg>l0*ju$*1h`A&k@==?6wrOAifEp$06!SmZ4lu0RR=PxeH#2th zCvG@f)@>>Jg=xtxuxAaDseFO+3{(<4>rh|rprg}r8kIv<4D90}H1MAZ_4b3P@Xt3kszpb+X4wvO^&CWLL|LAKYXN|5n3xMj4LCHPIodEr2~ zz56evbH<(jWeL9?u5W!$W|?ZrcyMQQQd zjuEp&xbvk*Gu5-de)SEo#HqJVh+T7f?c?a5728h^Fw{=eh;hS6%$v`!LS0mSb#Sq7mxm1P8F#8rPTYdG z@e#$(2Q^0EVFI4|ybzhjzQV}ZhByp=R85}noK|jm)*@i`6ScWIc_T4b4=ibgI!;rd zY0R(MAj(f3mkQIiz3!VK@^+hbsuVRkJd#7`0}L8nu?eks9z8U@=zSL|)Oq^UJI z2g!x>(PLSAKXJ24sU&Sm$boALHUH7@^*c99^`r@4vY-Hs&MUqor5;tO@zA*9)v-nF z#fHWOk2;kkNiRAH3*fyW358>i)NJl)ueLrap*id_;Vu|IEM(#nHULWxf_jFcoNeRRNzVHRW#{5Je5yY)_)u< zMju8t7o7X6yuBI4?Xuyld3Lz653Y9^eX{58;jCr@tvA#^8a475ht2-KL%&OZM)QiQ zNuFc!V(^32RGRQH>5hN-{E6^Cx%9yf{dGWTadp~X-;1mAt{iI;U&tCjuG43C{NSeJ zs`Z)?CYg~HEF6R5B~laC z%1T=^iDh+xj|(>lX)_|F$g;xC3xA6Emct;u?IE`bk~IEo#JyH3*}MHK)<~7Qd4HNQ z{0<7oC*)I%`dCAMOA(0x->s=A2>}dM46r}m)i9M*gz{#bXN{Z%=NN!jnr ziH*CHPn^8TBSt)I4h@*Y;Bk`q599muZOdymA{ACy|NesCSMXK7pTe(SQ+oNN)8E!T z2I!M?CP%_ULI7_6+^POeFVRtA)i+Pz+oEKwe;0=Sx{0APX}pTH*7+Z;e*JH)-UL8! z+ng}}dQ z7u)YAxDFVK8!woqA1^1a=G5z&uguv#&Nd;yOJtwf)#ed=E z%p=E%s3YEo-MCMhqvQRaW7KR_0;|6ZGAIO zT>L_lUEel=xw46UK%+a13u8UojqlL>?S+Hq`q_Fe=g4U@kYLJ$^<)cT@yUU(K3IcA z76a(-b`v5(sc8?753@^rNbrnZ@jQwFkpT8Cr9>Yla=)6DlQ z4N?_$WvI#fjE6}^Vfr-c|SM{ zmtKi82#91CyG~R{P$D-`=+``Y*v;ZH&IZ z{_6dTG0Fer=X44qDE}$@%ICq4oR>jlo!=fp;1RZMD{ub!!}YInue_F>aUgd>ox z5Ce;ekl-2ZvPhwIVz?o*!IJ7Qf-uHrK8YZcdIdKZe5Ww*g;-ihO;#P`>-bei^r%cJ zst0{G9aMis?a^l)W$ZHV1~?rykXD2isuf`H-~2_zes#gdVYXb#un~pGO4p(Sf8@p& zN7dS%Bgu5Od5oi&4!rC+?JTQ7u&v-ICyXiDtqqvCZk$Vb9wsGkCH(8jtMhQ!+XOX6 z2l-M7h>W3Qdc(#wS>(qi9@>gFU7^5%0a&XNY?Rj(2@cQRzf?p^iVPv& zPY(`l+k}7ctVx=c7wng<^(vU&FE(EmI#c3x#{W9pWTC}zu2XhZd#0@OR4E~sb1X@@yIhP3 zrgmLIn2ep3e*N5@>WroSVghnXZR7gF;Uz}4;JZRdy&FNQdfdELhrW)qtj5|o1e2js z6<2fwWwooJA$U(?jm{z6!6f(t()>jzt3$4!q#C@02Z}V?mc$D;TAl6-T=gM6I8G1OA zjdBU?g6gBPWJR6SbVHoxuxFKNqr24k6L}|8+t1z{Nu&==TlTM+-HI(ElqgQO!MM+dgs`c z_cPS4#>E4t<`tIIe140QRe1>jNG!q$_NosvM7nW?8_b7M+!;Rlw0J*)Snq?HrkPux zh)Enikq9tHHt?q3fndwX$Lk?tlsh(8dQyF&jF5uWxQD^_2YupIsUq}*Ci*CcK*9lL zzgB zL8%4)PbQ8fro7Nod1R7zn(gYXN7oT^`l#Ynfm_6 zf~tsZOF1U4EAxHSn>d^2JLro1`=vlRn{U$Y12exTwZocB7gW))_Q+L2()np|^ZCNn zk0=;WYyXVr7||=;E8v{994T}+6&AQ#XF)s&NclM8nb625b(f2NAqW@?>I=60 zaR*}paiimMW-tHJ_wljy1Al8u_FbuFdxJ5B}=&0?CPq$6okt_y9>AAcqa`Op}8?Sddn{3g)`kC$P8FxI`a z&ljT$NBY-$#Q}&CqRBAECz_{}_w2i<2mxcna%l@snTt2_DXuH|GTYSjPqY>`FCibg z1PvhmcG5>c&^V>UDF7W~#n;IJWV}}uIe+32@VM$4G(eC!MZ`5hc8_#IkQ7uqw!+V6 z!fbvEl1>dQGJKc&)E?fU52G-M(t`W6;E9HIKSc98s{!iGbdS^5NBNZBCOxFc#qzRJ zIlbx8dpto;Qk@t@_IPh%&-yq5KbYhtd{NuVE!6%+qcBNmu%15UR;W2F)CM%h@T7EG zzqW_%T@)bzZ0Xm;(s`k813-9Ka*$_x6BH1AxDo%=gfp~+-IVS_=}`^Jw$|tTyIc0mSd>7*o%tYN^=Y$sh^aCyW zEZe3z!Z*`|a0JKNdZfc$mCjSv``htXy$}CD%KoH63F}DzNr`88O{UiEp8Fo@M*K}6 z2np$L>=`UnQ5Za}{s%7Pd)S}8b<~E(?JfrXqdh>=lLw~Qg~S8dwQzwaHJIdNFeOuVC6(6Q+FFatE=btTdEh`nJAAr8sVZO8wDTkcdt7%mW@F95n`%H#v#^ z2IcJ|!`v{(VYToB>}uk~@VzhDi1a|WaMrmp+ za%;ChO`PN%?kmm>l6=#lh^-2THEeZ;;(%TLoL-h*sJgQ5c#bZ5+5FOj0h#uOmia(= zGqZgVcUMAUqGG~euwV~g^zvveQk7a8W72a+()qZhyu+)pu$A@=QATC?#jZAv;`z>Z z`lyCT9%T}}pByRj$~O=*X7}BiEv!XYkAfNla!iDX)?@1vuYCpjTxe|Dr&s1a#Jwl% zO6jnLDw7|>&?(gf*tJ4dkea?>JVhQ`Oe6Oo%Xb2yuj# z`0L04n3@-#A%`OU3s%@6EL($I@!5Zum`fZ;sAhXUQ_08)AW#uYzcczl<)w@FH}UP= z)p?}v7mGIfY|eX3E_c-EFINq`tv|d77&L6OxYsnfp{7TEQ3aj9mn4=8QEwG+;TKFi z;b@sQZQtLxLaL8#Jz~T5Y5nkBnB`H1iQN9=Yz-7> z41B@~4vaJW2~5gXv#q+`%C&M-wdIAjj@(KKL}nzk`y_Cn!K3KWRo2Uw33=_w0A=ba z++NbhqMP2|A!fII%8=tX)sv$qO9;%z`p0N8nUXO%nR$L8#9&nKpR9@SUnxX#hL-R4lpn!e!*H!OfSeD4w3 z^d5zobiVAfAGkjR&E_@f>!r%sx2bn)4%I2cG>jeg2$i)4^pgtF=Y58<?u4yv>Xt>%y6d7QTg-;BJ^R_xFN^2Sr1)F z<14(jQ<;oD1cB>^znJ!FEkXhXO0<9@Xm#L@!`Ef+;l6rJERQmX zvTrjS)R-g%J+!vF77pKkiLz5gU}J3dT9?yO?JFhNGvLY1k|-LT)J0#*Ej3)aOq?jP zY+3m+jjX208?JuM@zt#FLxx%>bMlK49KRxR<;ZQ1X!~lt+!6=a z_yBRJY_hqTlNWo8pEBA@?f9!JNTMSe5~}{#RMu7at!>p#2RF?W8V#w*M+L{}DP$`O z6y-9m=gQYBI(yq#Hh5Ax*k)pcxA2Oxv;OHGzJ`m+~arms{4Lyt^fy`53A0nKm0CBdbO*j z_7Q@HzCXIV_+erUGyal=a2FHq=LZ3Q$+mE|N?lS{mucF3@PyrWztZ^8mE@BFh_t7X zA+mdxtb!$lg+@A!4-LZZ}_2I zZxOldD8~;M8y-|9=Q_(L5EootJ#+VhQ0clT%nK;<7Qy40sn9mUf{!v$(zTnc?d@ah z+<5Clw^GO#67e{E3#ZNwdQ)_>y9r7<>!jtG$&hKPm7HtA>*5_MRqNzJpm$S_4z^o# zoP;G}t?q(^Y2aQMfO~OoHbXUt&+%IwTB5L`Cg*#zh7o;6U(qnX6#T_Pg6_}15eMMv zj)FfbnA0coL-t1PDsB59KLT*t&j?k zOH2@vfuHpn)I1b4ewvA{zG%X(vC$-{azKqy23LS0%UXl>XZ5E!xQFLYx94S?F$vqJ zNPpqC3r3lo@5VKQ{BCNGpAs()e5VbV9#Pyoz!^T&#QvgXh&7S8wtrW|vs{!!7OSR~ESpCR3iZO?GUV4B;LTm&3-NA00JV98KG}GNNRGtLtLh|Sr)w&gTXE?!YDl9w{kb{Q zzFJHY%OkL;wT5dL7-A9^m21@|dN_AHgctOF?~U z+N^QhunCYLpY`k0q%;lOBiBFs%pbqmQpiOmIQ+D+!v{t@3W*EVCo}Bm zc*}Q>3p>^j8Erixe7#7+DqN0z zTu-jcdEP-`mgw&)E2q4!2zqMhc4MWdqE=jjhJ8#R%1`;f1_Ftg;f_6NpC7KX(w^V_ z0S@c+rb38rJ6`Ol(M5b-tU<`u(Ia(QMA;3>!?Iefh@=>_9?xm7e|%ypafP2mRwg#QPGve9VI`^Lq`o9b}p#hNmCJw0aq zj+dwSndU$yr7$=mTMnGy**sO-kFDj+0YM9ERkMFK>hY${Cx3zY-|NfI$v0F`pqQ?! zyjXy9yE-19&SqL+R33~mvk!8ZuWd#|aT)-f>rOXbTSpM|+OM}svj6d5c>&;i!>Hf_ zFst3A%bKpm%Mi~y4pv4F;?YwPL#T@E1gz>l`{Bd9Ifq2un*_>SVOkR#9(p3p)I*vI zT5D&2F`c9-+mm>Y_sP{`8GdzlJ_5iooYoNJ_7p3>fc(ODuJ|%EriL0bMM}>S#WNCQ zd%O}ovG!kqO#)u13eEA)$nru3ui%N6GoxEDkLEI={vGth<^$g!46}~3B;n2@6m{jz zo$Txc32Z`ouS>`xT^Gu^=te>zndJe5`AdC5hg77E#b%Oh(EGeU zyX#SybTh-6BNB(HY^=M)#GN^3pi@@;4-&KyUg3D)l*)bDUn?-}S@S!qVTZ+y#+|Ir z5x`}K0ntngQb=a7YU<8Y7@}{JGNepVKWEg_pXpZBmbGLDj~(z#|K~g6ZYNYg`;!2(`vLeKjNeDZR<&J~>d4V%>XG)B%O4<0ninL{-D7dO}Amv!4}>Kmk0 zkT=|O&?|`-;@K|cMSnQL-}|(fEz>{qmDx#bTKf8Ev-} zP1lWt@_9>PxiBV`@<4evvW!XlHYH6+Om+1ChmY0(=!5CP=#VFlA1kR5Jq8Sf(eDi#uCHa2A=RCbv#oWFHByL}>kf_F*dUy}JK@}@G1ogoShD{*M*o|%hL|Yz zeqC!LbG%buXU$@|sp0*#gLAdlqcELYsUYr#6P$$t((8fXU3{Wqs`h6caTcm|YYaJ$ zwJ&uxH0@o{@UK7tZr|$aOqAzmueHkzuS7P}(cu(^YRVKzR`sti5HN6QSzjv6VzB9~ z88nKWE4`=dR+rolL5%gPnoL=>s#=8z>#AtKDqz0$x5>mV%&`qE+#YMc2;@*m!hO(> zJoCs{RekVsqpIr(DY4pGJ|Ns$GK}X=Bznx_Kx1rvikpI!L-j#@so6(30?|~J!_(ch^B_TNH}bg zi10`fjZ80`{4Q;Ef7Di%YNE^tE32ZBVq0}en_S=>1=%KyJPQ#q1P<5wg20I5@VZ)K z9*pV@&sQOSk&ndL6%}V+F5^$9{{Ou6_p<>6&{d_Th;pSX2!e#*QCdSVuvk9x?clv zB$2EnjD~jc3u+REE*v`LNTpT^QTd@r-2=E!;$Sh$)FVQ9YNwCErj6;-{$P*$2Ci!> zf76Za*U^M>9GA=~A)dgWihYl=u{1AXGEz=#6k)dbe=e| zysl7>!syT01i^WFSkm!(u>rws@$Xi&WzVw2JqhJmE(7WVLU>xCMv>MD(u}S00#Lue zk^R@d3=?&14h{~0)Nw4n7Khv}N)VbUQ!WU!wn?9FP8@(*E=xfX%*|K8o$9f#IUBL| ze#Z(hzVSW?gYs`3;JcOveqxmTO(fTG0B0Tj)n8M1&Co=6c^LrkXncl$A zPJ^pXsW~TcTP1dpvKDcf<@20zdVG~J9eZBVW7j>M7JOA=Sx6MKoc4Z+!@vgBhygPXChiS&S@J#A(sil_=TR--zk zRm71yDC3jjZ=69hIi%JCWyPFF?` z5m!j-e~AH7gHXQ!dQ`rNDPsN;B~G=(o<9wqj9`c?_$(wxa%@%j>}DG69<(EbxP6QK zb`?USjm*^W+NWjd5iI;`RiKNXRcrHnhEBIE(kbWY0pV;#{RZ01m1m((9?xXo$DCB!Rwx4?^bUY|6%!Qb^qgU zh%X_AU?{R^{+k5?_$jDrBPB%{?8?Sty<|*fv8&ht zWhJq}1y-!Y4}p#!l(|@t;;gtOdiI~Qx%rX92FQ!FbK_?UaaUNwmQKYLU8TsriGE50 zk0@p=bhjdYxo~bOQp+C7!NSY&BQD)p7~7GT)^+8f?dxIwT{N1%=-T!21Na2X)ARR6 zCd+eAwbY=jLwdRyt93}9%jSl*M>lJpUt%F^*hNL;Z;{=s6;Z^L>)UaN0Z1xOsfsYB zc1_BX2WQqb%s0h<!M;Sa1 zWrq|51HS-L7$l)+N0y&2d6O3eyTWC+pjnB$6R#X6RdwY>YUAK@RmkHqjIFHz6OHU* zql{70Ixm)+CW1G@2}^B`DE=^}ShvgXiG4c96goEVzh15Me_z{J7ka(nyh-L48w#GU zG~~+&N@m2cSSABG zUzk$Vus`OLo5>MmxT6&OLfTVM34|Bns&I^hZ#4ryRxJETrox=0JV?6#ON`r6TP5cU zEqgTN$Zw?>_+0QP7*pcD-CkAzd==q#dlg`Cpz)^h|Qa3Ma&GPuUHd73k$eCry3_tn-0!y43xQlk}r{qJW^Q-?s-Yz-*JkYjS(2W zEt8seEej?T{Yp+&UTKhhS;SPAvPy7R`G7R-w=6JEdmPb%=Q_aL(BNdpfW?Gn&qwn4 zP9!dAYW)f!d+5hr0>^wmk4doFoRRWl%FG(6c`3?RW82WJiRqN;zo^9KImX=42E$(N zpK{CwCat(4rU3=Z#a}UD0TKL%b+48ocKL|St?J3&;ef?MsITbG*;R>-A&H&)#T`iPq)w^d&dXj*oMW?|mLt=cP*1*(pxj}z;3%;CcB59r+mXq|bI+Mrm${H;u54?U z$tNaky1cEs&wFR%R_GFT`gKX@qPBxP4?FX;m!QF07Dw14Xum_E@%iQvw_i6@l7Dz;furFYpr|=oP01j|4Y+QsR z*1d8E3=E`<(iN2-8SPAJEOVxB%Ea~?ZbispyH?W5@gX~giG^od88QCZxaeoTbdhlV zoi}@Z5j@AP_u_~XeKKZOvhZnaY{_udGeLHaTV><9cLC5F zC>5wQOG|CPeIskXeU9rEMF;)tsJkHPFdq3ymy`=b|G`&sHx7Hf_wn~NpxKZFMIdHl zCw5_ZM2e%Mj7eVMbKiDtw#s*jOHGZ+wyJOn+PEp@in&FWSW1};1nNau%SLX&foxE6 zzR~5T`;wIV>3lDSi1FWHx;upyynGHHXLMm)WzoT71&Y2`QNRlPD-dY*$A<5mv%50O z(&R|1fTIaGrhq4P@SLwYXTf+l%s?R=R`zZ5<{38)Rd|7Of|6>!f#VR3HHbiLRL^Mh zUuOX}Xu-j{)JjQzAEwb3d1#YEcFXOoC$tJ zIH+#xc6o!?rYQd10`(U>g6(}m1r9?XD}9X(OvFvl1C?$Io80t7XYQ#F3D?Ui>ZA3F z-13x+gkhqD;4M}icKS5%vAN|j{j@9LiSU(0sr$qxm#sdW$;S?%I*K<@+XM3SVLTF3 z(1}1kng5ft`DWy)5B2wtb!Q_!p0Tt&Vop2|xZOV2vTd%WfP(Bm>9tou>!((-o0XdRdV1P8Y z+1?OS=@8|q*7u1%nOM)49=L37$d0(7=mSQy6n`^IhbC!E%$`b?F@qXstlI3Q9U`2U z=}#trR#|b%fSMD%OYt}}OW*jNK>3#LZlCgLFAe_omK%UWj!tGJ$5|5Tn=q63LU$)Q zmeiK{ncftp#@G*i6A5soJ+gXG7@QaV<5cWXaZ2sJs-+3;*5xPq>OT;< z`!p{6yipo!GX6cUG^lCOXyGHQj;CDry&-8Y;i~$3G`Rp${P4JB65}PG<$D4%d1kPhTm@EL?2)VP`Cv_EHJfMn<@v1?P0C{KONI5)8H_ ziD=i43%e`|a#s>et@GML9c>s^i0}&;x@6={`h(DoPKee+%ZW@nw#D)?8;)A0wKhJ+ z$zDSd!H3(+zIQJn-0^P$IOVCDaJa~Z5xZ zd;!Gd|Mz0*x&h8z^5Xz<;M@qDaLfZZ=@G74qB7=aslt<~)S4t&zUBO4{GB8dR!9!c z5E8AkaFDKILvzzG8TjJ@RO+y`nVr&`mHdqb7jJ%C)Q^MLq*# z*Q0*9tD%!t9csUI<5;WS`9q|2q&*(t037vqBf3=aA2(aj=!EhN!FY0-Rt2{XbncPB z2PMC+9h+*{@7--&`Q}QszhrA>Yr#mcb~^lSex6=H81B8GzZhm<&R3aGD*f!YMUykI z_qnt(`PFcI}2!_u%UK@nc- zsocrHtlj8g`TBvZdfVkbCNC3CxYBgDZ0aBXag*wPBL=yg170!hjwSU-UhKYYqoa9F zr>Xi5`O>KzZVcniJ&Ivd209s2thVANwYnM@mqt-H+c3!6(HJ)FAc8SqiK)Y95mSz| zG1%J-k>$&9Tr3#;QCR`{C57lUa|PEsI6k0^fxQYXZsy~lvtKDO;2g2BPhz2-DR6*| zRy=XsQ^3+aJ>rx}K~d{luqkV=nl778)MV>5{p*>15$O8kqX`n7LF-V%K`C*bASfCy z&Xn1**u0@4A@K&^!V`JAk$KAnnKhy69YJH-=vJ5j?7YrOXBg7;T{=u)aCF7xz(=Yv zSw_WPTb^?@y-&E?M~o0e$W(n&{JM>Klz`V0lMmfVwN7cz`3kvqUOLo|neBel_^YAQ(m7vhr6X<07>!7G^Qvg;H2O8YGVka&6 zEfO2MdS++Uz1iK6wFQW+dwDmvM9YHWK4AqhR|cDsvvlL37w#63XTO>IYr1^TJZE=Q zaCL!=R`1|9j=M=(lM~+VGrtaUuRrLjTC<|0dJ-Sryq;9@w(>>eb!Pl72eo==WBe zCFNM+g1pKk>UxqWlq63D8vIXh6Yd^Wq)E4+wcWha)g+>orgZks25ii?Gds4r{!yl< z{dIV?2aA^Kl)(im9y$gjImcgz%p~xyX_0F(hoHn^hOSQTUgqU$8_mJdNS|YCj7P8Z zl&7GSboM_T6nSdzszrP<|ERed&ov;}i6U}6kMVU2G9$@l>yoQRI$W_-T*V5Z#XjhK z(N$?O0lU>RWFfL*=_}4IlI%}c9fCxY989P2SiiiLQ1)K~Gqh+j2A78czqQu``iu^{ zqY-DEHOMP*$idjZG&|{d!IGvd6&x@yUtbC%|3!#8icAnX4Zcf@ImTEm#i0`y{h9uA z&nK$KNy7>D?#+2gXcAhc?^Zm7eE**|pzm!%7 zDlO}T{lbp)c%&EwOT)~88g?eT+y3&UwgYn(5Bd0=ZA(A^lq@x;1z1pm9#gC}MZzR45&%i8Pk z(?hj3vj94+c5SpW{^v=E10m!i2OyIrDd|@Os7vs{6WEO1@+OU_FfFk4iBx|?FqNr zea4G68+$+TohTy$T(yEh#hKwt=Oc7@!LTABI9>)* z!uE(JcG!@f>~JrCEdUaYK?nMwO?G;mKABPM=I5=-o@UZCI>XWn*U<8(B^aEW#Q`W+ zO5Dd_7rF`}hh2+?f$=UT1cwOHj8}Qs(2rc4Z($}hUu)BH;zy1smr}KxnH-p4=VYa? z_d>E3^){#6VTzKyNcz2I_N3hpFqY!fd-uPpTndMU8D>X0`+WumaCY~y+#@I{L7+-C zap-~9$?!*TQ~ytdaHk6OZ0n!9&Fy*l%hv$0r?B`p5S# zam_1+-PgvR&ry&>XGB1qFH}UqjjE+!P9wyVR6@ay$SsBqvQ>-;KTt44#*I=y!B_8Q zqJ>}Y2j5#j<)@S>uhe}v&wj1|W8#p?g=hn1ajB#!osbClkBJsBsj><=E6OuDEG>Zm z*{(D}o@f(L{E~eaP`I@ zI!16Nhj>cf??>AOdZe8@_PXCIRxL|xlM5Z6vZY&2iIy<>Cqc(z1cyE9sA|ukgmT-G zz7xB`vWB3damtDX96?rh$r{+>>d< zs~A3B0-=xs=r}n9z2x&m5vStQy4ex~x4ACm`BPM61XEupOLDK$;NUPkc^OdPNset- zO8!ehyxiQNf_5Y(YXVvB7;BoOFIrgM6Q{V2Bg#;H4?=`}8UZe@h%+jp_T?OT`+?>_ zh&f_ApUwOOTEt?*3@`7C=M81%s&4H8l!sH$vtnIo83ngz<-g#zt^Ppb`fp&&GU z{L>be=S8L|Z+sq_jHA70gkUvB)_`5J*x<5{YsjS+#&r(%puHk)J?Ko@fi10M^d zW#e@h`>&j0N3a7>DTDkhzJ-R`s(*`H3CF#}!!kOIb8sBtc{mf|aT6Z$m7oU07FObQL3I{3i((%N605jfrkxdN4>g;VCfWgo%isJRBDC=m2@~Ygyoi5Ijj%J8W zKSmc`Z1SY>xJ};v05PZMr23tG3Z1%L1ev-MKX=0%fQH^TXK$*QwxE@koA0_fpyEG>$5{YJm38LlVu-KC*ZGQhC*2hRFA~vg_U_V6EfHRDuRAP! z>2+C|)DsNM8w>@XHP*R-=V(WVY$nYFX)2WZtpSLJFID0V5&eo8X+4P9~geH*cBe#)rLWfZuqNmwfT%c zQN+dboAbpp^M;~b5es)O>f37;Pkci)<8Xi$`SK;V@36C2XSbSLs%GX+rdFriyo}vW z27xE4%H9a?gV5_8(rdV{o;&fP@2OJz1fmC>h==t%yvs@6(K~#d$>7Z!HLp~j(BRGi za^D_Cc%scGcH0&ZbmiMm@|MX=LXS&>PLHQP8jAGTg1Kp*o3<8%79F22rbWQXifOxda`(x02+Kr3{s4mvb7 zh&BWU_b?3>22M#vr{Dhm>jjRER0}6l+qsJY{|Sv5UtsI6X41$}E3NR3=bRYlCHY5ZH z+?EOlX$%cCvDv*%I6heI_bDqw^3vzG1~{jb4oV2&uD*^j2^fSYF^&gzNd;=|!I1G3>&4RTC= z=pXFO(eh6!%$g(2Lh!%lIEDMjC3`dxh2&NC=%NjoKobyd%{E1%g#vhz#P0BoH*EdB zdO?Ocp%ikcU_%8Cqoh30w3ufa)_&7qQm}?C86g3q@g$kBk@pm^=-Yl!)nAyCatv)Z z0qEda5aQ~hniKu7`I5stIeUzh1xLzfcAEMK|?60sAw?12)3M2{4cL7ys zxi}QgT>(7bcC(hpKA~miCYn9m9NK~xuSsYCS6j}q&dmh2A)#a1UI~1Gm~th%bi6m1 z&p|lrV>)^(V>$r43*TpEPfox0u-FGazfE3m#Q=vx1TWkeB_7{}HeZ>tc2cbOg`V&8 ze1~Sk0Ixgb_qhBJjlM@p)?yz)t9^ng>1M~=q~%CexoxWxoz0;oX2~ti?0KBws7I}# z7?~z_i=yJd_koyxewDc9Fk)_CZk9~$fM5JLa(W*!Y+-6VWBC#2m3?%OF!c^dn@l1= z!9gjOCp*VYi7LgvDO(-aR%X!NoTMOvtr(5MBf&4 z^(UPeV&?duO=33Vq`fBK!4|M?M9!F!U)YdpSj&ISIgu}9p&Tq}Z-W{-0tv=vaviu6 zwtb7bW4{s^Ju1%$n;S#@xS`cw5B9WH}_2w{mFWx9fV>&2v%A*B3c1lxf^`E;iINc$K zJA!!r`LwuYh7HG1424DatH($0bFNyXLj+>&T7*~fGYeRyx(6OscBXJijthr>B<#1t zoga>4JH6*&>jwMhoW+gk!-w#bY>5*Bky9ji^BVcTOv1P*QU!0cV}EQ24k@zdJpt2) z`CNv|)@Q3q@|Od3w(06mLpx>Sy)D zq{)_#a{1C2DU+5scIqQxEuUQ0@N&k1d03piC;{_QRtiXgj3x5+E^51((Xk8=xb$2D z!zfW$<+_^T9uyH0f&O)EICoz0-#;z61s%7L5OxGc71)a29daZbKL8%COG~b)`hgfz z#y>JgjI_>+bP-Tl-Bl9{`A2fGK2}%CnY>a5NEb?H62JkO#!rpE`&lhq-@@TKAj$j? z`(qR7#Xl(I|4GWR1xLb4HBt0mFR>(mQ?Ry#!R)_Cxw8tiS>(}%MXu3|+%X1%^3)4O z27WhMXgk}6)$pLtt`>sW+`ztc*tm62*fedPGOLG#Owq8|6~~J$+N|JIJowsiQ*oK1 z;(tPL&eh;7Bluo!xID>0fw|wx7DNa&w&tbx;Yo*xlcT;+bFJ~HVfd)tF61U2d=!z< zjXV~;*irIzpw^O+JR0x~ z0r1FIh&u92rP-f%%}!&IN-J@s2VlwA)7=SJN$4m)1?@Pk$giFpsjG+tx*7)IUE|o; zo#n9p>OZK@tFSbc2p?olkRTr|rgffkX9egc9OinglE9RHDEE+}c5c8aT?{;IH^sq& zEy~4E0;IFci}v-SX9_Sn_M^hG9yV>2x$dr1$A`1200Ha$_M8r7&+KtTRFzShJhHf! zo2==FM5_&9^-4_SARS{<4eXJ5E0SSEr})EP94Tk$yBT>!e=h*fw+ zO8dq<0VstlIO-jZL06d!?omt`^N_a3MmA*q8*P{ro@d~5(`6H8sbk%Fqz!KrCp9km zR89tK95|D1ElC=KhOZPU|F3^JI{vSk83?ruKE$T;F!z;$iM)}mPxRobJj+&4QdjP< ziTyASq1sW9(5i_rf6@!oWsXD)gq0(b`ivRbfv;SJXSUqmEvpj@lQ!$;t%I3VSs}W+ zht}6$sAaCpotzBj_Y>mwMtgLn0aqQzJ0hlh z;K*&U+%ynRksCTi?VoCvc!acxpaXk-7;83M#9)Lv<7_2;r#FsA(nH{Mf0aAauG#K` z4ucng5QZ7vRF6U9kp>rA!_4|-V28G7mK>OPO@T}i1HID|=}NsY99^yQV2uh_lt<_m z3W&^ED@*21{Xv{m^avn9_%k~J*-7$DQ= z95}Sunj01PwA1gy+jGjg{@b_spBUtb=TJ&VXG~I1;8W6*du>-h<*Tf!?)EpYm@DBB z?>m_o)0i;FZA-f5ADh)hd4T&FfdllYUGe@U)U$&LS`o5~;W`TUd009dNBx8{$WepqS*XrFxM5vqbof0)j`0*=JS z@~!n{P7_T{_PSmO;Ey@g?2OK*Ynk+gm<{vtM!_cY$j}xhKTZj(*_~%U9bhB|DSdB> zV0>;QRR+cwxnRZKFT$9dvD@P9fT!SZZkcLdF!v`}Q3oZouGTbC5P zMV>TYUVRSi!M?TmRA)>(MKrb+1L&|j&GFW!H$rtVOlqqB-K*Q4DBx}wwSG5Yko%*u z)?m?k=?`W@{!i6T$q@@%+i0#bMc{!$Hm5R`=mo*Rwu8JhhQb+DLAmU}uS5lK0ZLe} z5^M>P=5juf7l(h-v=m!uMnF>( z0ap=#Ysii+E}A%q5xov|dqreqqo`uiGE8V#WLZ)PRce(~R3h6N0w$v{{1K}KVceY- zu_Q7HWUjw_ce6>&$l(9e!@)-!sy0@v9@AfNM+hf%am5 zF0Kja0b$4$r5MRvPtB&ZQ!$A!(*Bye{&TmGusvxUhuc|>54V%o%X10==qnR(Fn#gg zmhq67!;@MM-l@#Xdhxd;6QYJPWzhbQ3Z;L-R&Hn0Zc*ilH`=wWex-8^NT;cUBQ>@C zW_A5$2C)BCj`v3yx?H}_4^QsKd!M{)32MCFCmrw)h^l$xhI)l%op&X{wXWD(uvzlR z`p@g$PJJ)AZf<_sVz^kYj}od=$izw$ZFjP!rKR~xH=V8rL~7~h%SQ)uM4Yk@#l=o@4d8Dj=B1T_HQ6I- zffgF|50(};D%%d`UcOHdkD9o@N~?^XghQsq-~XclN|;U{drf1hwCRv6eirqm<&LEF zVQ?PxL!DfEf=Vj5vhlgG+8W=o@;KMq24T{JPbSH^rgmrogf^!#zlSu)fbv(ngs5eS ziDvS%%MdMNk#_V8a`}gj2zv#IvxyF9a|u-{9}HW62blwASwi!H_4D({XrCl|#KKdIcT7p8+j&y+=uWuH>Fs3HIx<+^F9km)o#@(t_(oox#~-nxZ0Cbn3)~ znC2($XUE$9*>;xSmAPgr^wc=B)=z^|9NAj!>1f1q$Krlb>`jIbG%Mu9fD}r5ny~{D zlj`wa-=n`+VL*4|D_Ij2~5ytwov-Z>k ziRZnndk)`;LtcpgmPmF&b~Vc^+FN9>DMBp*CJ58l84ouNx5RNT zm_Ao)^Q)BJZUzEkd7uLR)57BYW2HOz zRY|zd`QJrn4rNE7rm!Kg3SgR+3{wx~qOm%}nLd80U#4Nw2sbKNd9R%ua&0{FS0jMm z&aJ?_y)Z%Ib&uIAz3Tv&MRA?td(VjqTO>~giu2um^P(Sb&&yzcnICf7lnGvXcz{VM zJ~34R2I=`;DLqq}^a+Gn_Z2*^>*+}CCi)(}J zH~jX}-G=pg`L^%pABen@p!lWzN#UTug-&BZkab8Yl7Sd0czNEDP%7wijyT@WQ`(k#TIuOw4^@NZ=4vmysU9>aDY4&9h9w1XS96A z!OznU_~; zrvBsGz1nHZ&Yi|=IjCD58$9Zx{}YFfEy{-;15C+?vD5IR{*NJDw<1CrQiNUs5h3T% zAL|-*={T*VTKWSq-oSW4@%?r*es=GPGc!9ukuue`JqHC^SVZ)cfd2u-iTN7=-b( z*%JkC{FDwJus|>Q2_6(NbJuhNp2Xv6{%%pierl;*){%c-yre>`};5@=`Y|qM<|$1U6{};)4%YDV2E1XJZ5M3$P!D#InF5? zcc3FmS}79)`}aI6+NBH%M9e+Kt;!%ToUxxhM>#C_BvA|a@ughFR|1T|3F_VB1@a$k z`e!+*+UsCY=pzQLEsJ+CpQRPK!Uw!*D8r#yMR;n+E|(`A0(tO$k1 zUCX@1PI>i=iEX%lcsp@@MWe+vcy7zu_5;fX%AM_KD0enZ2~Eugi~Z-#t2EC`hgNuYm$KrSZ(P@2V^fSGQ=`6gvpqE7>0vWafpgG z`t*!{MV4j*df8H`vwTyrGqs9v41#|IzyCN1axA}#prh-^nJ1r8{(LFC2;>8woEq1{ zUaiF}+1`B(m_Fc5HI4VX#i0vX>{MiD`UwC2&Y@ddckoL@cyp~M56n&5DeR-dSWt`I zk9G6QzFOoo>_FhW&!06%KBp1(AwSB3?DOKt_R*gh(`3F28kCkE+qVULf94&Zo?z%D z6ig6l{%X5-&vbLPy0`^-=+p{c9~w7xD1u0TDxTdpUviJXDyo6??}Dfpf(C=Wpc?CC zroDbs@Cra#4?iq8Mys*nkAGICUF97*w){ZNDzV$_geK=Gnhgv|Pxa#cn}H(Oadr-F zWP~4k{As(E*UF$!m`J*VGHzVfk7a1=EJ_f&sz>M^}jI~9UY~h zrx%N&mD1E)$w=Sw;^iZ9w1f@(d*>8@q;Wo8^ic37L3VX@#OZ0q+lr+**4~r1v_#&x}fbo zkKLO`klPDbgW8qQwU1drL%V&uH%2wd7MWPVt2TbfbFG$?|48>0%&qa)4|&a^uAXGv zuV3P$)VI5LPvDO2*1>ywN;$*;|K1N7#%5DNn&UKELRuRB>ZSUx3;&Tos;OX>h%A&} z0y(-WhJVSw4`pB!@1(_XkYvO6RcLf7V|%;t3iPJKrCjRCq?d3SRG5a@7$W zVj#Nes76VN7gqi$6haTDrHJLW@opx(*8Och>EUn(@4hvCq8VS}&x-0{5Gze5!J#X` zga-BtCv_el_%JfvZ9Ltd=y(CNa!x0m!Rc42ib_NT<5sd#ABJAmsED&8HJ;D}$o~5p z#Gx-?E^!w-7b6z+AC>DoU$}X0e}4`Ocus3M5s`kHXYj}uF#=PuJT#EIJE?r~$#z+i z;qkSwQ_StrYDt@);v0>_wPKJyf=_p+O){=0BE=EZ+5r32?PHb6i11JI3D4zrFtH^? z*;LYyEg{25^wu^aSy2kgRqH|@{xY(wuJZJm_j6r9dgkVYCsXL=yK`4cCI|JNifgy$ zzOy;DlRo+)-NA9G(UjX6HcPFDoypCJ!u?=5P%vrR$J^ErY_+#UD{8Y#`^?~_bTxP5 zFIrg{-g;-t*>;Bf(p2e>F?{kuQL zaT;N59RlT{XE_ucHq<@W-k5a#i+yBB&Da#<;Fqa>%}n*HH(i?(i}MYFvf5%yGM1P{ zNm51+hqNm9_Mk`kkY25YucKxU}uZRHqQRekEQ4IG&9qb-yh z$e`1=#p(Ic+e+;+T5Ykmsx>uCWD3+IcLt9&567)vMs4Qm{53Li-&(ucFZP%6if}5& z7k(WT)|;D~(~3%R^NY!Qd=zWn7YmHD(%eQT%xgy}FoPl=4O|p{UUP9nnjG(%xXGU} z6NPi~zXoD{3tpN3i~=wp1ACQK=C@tiK5>?Pe8Tzffp{G}5Z5|N)}e6Pa@Ez1x*0C4 z?xk^fsLZ?N?Ml?A{+cVtUMOV>llGeI>ns&5uSi1)h}D+94Bab^ z--$hM=+5t+Xez z%1kFHzPDMyuxBq~Eg|%IKk=D3BjlLf0sjHRA=@US4>TBXE^ScMGBiuAQ9H4Ipm;i+ zVXmTt;bCzi;xi7Kzr=Fb`_I&opcMN*Md5H{OC=>oA=nJbyZ%@heZhYdT=l~!Xjp`L z7~h>yiEd=qPRa%4)EQ;A_32?xj?)c0>cizb@H)7@n#ZOqkH&B@Uw6DiPhEYDnl#&q z+;`+eS1-jf1ike@Zq$)OQN2myY)25VU2{4HB((C`hJUDruZS21ic*Im$u<1tF9B;* zcpl!&XAYLz9&%4ltvi1emSD!lY4L~enZ_q9GMGAH5YTChQJ|4AG9sqU3xemF)y75S z{c=GPoBZDU7>Q5_ox0yv$lrRu##I{6)boMrD7gKCxGbA0^LoCA zcp-h3O1$b#FYvj^i(bAXGWu?h<-{){L3kwNwA5qZTZ&p_R_a!9`>KRZpIyC_voxZX~a44Lt4_>-|4fu%r ziD~qv>yKw7B>mGgyf{^h(L*QXXt2AEtUo(-sPLnaq8H_CD&i8sf>YUMOK50d@9*yq z*O=}9IL&vpl>_=hr6t;Clj#5KUpR*!Oy7vvpuN^mMG^e#8Nz$PS1Tt{7N7C(B-{sl zo_+XS+VH9thcdtJV+9F(LEgze;|}{2jK=~-Jp!Ess)#*bf)Z=U%2iC_A>k3PE|!Jd z?~D~=Kj-Aa{+a8*E7J)iTWK>e7$qPj{oTAGA$u_ZQ534@>Qf2KWT4k;0!3ZjD1aXL zZr_ozroI4-h9K@azF^^o_r1&7oO**@MYUL_i%fLkLtr(DPi(pTYxpJt_cV&q_26aW z!Wk8rv1Sak`Ez2@N+_8H+I4;~>T!HddAvQdvj2E6-jlvciEp<}ws4>}jl7zEzW($B zf0loHX5ZR|fnzvkA+5(-6Q##jBYnWD){7aPtdsSB!v->j={#pS%HRj`_1@_T;JDW6Sj(2)K>sxpQc8WA(}_ z{cJz<4t7?r9-c#nODNG`iTJX=+rrCKEAG1N9Ii7)v}a~w%AI6=H)p}!A5`6&h-PBLqLfFO*kr@&+-ei?rKguP`iP3Yc$s^=J!TVu#J!iQAxjw&36PLc%V0jomSrA z-`8nlz!i51a=Ld&G zE(=4*K6L;F4IRyQ*2SpO{2|prBFc_Z#mPK2kfLYH*73u(G;w zJ7?=0lE5~qPLo*65fanB4+qlUfE6HXk6}2&Jf%(Ka9AYE&MhM=l zr5^?Rs*MHW0sCG(6vp0^w&rfX4WBw1{*1p0n|DuJx%M{G|*$ zk+@?rhh_s*T1(YC22h81NLY5xbU4Ak9r1w6)BG)y>-M5V$j41J3PsEr z0(Vr)LG_6lD@|E8VO3Pv68PC(sh&6511zNz8&OKzA9GdQ5+YU_&Fx_x zVsIV^1S6b%?L2SOvf%aTY?>m11!G9Uv%F-(x~|D&gjV#X+75WraD|{DZ~RgvI+G21 z>S(%gqn|0ezmfpa4OGEJn0$RRK@2b=jW}a-xkr9e{4kEOqhgQsp!zb3URiSa~nM&dGvIY$Pr04up zSNHu4_mIg`4aKKZV+my_B_-uKUyj>j!Pa!9J!6hd?l3XN8!P>D;IhupL57x_u@nh& z)o^axG9>0pgb4p+m#*2PEq!6X%NkQFc|cs=$A$PSpTGoq$zhx^YV3V!Z_3~dQ(mJy ztE^Y)v-#AR?GXs3jUN%{RCsZF?rJ>q2 zy!Iw<0(YMe|29hu0X6kdL{=-pm`0{Mmzk3!G3$bykPPQ4yIEaX55MqU|6zgUEEQF` z4b}={qzhjj9ZqZ=Z$W2zTxd8(2nXH1acW@D!?2P>?Z<$OK6+o#G|?{wR1Hx0 ze7%A$TqoUU{CF5*BK=m|Z%C(`nAr+y~zCx)BJF!p6y+2A8_+2$|Q0Ok=wxfi# zOeLPj9DVe5=`a+}T-|X^=X!cAKoP;$iRb&Y%)f%RZ-0@iNM#h;;-=0A2#TvRE8Hzs z7`MgT$%w`P6?stWK;Im)Cm{}iP8AQH;5(xl+{wC*RJ!57IKayox{JFBoW1HuI&zOJ z_p-uoTWQ$u#sAuD_VZnOV4J%ukQYu;=l)M45Z|PsEXvEPgph9$v(lxUp+D5im`|K= zUdNyYCm4-JFPi0rHrdlkH7yX66XSw1xMG!S0(4|Qpgicg04y@F7Z_tx(|M?*0qik1 z;Vm|{pOna>jL*uV>jtNzS0^t9yL5dsZA`mI)ikV<-!?Yg22i10ly)c;+drZTSyxH?{vL`9uN$&lQ~bAu;xl(V3vMOd$M2; zR57|gnXY-6Zl>{Q#1E8@OP{K=+;et+iJ?r21eb!QMuRB_+mLQ+$j5!Lmc+vtP>Nj@ z50JL1sJ63Ip0zlzaznwp{u02>l607x6S5?&pkLyWLbUtFPaQ*yRe+gCJxNk zM@TTe6eEvWlNW3WwKIlwvxh-IbYx>QiUlq_eCX02pM zet-?&U`iW6Me&7tOa3i|SgVy+jUfsWA#1m$E-~akJox=9S=Qa?18bmjGe@`ZSNaMX z{jK7d_BB%i0-Lo_+y~aVwfOM# z`*HxOl{F@GbQGyy6>O`v^7-26R7QirBeNnvFmJvBA%DKQ$fE zso13ErzxxA#??y?1mV5881-8Jq)bgY?eGOBzH1sf9D|)3QYaRCuO+!R+NqlpaUio( zr{PC+n|>S!{3mxZU*98#L@iE9wkXoHzM#HQb|#c=0@$rl&vd==(fyw|4{pm$sudAm z>WpB>G8yABr`VPhQK_WLf|;v>-`Unf zC^x>P3Bi5m!HS|Vgtt%oVjW4m(BperRyjCJnn8z%y80ekZ=a+sH#Ke6V|G4%j4hy# zDX@L-Y;CZEyU8F*%2YaQwmIAPM>>@ITypnmnc2XgoO*3tteDSyaCmGJ&^6MJAfz#w zvwH~Nj97sd)trFNuqdUEX;HO~c`oXe5~aPhErtvl^jjt>o2V)X2UToj@LRdMdsUl_(70;Z3xedD%kfkf`G<8GiUtl$kkXTI6RSX|^@~myAuXCiHLU63_XY*G;_pJkG1TUZ=3cj+V9h zO#zz(JK^wU0TggUD%#3C&QE0)Gld#FH&2%Ljnad<8^asp-+Q|D7I65c;^RMypANax zmbtm>usIVl06@ZNGWu9(s`1-LJR#w;eESH#a6z|xSv{)U2mpP0-NCS*%5+#hbRt%Z zia66Lz+m{iih@KHfP4&h7Hg5rj;m0(yL}%y+V|Ai3L`RWz46EFo}BL)Dm3b<1Mk0J z&4y`-6~;BWP)n8KRyT+fEnmhg>g&U{Qo1f<%~J->UBPw_9ZYyGc}kG6Bb4k`wWuU( z8r#o*QwDVEc;Q*~;p;AKM8b$7?j-pk&{Q`41a7?}dAppXY(Z-`$GuE$(qawA0WH}k2_GzTOpn;0dLVK#+WSwAn$s2bFnrSL0iP^d?06T zWv@Y0JS^Y| zE4(w^K@YCoPHIw^#cTLU%G!o*UP%A{TMHn0dOLw8TojjLnKNRc!-ayk9%O4n%VM$E zfI0!kM@nuz;Ba%1?4XGUchQkz<@<(&L6X^bVGG`&8-h>^$mMG7_cXBDa=Vh2%xMM{ zNEYy+9Ba4GVe=i5-P#i*L0fOgbF)UZ`svb{i}kkw!yelveW>sYQM?hzan=%Fz& z!mM^k#}=TFi|R z?|?@X&9Bku5U+h3%|UIO?tTak#4Y>1T}-Y!k>AU889=`5ek2w6^!GgymhrzX+X^wD33#pQHNC~k5asYr~$R|TSgtWzMl zf`E1}5r7mR7I}~|7JMBZLS^~}q`YAH4#B)&j>}etm*)5HTodw)q_o-TjeyuQZHJbp zD9zz&YiQ$xj_*ly291y}CjB8$DygoaXY1*}srCMKDFnct0aNF4wRL6}W4D6~b=J{* z1)?P3S!3HX=cV1@{~(UdSKT{e=M%;p^Ph5z`^g9L!ZLEjR{t} zWR45JRgRN&>~VEd(=G2N#~f1F*%>~^F)vK-^9NkD$_Kv6CyJC4{4T#npwF1i$+5ZO z@+(nhXB|Cf*V703vx~`uXgR`%o}+Ov)``pRz*OV)`GDtmCGiVq?3nK@R86Wq5}h!&0$T*KIy%x(d2>Zi39&H3 zoNMQ)m}?FBerrjuXVLO*uNWuAED7ETHSJ<2C(VskvZpcgON z54aVcE~FlBmM-&8$eidTi8T9xV9If_p57Z8I_>B`HW32IOy~=Nlzx53`#N^)xXmo! zzdkuKCc4*rG(JgXG+BN)a)Sk+hU%l+E#SSp%Cb9n`OHq5XIg8?viW5=2@?J_uQE#X zO;$I>5tHB%{&n$SzD0R`EqFVCCcV*<^X_0}q{A9H0Q%ubp(ep|RA>pHq6|Z1kp}n> z=*+UbNfoIo`jzv>pffa7^eW3MK4G_r$=j6Jb^Z18sz3CxrR@k-NX=NOpGP%x7z8L!sXi zYivm2I&_+U`8&B(Y(P8Xrs&NihSPCmwBD2rv-{0=B`ntI)W7YMOpcff7;3tb>A15U zxsPe+;_t}&p9>~#K7Fy{5@py;g&_HB$11Q+0VveLbNsJ~f-^8q*<+Uq^(7?*)0zB^ ztYSS-+o)I2$Ww|9}(vBH3S>ctyk{nd?=y?pBM+lBLIsY z^`GQyuz}>U@RaSDIo`>;=TrJIGbtCs8vw!o7Tet0Gy1=Chau@+|A1VtxPL-qGNeIv z;B=ErRm7}?k!WXLHE||0chS$uh<_y*{xk*t@@#&e2Yt0V_BNWuRllbmV&O|T3k^>; zu%%@c!W~c+q|^T;7@McM)$%X6By9Fi9-8YwR;iho zIED=LwTQ99nM9`i)v*!XmauIjGTnM%mo3h zNrjh}HnFyb2GL5*HgcW4v=)j#65)0<|CzEMw!ynf#!M}TNJ|n?{UQ{8zey6$_U)6+ z*&NJ+-;z1{rvy4aWSOVrFP`fLso%>xk{t$|h3S(A3GUpBWn1Fi`zm-^8KMQuqVn_{ zc@|0mnYz#LQngr8?1{%#8TJU0cUMaK|9~a?qgu3=f#wR~F+NF=3>WJJw zm>P%y%uG$M;&{(~X|$zCT)V_FJQnd_)MSKSocD{wQP8zn^YroQ^e1q#ev71gnbP;T zV3`>=peh}8Gdt4UC_#8{s>tNQQk4Z$X=>jiOm=+&)6>j|7a zqFw5`|5|v+>PT_WYz!vm++9c4(+K{>5X73RM4(m>-FT;qy8 z9_|hBYBhqnu%$At;Qs!{43P%@V**n1g(}MGs|@u!_#5R!LHpmBhcw)H-qD# z{r}%bZNB&kT{m7#WPI3Be;oB}|HT51SkhAVFv#r467=_d$kTZ4F?`j={=!lQ1yJfz<0m4Y_xBCX=a6qLU}Trz}7IDKDNeaYNsiWyY6TL5A5Vd z1lkHsb+E;Xr5b#Y_|hp9K2O2sT0wr zlV4Dh(3?!9qobrBL62HeR=Zsur`%(y*(qR2Fa!y6)I@LEruGl+SPms^by! zad4N6B)8kkc}dWCrf6{&b`F?t?3jY>hL#Vs=|U^EI@GcZe1xzlOeb66p&O2SAlN*9 z(~v;jI;=ivEn6If z+`Cxo4c)wkeakyiRGo;aTC0>~fJJx6#7$ubab#O>opZ+Otbnx^t&$qV^PX0Lj-e>33e?p+h zL}C83!HcjzUNA$a2x++9rbs{u9$)3yjczB$U&@$ zzagn@CV7+G``{64MOT*ht04%#23{-RHW5%FsQE)a&zT=U%BNmYSAxjV{z}Nxbm!a%qbB;YljG zZf#Vd)`4ajzy?t5j0t`BD*sMxWB1umg)VqucxWuK#?k~b1&^Bn6p_>J*4Pu}{~p73 zV_*k|AlL|Y{(3{}`aa)Ti|qDd5Kqm?V7-fX=T#Xy%Si%=<*R`u)s%H1}-rc?WS!+FOE%$w1 zsJkob(3uGT8a=+20$qP97SoV^{zVEBiUK?b8n!-Op_e_S^DSPr6OjMWOWIqjvmr8C z&9LGq^&Rk3qzQD2g4OKs_Ra3-x~ZEVoXmiDj@t!1lUtlQK*;*nu8ZGtTO1g9@9H5! z8uE{*4ud$9Wd^j3PnaAf4VU@&kgbRy$n>t*@y}GYf9tTtu4-}i*c*7zJmSHKBX3r+ zzv?qXR!3u3v?cKCr%*iWn8BU)T8Ko#EHltR7mihxn%w8((4_x#?8>Mw#8-yr<`+_w4Ssiebbn$x z2=CpO;AC5^Z(4Qu&XK%2f^~4!^IDIi?|k-871#E+>qlN3iaahpG?8km(5zC76F*i!U;_ zVhU-|g7hUWtJp?x+!MnLONyiKJ?}e!@H+IfW zDhx+bH@ND41nriRZ38N}z_^GSz5>F$PqfT|gASv?`xqtT#=}RRWdtIrfxu|%rUz1N zJ~XmH7JR*THdWaoxW}Hf=&zhUjS2ByHb(u>abMS%a9gOh7$!1vC-3IrMpD)KC=b>Y zY4YtdNGFE5JssaZ#SLx(DFOuTv@kaL;A%W9EO5*kBS~Ls4>i0nj7bmo%7&b)3Pzny za%Fi{H`=h-vyK<6d6t7KF&>z1ja|rxu*>t1WhZ}-XSGI&X z+GtK8TpjV{f?M^zYsE?9r@_A2dE8Yuv$uqYwGlFY!*q|}VLgC@H=in}%&Te(1@wL< zRIm9QOaTbb2ieY0DkkLXi;(e%3yd534M%aD4vkXNNws zlNFcq|71{E9SX2HF07s`vbAT>leK18_HtE0Z@TP+W%fH!qhn@!t{$@U$zU(hl-g<4 z#mqd3!+ic~#|x!{6dgA*d#8iAa{s=u)Y7{jRngA=`4;GCcRrczC7S$?yIAa<5ZYI0 zux*j2n~DbRJ3A>;(LXTjO;VBodw?LBSee3DsXFHBOa(L!lI32P7 zPfG9KoB{u)bEEX~^nP-;&*!@R*Uf>=wvAUSje2=qPTk_s)Iut;MzN^9mylSHnY0us0Me+>JW0;Z`@T_+)?c?Rcn zNH$;2XVOy9o>UIIv@_E-SbM0#-PtPAw1;-z$+#q1;;N?7f$jKqZu^fSeKE99+;S;^ z%yF1?khzpJ!--X_&7N`>`J3d^zo^iZ@lQ1=mAk>70<+FO|ECW3wig1&3kkjG^ptM` zLZsRLWJv3jK}!zq+ep&UV&Yz7P<^d*SPXYK-RW&y_-MGbp-3qfO=AClmDhYfd24T# zqX03uvTTrxKQeNq%Ugvl_nICXP6O-UD^Q~3~+dK8TdhewgFCKT> ziUBEXF58wH0H3+bchyAF);URR)vAb2u}4b#P?Qd3n<6rZrGZQfZR*d7jWH4At3~Vv z$NR;c^OaP=(+Ej5LW5NB>qqzo%8NhE%ZD{9YQQ@G}e>v*yTE93kX%bsge$rw3J` zYc9(@fmRF2$llkR+2U{xc&B@7<6ve6SAfhv(sXCX6e_i1WE1CNhR?c3(dldaI2y-U z43GNa%6xAe=lSm)SHNqah2zQEaTE>k8*9|7jR)dNkDe~H61Qk04SB?m(WpR<0tY>H za;(?c`^l)*j#p{-d}+On+cwUuDShha>(J7ros=jzT;{q6fm%14FNj6FV(IcgJaqOO zQ5lm!?*#hDn$)DU@b)+OVu%DZoVzt~QG9AwA8zsd?z%;9gTUx;#B!K)us6yh5EzIW zEu=QW9~n`C`yx01Bw>igS>~2|Yq!@hR{#P>4G%0JovrspnR+|G0C-lGR=qKF6KviC zsoQ<2#zz!9+Q*RT7Sr1!b=#Hm+@sQ1q7DB)Im9KE<<+60K1@3+XjIun-9D}>ZJ`?oCEiq?@ftWyp`T9=Z)`)`Z*(2CE0jAn=xNw4eMKXgf zBgDkTjAgz3Fmy+rmZmUpGSNG`ybmCYZT0n`${z!LltGKS8i6?yR}T=VTN~#ZaGPd% z!u~5izbc}{&N3=&Wg@bIokiJNCZse5U)Qkeyk1d{?erUrnJ9MGE@EqM4C%S^x9HoG zX#pk`^_517egry{iYCEeFQV{q78`xZzyVL zlD!Gl7crc!q&xmjjik{ZJeL@hc^o ztHrOGt6aerl9K7k-%(LI5jz)lWFuZj7CL<? zO_g0&$JNyA&Rb2_1Zxl?iEYPWQB}}{;oeiN^KCg|XRp0^=X#WXeeZi5wLh9O+=;+l zKGz{Gsftsiar5s)Y)jK!|A@~@=7yidPRSfNb*Xz^ITud1j{dxczRg4fS4L=o`Rzg# zXT}&=Kt=6?qjIDyRXJWdUo3t1_4^OzMj&g(lIod4T`IYl_wghMp$c7A{bXbccTMb6 z?|_n8EWq*U7JO`0v1o;KO|Yftp5jwx>%OglqwR}-uut3uHnCWOwK>|=>&Ez5rVQW? z8A_PF)Z-CP8FPuaHXd`Fv@1QCo(8|T(G)$B2OmB8};_aEV;}Bu@Xj2 z2tQ%PnZW(}K7O=wf|mOXZlLHX{8;&k3+|}lYWMTxmCYVQg&BH=Iqjs1Kl1TKk@KKu z;HytNm;C{;sou*M+)hn+ms6n#jU-~JLKCguWc_iqBRlu9bh;+RYv<35>)q*89%bT8s=LZ53`q9D7(#znJwsO%(y@2upZhw|Y{Ia|$b1Een$;Je*c`58E$O29XwZoK> zvXp!qae!lgSH%h*o+b5=`A-c~s*dN8h4g{gGv$lH}? zfhy=7roU9wq44o92dT3fj_fH%5%5GQ{^jx=>c04(w_T)^(qJNhLIf{i)O?W0{IPMD zvy}B2aD@R4x7lmwaN>lD!dMPP4il23?-H=&HsX8JGhs{kwLry?b2(|Q`0Bin3*h3< zva1Z}y^tn~tIpKXWBMBdXcDTe7brQQEX1E3uOQ<S2$fU183?6R4PxD|UwCsd~(Wfykkx0;f zI~#i^T@Z+?a;Jf-C4tCxb3}VAe_!8JT}Yj^JzID;oIS%4@?`Qz1a0`<_aajOUY!R>vzxTk6TX7Ge#o9W58(n6+U8ItMv^0%~4qhsFoTldE@ zjvIr-KT%W)bbVfOoi@iE+Y$Emj-F&X^zLTjSiNxDs%XvvM%`O-EZpr|H4BE80EzFjOb ziIU|o-lP}0mcdJLW#0Cj$jD3=d*f!19;}b8=2+H$sIE{wd$!gwEP#0L!crU_fPmPK zl_Q-}#`^EQYqEqOOu_=>M~pSm$$6(oB9tT?m}6p8WZJ0M^SSK64WmiVVtAQT z1_=rrz9*a5U>hYhfxt+Apz%7@puSY|r~=eZ*0fho;>U`PYO{D;Qe0eWJO^4KXw8lB z{UdS;x+zF*m`UDFVJf@}5}%5bjWza;OCyLVt@_r}L&Q9MaIC+up)s_oSI#N1fX)QCnZ*-ACZ#Yc{1l7 z(_Ed)c~3Cv5#P~v5kv^SxU+ z1yTQsw=Uf6`DBJpm=kx+g$N*@+#6+$v~^JrTREaVIjgqQ#4}3{PTz!%9?e2Rz0ziS z3rnteeF)fm{1Y}HMq~MUgpP?9-r5z@Q(>X1qNn#)p=cpGpX;!B&*Cuj4MIq6TTt6X z{SdOqo1!v0CboYFOkOM;Ff{{4T0M9LN&IyQwb#AlIfB6?f_yL8gu7Kg>-V3>#X2c9 z1$I>^`CK$2dbmdBfWSFd{TC^YgKC2g{apH6Qj%!sOqf4UEH)?;VhG2JGdaRlF57|Q z-`H&U-$`Wg!5 zShc$SNFrrkf9cS3ACFNcTy$ zweC+l$wd;>`j)g70Ox2wY^a(wZ08s!IloiubV%ejn+BDsx3j7(TTBtQmM9h(iZl;3 zZj*(^Cq(Nx2@=gPpDN7to)1ds1is+)d)sCBq8_Nxl6)eX(EgG%+{CQ0Fs)ad+PRlX z^u`Ml6D-0RUT6zV)MxF)$oDLjG2?O!jK%0!4n*?#!s#}arKAiAcM%@gs{tHZ62~2x zb6)tRMdS1v$5N6z?xU}Yr1E1+420JZ(P@|{Uze69vPAB4xNGzL@t8Gi$PXOFrYj-k zz~YN3iXb?467E-tw$yy?$ZAmfMyGY*T*w@ewAEb$e6r7oP^F65$np!zqHKA$)Mpn) zSQv1$=Wg~xdTa7aPt)0%C=dRFR;z&grrcyYTZ7QUG1zk@{&(ejOya{ES z6hD(W|K8QMkB?$%pBE^oloAG2C*wZGd0{nXEs@bbyh*zeRORz}!SuuSf#bWmH5Rok z{Agpf&FSZ|(*KIOdf=?7tyPL~nw#SZlbzYQ_%kA#s#D~d=l!=}MdLztdIjXRo=fH~ z>i)`~mlyu_zXUEbw>T8?G@r)&aB(6cdEJ?ZxG(BLFQID7U8VQPZ!dh0xSUp1{@Yae z9yoqo{om4(+Z8YU`_u@n;?in3W?o2~B^RhUfN7u8{1o9eG*bd^+Z^)Ba{jVrXJ}qCd`gLhNclxq|Snr zW*4}6F^CPMaRrL$3Wr37!~${w#!a9$M1tBX1TgrWm4arwi3l>E+H@C9_)Iq8@Q@9? zH&?Wa9oc%!&Dlg@l)R{yJt-+0siHOZKg&Drsrpy`(!Wo%Hh#A^o(Q3F87yk7WsDb+ zsed708Ik`j*tyR`T@8jz>Eq36$i)hBI)^(OJouOALI*Gg<5I52nG*eb#ks=2y!VS= z&{i>&shPbj?U#=e%O%>X~^iAA@+TK zVcb=}O#U;rf1kF!qjC>H7O({cvqWJ-_5q~kKEj56d@$+Nd>Pi%T=aX!+d|1PaLvWG zFC!Z~`QsIh79Anc`KIm#n#HkGCsz)>AkHLL-pkOoF1g_=#>{gfR*KHwvVu9pN+)A4 zs?BexupDB+sr*jWV!rfJYP@d*b)^p&;liSkC@U;bzYxo83 zHCWF{c&**0!) z7%3LdBy7lDVat#^FX3uxbGKeDk}_o4=q|gk=d?2vK)v)vG4396$oAuph2cZpX==a( zrTBNlp-&co#+(UV?eH{j-z2v^;@zoid`&^%%~dArYfrh!H8y&6v%Gq{ZVJoJ{d zCOh5@`Q7_fJWV=BDG4OCDqE>YH$~dhb&l$$Qo}4F>*-C&`;lIW;EqVkVZb%VzE(OuDn+{jHpa~P(u@f z1JZw)JQ+A~+jeXH$$@n^N1Lcri(kt%go!h7YpCL+W5)B#e&a0|6soavB)%#o;kZS8 zD8|MibmTH!lfV(}!e4;TSgSvvbN>pQu)le=k8#`R%;HQcyAIN3Nwao^4 zazj>7Uvkj*5ptwNh<+18K3x5a$?|r>qM@R)P+V@uQ8LS&>ZH>T=IZ9NCWb3kI6YZp zcQ+%ki`bw{dH#~nUA2!UY5|-*4dXI}(?X}L*CnG9#I?@Dn;%-dgPLt{{A&<~ypIM0 z0PrIyG!)Bl-yaf3+O&Pzu_)>jt35DgASX{8VlvD1bi>ztxLnli?fS|*ifDlG2SPNn zqh?e`D=}@t#@21tn#HBUBBl$12QAie9huQCRtXm#rqkmKr%Dhf)k-%B3)$d+P{SD;h5m))adoc z^1UCh1dZRg>pU5d;9u(UmHI?NPmaErI+*R#G^Tl&f}wjxmoi3F*hun=$cHJILmaUnVk^2pz6 zKGWcUYo83}kGD$Cg2{q|*Yn68xuig7wYWG89qYK_z7O#YTd9XPD=*sGDXrEhyRIEG z8=UrWyLzxNXlcg?`u>aT-ksL+*0pTolXT!t0b6z9f@^oxeR2LZ_f3v)k%gv4!^_@mfUS9H)#abV@OxTh_MD=8B6o%zdgR|;^llwO_UB@?@S71v6A|#ivpSi_N z*}gVxKR9`VX|P97s=V7lZO@_u+bj?1b$RBbv+=(3fls1}-#23VTJ5124jmAs!CRMZ zo9s?!UMNt-uPgXfR32!XW82*uSI_hV)v^KSs3J=d-aBZUVnRJ)&hpDBjcdOG^Y|m8 zE@JDe4DOgL7&Hb0YorS_H#D!9u&;E{%fZqHsHliKUsArEFga9LVsu7+$vK;y+d_`+ z>gld-I%Z$$-Kq@sstOT&!G}27V)Q0Z#!n7)!~6oT)t0sY0YJcylKIfd&norZb}`FDZ=&Dll0XGC)}bXO&Euh4p|0ul5E;P4 zJ0F_?Fj^obNtz>0%oRIZ5pJW;AFX0^f8`OY0UKORGSiTqxvzl4FF4J?GF0f!w^a}q z3NDSf(Afx4RuA+c0xdRKG3njnD=i4I?y9gHgH6V~tU!)>m7zqp><+3Y!Sk5vXzEjB z5{YXvQdz_6Hm>!bB(HLE7%t^zy#80uTDrss`$2aRRxl`aAlP1`P^ocg&US|Grl(&3nC5F4+gXZSRf;_I$RY#j)X$WiBADw=lD`H@ z^WNXtg&VK9slQb6i|W_zlJWP8+|SM)SVg0E-2dW%h7U(>N6}X|J+xI?P{$fI-=veM7LrGSazXL=T zbSngd*hyB}318AvAs=!mQ>m^vpZ2fGaV(7=jqh({0PBQW>3=qRmesxm-YPM(ed`4yShxm8Wpb6mtU zw54bD#$T|>tl;}bPeex$jT%-FbwXRcnlB+jwhRsoF zRtFm69djJ%*3>)24Lvb>S0hfg)5?y#;L1O~d$qxXjAv`!`^{Xo4M3(Dx*rc7SIU%%n4#f=5K^Z#iKV6-gwv0=?HVlsE=?G6>)YnG z@Pbnm!gpqOcdk$eITESxFhZIuLfKt%C)-)8mJkqKeiyc8fR66mxi0RrFX_g-6oAh@ zMrG!UE#DgDHP6EOe z>OT+Tp@|7zfsy|=?b^bCX!yF*2!ruzeXl*5RWdzytIpYT|0@ce?iGy!9G#yGx}EPK zr_~w3a9_j=R7InM+dd71cF};r1r7V?D(ru*y6U66-VjW{+=XEWsS|MEuaDS%)f7(Le)+sxECZms1!{MM4U{+Q z;6>Da%I?GNO&jD-ds^O4Bm|maDNFw*A@e`*ZFp9_WwA~FvWk)HmXum!KrzVn&u1n8 z)DZ6dcaQ%ZQ(+`#|Jx++k0ky3pU|{mx?<5nv4u5`L}h4L{hv($0<{qQNK#0xX~w3O zMx~xH`_oE8MHQM7OgAh8%^Sw)C50#*MI>D~{@(@$G;(Sop_QE~2aNdwa{9)Itx%0N z+?_G~p+dm~i4VHEy-(;uza(U?Jm$5sNrjSJ{SwHHiGGrB9eJ^i$x?EVz*>uKvZ1RO zD_nKxc=dXcB*eW{)TP|;;g0L{Z6ITF>p|QY5|L<`VO{>-K@-||Mmo69Bfg3x(zFu- z$c&47S6uncwzi14{{?Us}hcG{roY?51@1O=!4F7${t4Shwo0l zk-o))__`aTg>9jZL%Kp^fhbTkhwyW{!5^DlnUY9Sc{*^j9`15) zYbzOf`Co&I@6S0-4Y^}uFE17)W){uP17UCZmm6)BPx3i*I&&jrg?6-;9qtdrI4JyI z8{2EjI;H@GUDl#?(!3ETfk%^B_-60<{J0m&iU$;9=;{Q+EaglOhP3%heco(Kv*Z_R zsyy;`pop6Tf3dOZ<=t!}z#ta%$LzY{c`AWa>RI!y55wTas)RIt5jkV;9QdTG@w;g>>G&pm-UVIF!n#z4(ud~2} zdrZ#?)$v%C3oxqN!nSN#br5XEgwwdN+%GRAW;C^lgL)>LJ+<_cGu^1t&UWGlRj$nE6X{j;F|wD{k;$c5_6iFLpt1ol%T1hfiwp7sc?C;deb@1q`cn> ztP0}(n6**W!kmL8ncm_h|Jg^Xnk5>>HX+P#zgcGc<;0%Wk;_~CqHV2kG6hwukijh zDNOf(T$VAR;GZ>NeKN7rAXK?GKRrJ7h9Ph4R}7vZ!fZPCc|Of%8FOKe{ktrDcMs-j zUWzW2ngz8F0SP-nuNFVbQG4s+;<~z)5&07vf1a&Ihs!Kr0y(U{E~GQzu<2u2_4DQM z_cEfZ4;%U#WCIGgi=W($j|`b{RE2ruXHpQ=mBRf)3f71rZ){VPDTu{PS}A#X2_7CE z<`)$uWM?b?=R;$W`IGU`D?X5I&A(?Pjopo^bd^r*b4J_J7=v{`xgCL``bXhkzb^9Y zZKcYP#J#Dq1ZlCc%?3ZFPtFS_R2{rpu6PJg8A%X09_Tiq?Z?jXB-#$G`(g7)qOSFQ zZvLk1uF-hP)7JuV>w%fkd%3}P#!nPS zA%IoETcdZr!8RGcsbbqRkP-Ng_P8GB8dkl3%?UfH!{gbLs`XoI9=&!luzRiN5nx`? z5dokk-|cZYKLy1XNw-g2;%9IEEUh#G4aqdqt%@5g&~<=T;M!_}Ru#0Fd(Idb(S^qYSX!wA8@DtWd6LE)-9G@-0b zLVIf6_q%WFGBLE__Jc>ng8h zpG#CUt!Gb@rMNZ`Tm^yb&VB-jW6aOW6Ot;yq=Wwcxx<9U#Zz1h=L3pHWmefNKq2_Uw ze<%+}tW@rMGSUMZ|8N0z{@7AfV*LY#CZ&u<+sjmc_ALn&`hN-!s0x(21cI4wQa3TJ z-|V6aDS_VnM~f@$9Y9~INsV=u7r;osyC$2?=o^m&^A{z; zaaf9`@xBtqm_F-+&Dl&ZNH_pP5D`<(@!lcRxR8DfH{nlYbs0lm~bIXV6 z`wo!=Xn6H$yKFhccnQY}xnxn>uqY!OxDhh%O!nQy7`HHPEaK|)hjU%`R~p-#cXQ_Y z)#bmHBy*-<5Fg|p&4hQaoCWyfX3bE$mkUWB7a4NbUP_i_g)q^hi+RuTiNWZfC9r1< zVp^$VYc|0i=f*myftPwmE>+12y^rOMHoOBy-XusDV)jPVl7DxvCCN^MSth zrsqc;@6!0*&w&rxZ~JQeKP2fZ29loGQ@U&?LSj8W4Wh%ZYoL+Pg(Mc=MBKxZB;xnRu|!UGaTw<)1$S+Uj87X3=^ z-c;=wsnKZ4LaA2I{YnGdk{m$AXU{@=>V+2ig(vP7lhx^J{^M4KxxX5;4r}IO+V$>J zZp(KP6&LM@)+{NrmFPq}h9dF0%Jdz!?A+Y3{14HcAr#&OAXz=0>M0ddbMnycj00QA0O?Hd2pRrV%Q?~rlg}(oPV9c2U;Y^g zXR@f-ql|IKomg^Y=}_|b17k_4A`uue?wDWyg-43}Qu3CDb|f~(w;%LI_HlCNQz8OV z2v1Sd%+jY!H#kCav3Htru{nAD6R|(De)GTtiYSWhl0D}RpLWr-2skpncV2@se|EU} zUED}WME3+5uZC#b!+0>`^s};3*UcROLxTiQ6U3_v)B)|_9wDc(AsJ6V5}(I!@>s6> zTpJ@LKiqL`8u51Gsu^KXBIu<7(M}aT!+liK8zgf>3rUeM+#kd-amh6W>sWneqkrFl zy0WK9qxhStfOy2xWE1g@RdM0pSAd?FckOH|M>`Jz&&wd+D_+`W)7ge&xmVsh<}Oqf zCU{^|%5QNKk0?HyZpL2L>~Hwu`0wD<5mjF)MHR-eCJuZTjH4fEFI9rVN zg=ouL;?=8hRlb~EssC$un2iTKyh+jqCUtxJHSjvAr+1DfNIyTje- z&ypd^q(|e>C(e4n(3ev~fW@fO6b8o=L)LT-`VrXrLmaE_{q@)NK{IDS{8YbRxGw0I z4}^Y6Jo5^VF-Ki?!~dL?kke6N8LgQL>-;?d{P zILazv49Q$uUxu)y4PKS zS(bLkXZNrmmPTeFXD0b7I-p@*M-+$`0>;0Ly*t}$IaD1|08`(&*~hNcejB7~pNKFZ zjVz2cIPkWwp6(IVDo^WPHlSbKUsIA?$X+D%i48}c`GwL;7!HW)a}eYJaj3u9GDdPu z+JrmWYWaqz7tuH*W%CQKLBlD;8>(Y&(lTS1rS^!ZjVvpc}i>h@YAxGmZd_7?Ii{|7{)I%0x6gKl^7F=X9__aV6)HzR96F?@Br# ztYK!zXiZVd5uVaAoclb)wLlkSwi-;Q?w4s<_vMvPQz^JPKwT(=3+rD)G^&3FBT5<3 zXBQt1gA@NZ$k2f2pqrib;1>k{#ghD6oenS`R5s1p*eQZ1kwXEk5Tm@vBwh!UJUl9i zUyFzHOZc|{hTAau;VZ`?W3;ZnYQ1t9D|PuEuEaZQ%ITgI@nJiR@PpW(kAwi<7*S|b}c&WoxEEc)p`!$%dz3DD<0`kxvURL{p z_ZEN(I=?Lcg09~c%CbOBkk6Jc{RabVhtwmtuodqhnLuLs22`QjB?0CPWgZgv|36+<2f#N53Kb=B|cIq zRMkS(P?gLp`9{`Mc_^M2b;-jo>KmD^<%YZ{h_&3)bvcJe@pk%_6nM0fz<&Jk2$m#K zP+P_aU*ugLNLPRB0lHqmjJysn*1h~>Df+_Kw1WvZz01h>Kv|pYpqSX%)#zEbvj|^Z z%wS91!%zINCtnqNK%%`z@Ydf9G@RvYSo57fAw3FsLUj6vdpBcyEfO<@zSgiU{4w1r z(Z2~kRrz&)%pAO>63HUR4U?x4i6H+3MaGerr2<~y|7AMKD_iH>TXjdTJUurC`FJq@ zL?QJ=HcwJ9T`dmA;W-{Am(iKD*kHBGidV3``nu}BZ&?Qd=0J8Ml|ZdIlOhZ2{Wr9C z=Qb6@m|)v5W^hP>>Av&C%fX9_NarQOl{l^nGI@M&25Ty25;<{i=dItni5gwRWGe60 z+#*oWV5CzwfldWjtfFeYC7e;nO~Ym7knL8RT?d^l$Hv+8Gi!7kxC6JDJfy+$$EI~Jb#Z8?AjoQP~jzM!P)e2M4GMIPlH z3?iP`k3&iUFltWX+xz##k5Ouf(8d;($%B+A7sTDPg4o7Y!Ob3jH;6GYQ{G^S8)C$$`*pMCaXDj`a71mO&CR3Yr8rehBl^ZWY zc75$emSEKVJ}N4S27k2?>B_4G$4Ym9lLbB!<;w5X<{t5L zdYKt#H7CCCPL+mTX?4w&0EB*OT~hgSy&4S^zWAhNpV3$G;#t0Q5%Ve#CN6SN{m$8!j#D%lRhBld1f^+hc!##3x(r^>0OdpE*#G&_>i zySRZDt;j32$NPtbpBvV*ys~pMH3+`vOUWw?hINNUyH=enWuFY6J<<8&hf-`{99Pz`kT9O~jV$BRb4=W2oFf&B+ zFe_9Q-3)8KQlVj-0k9PzTDc(X1L`S?JftqNlR6SqFra+K31NEOi#ZSrO^!UG%|mZC znF7szls?`XyljN+e;l(2vgbY1+M37zFz*W=hgK|iDrfCYx!(2~EitY&Z4E&BN~Ok` z0ahK~%;fK$aDxF6Jr0ZfIN?I;rmAu@rvN^Tr5{Z5L3rGC#1j3fp>h^E5r%lvW*1Zq ze4XFURYMF^ti>71`3k7*f4IAlJ(@-$oo^ULsK=3`7z~eh?+kHN8wzf*>wNh4XnP0z zC`(Cu|MfdkhE2Iu&{)-fw>aa}XybU&h2mC^7I(}iFQDuETn5Q&XpD325rZ=6Y}Q^< zYZZ+^*iiOpS;SWzmu-fIj_Sm%rtDQOFQ$?Gj!`Y-CNux;lJ0%S6R?0VA74t>#lDj^ zlmzkEhDZMX;9^U~PO6juF^NZ1awo-vUU*fx3($oWM5P0z+`RG-206sJ{MwBg&KeCB zvI;+RCF8qktlkQrWaQ*8naV6wkV;#yUSL=c$|eV)trb4a6I4QTBBz=#f z^!hLgu`%}2gGVseCwI}TmKbA>2Wf0g{dbpzpMS1?Qp`K(xwA}FduLdwT7@D+D#T-g zSKcjX`{vXtA+Q>u#`5kKF45UUZ6%M9=z<+lel%xjU1edan8p`HM>qt|l=+Fv)Klm` z^N1N|oDi3kWIEk9H`^o-Ph|AqxPQZ6pH;?6uUoW>wf#-l|5_G;wDqF^1jo`T;M@E8KUWm=F>V;TNML2`TGo74D7XI|%A(ZEj&eN&Bk+X ztuR??C~M)*CX))aUH;MHsK=m%yJWGABCDM1Jd9g0ezoB85-nA)Jbx#Sx)1slh*hez zpyy}h{NA+RRTtQjG{*H#v$KPDJL|)-myjWDzlfHgACL_$_nAo}ho;Nrb@^Fcm4sv? zz(ZnP>$jj^d0{VJ3+jz4#Ab~;(mjvJ30?#0OxH*4E$iv<uhv(;pn$6luA154H zdik|7>rKm^oRAfqOQAM~EmqOkZM^o$t#8ACh>cd5rv_9HD6J%d)7uSF;!JvyqFe7ZtcJmJvmYj{6Kx)bwA68V=A73Sm-w$}#x;rlv zf0Zmx4JUs7VF8l)>+9=K%dIv&aw;dA*9dSVq=q!;q~kw-*fKvFVMg+$7};)ws%j%F zC96i@pVtWlE8I(}^1I{J@~UI}a;5maHL{fYSt2ZtHnWY1-qFYl&2%LKY0;~8Kl{O= z(HT7haYG5D$u|WIBJ0B~FDz^!b6?evKWoXDP)2lJo9q=hpwde8l{MA;@;e|VX7%CM zoQsC;yV@1jUAD%Y-XsaG^U6g@x4}o@^C{d_5j*z4j8@J1CXB{ze||Y4(I{^_;Xp^e z=-m+H`>9c8qYrMhq7(-QL%Ox6yQ^)cJ}oOUda)cnkZUBMrulv*BHMnn4tI&V zS?!wfw1vtfGT3>P5_EHjvX{p)dN zhAfc_og+(p)xPcbb>jRFegmj9>rSk4rF-x9_nET$R2f?iVB%%;#N~?`W)Zh#BP#n^ zAqs6@%17kxO7D$**kg76*&LEP4jTM>8r9k$`5`j#CQ>L#!{WQkt#_M{JE#^nCNu+wuzW^EjQl$NLDH0`dm>7tCqHy^ejDO=A(dff?{ zy|$><#`>fSBbmcKAGBL?78gXc^=C*YOfUPfmUEs(nqn*Z({?9Xjvj(Vc&*jx@64!o z2>56DF<4wo@BOnubGZeI-R2p7-a@K7q-N>W+)acelyrTY`p4U$%Dxj5S;slCXUST? z%+A=z9k!Y)6!krYy8B`WZz;Y%HlRBLkr))6z@g_|2r|i1YEg@Ofg*v-#tpNH{*-e@ zWc>SxyTZx6>x$~Vr<0+0>@5nPMG0-z8Y(XF-2-EoAQ+x_Y%dn!9{+g8^c_R7Z@a1W zdKwmjAx$tD!x|6YseE7IAIDO*8Fitf)RpmmMoNeEszV8OVP1+%Pu+vPwh`~A#!YYb z8&~f&N$!B19X|Jba=P7NHgo%|R2vGWD=-9_-j5xRVd@@R^;Onm%qCL}Qx7Z~5(kqJ z-lTKN6So`P<2Oi-i*2@4Xben!KPj^JsoxArY(DXuczs$Nj;nRWZ^eI!aKq#HAbTce zb-;CJ`y*fQ_{$-Q#O;Bia+?cW{&ft;^ChpEXBob}&2sZo1SF9I3K;9o)*@ zQH?h{WS0Rel7P#vx<_PB=|q~VX=&94;~fQ-nzl_c|- z?ph3pJCM^J6Z85BDjYb2B`MjA%m6D3L=pj>Q;Z%DA0XA`V%%<_h9;of!Ulp815sQ~ z4=Ss_r`T`n_{WLu|M-2=IO^%$g>Fl#$7=ss%?cC$z_>eJAWC{b@r--R@yEEDd?ikk`i8NU}YmH^1ALj#zo$6?0~ozC5w#sUp@ckmdBL%DuS1-&0P{;>knH z{=8EIS3x(XI|{<~_yWD&au?0h2!~%g6TAfVux7H$lm@<`@M90+BK(Cf^)DB=AU3rQ z*6h{SRC|Rpq9NuDz0u3A)9 zuv-`-EbO2zN1!xAi4df#!6`2Qjs-+~v8@48pJq16wcmAx@V#ClSTX8j%1-whl$BRd zQLq7M&4dn?zwhd-W&*#tCmJ>>cTUI`7S*AgBHk9b+|Wi=Sed_Liw&BWj;`WExU>Pd zD5*v-(BJNp6fO%w(@aCX;ET1n}3W1m*YUo5P)-jFsmxr45D^!AdkNb5$89LX*mUU*M- zojd4FukHr8-Hj|*C%+j}RE7gFHf4{7(#2K`w65rK_kPypQYnr8Kn(iUAbw{hJxL~@ zBmxdZE*>YK4LP>ACiXORqBe3PAmYl+74{|&;FH{zlQ{^^WZG?8FaTYEDp!?ddA&-o5ij@T`B9hrk&Y%Qf$rN5$^B-y*{3G(jO z)siQU33MN$zj8DeZF2T(KrJ+166N~VT2@_MT+kOp^Br2puv~-FPQc6Z-N}SC zA$ujk_WBL>szrcfUhQ+O<$FGxD~_n<%SPdNeHLjJpc@bHbUv}>Y%IOK3fav^V9yq< zmyE&@=0T;6)m2=vul|75DwD8%EM#o2&tgxAV6oN!Hz3xBhnEx4%os`G$ce~$$~03Z z$&}Rz{@EBuc4bXwU`;V;i7KZ5r}rJlYs-NC!v@KAzZsLh+#^L!mU={Le~k%!V^#a~ zhk;)Vrl{6sgA3HyPCFlK=1V8py{*Jce6A4 zJwEsi_Tf|BnG)c)%rK+|)X#T5Y{{qP=t9)!>pASq;{~>(l=~MbwR$d@b1gT*g}IkZy9NQaYm86y!^7>#`VPB`&ihi8tD{W$oGWjz?(@W`ROvt|UF zow;8!2Dcpt;}a77e@22s!bFd~s_XgB#62~UW19qspJv^jpQAU<|8Ss0&5begAJkJ= zLWOV1`r<16{--7S?Ux;P3j0=T4R20&OUtsIFxc#bB5E2e$0dKyRlV`e9mt?VZf^z} zUUH45 z3lgt#BUi47x-{gZu;5ieK zzvRV#5pAA@i~{w7mPFMbLDSMnfBg!TB0Aa@Ujwlz3AbRR6z?~>?8TAHR(t)D#UH*h zv&Ne7M&GcdMA@!TyHW?Y`Xaz`zO_)evdqs)?Zl|m;`avoN!m9GkX4e|(gpvj6vDx6 z?4%jdFmMI3bj6V>suBzO;*(2Z5{Drd*jW-WY2nkagMtf^hFKa65bT&1CH&vNH290yi>r$ZFyamd*GV~-Xc)j32*Fy)MrPUVcE)m4hK$6q|V0FzW2n;5y-?}SzXj&Iu!=0$8p0K{{$!Op<1>4 zo-nu7V*$7X1QCG)`IvIis{i|>?BIPS<&Nhg5sYf0)*JIX!N}239#k~>T4=FQEd>4b zJGvFhHl6n1d>pq5N%BYp^wTsiC#qLXM&0T6alHg7&dnIBsqoKU@fd{iX^j3GI+Evs ztqioK(3So%m*-}VI&RV*}a!NsHWPmyWSugxWntQ&|#BthAFEmAGSnNjt18DQbttHJ%voq@b z&b6KoUCQkhp}CWv+`BQNZPj{b(=X~f7ew7#azAVzv0AgN9jo0ewexM*9v~knZVf0d;%o~+xi9z(tx{L;X8J+n5U(>t^Kg)Zyo z+F-25+(W~BT$K&8SqQt&muU)y~{+IH|VFRdyz{3+?WylsJFw`CPT)~g?{AAeyV zzf?wLu#(E|riFk0i+>(&k=8^;mMT-bcGcQ4W=TPH zt>CmwV6^h1OGf6qqr7| zZ?p_$L;~PkM-}G5fLscEZK2Tl2cc))RqQYL#Nm;3!mxVm2s8^On?D@iQ^@CvV0(cx zfP}68k*1?)nFSOG38_>(nK9EWixsJXzX7bs!7+T7E2FfLU0hECGRG zQU0~jaxj*d@6Y}pGY}bx-cf#SxDZYKp>sIfh@{iznlJl{$=MD+Zti0E;{L|x|4#@p zs{X&!Wn&IXY6qUdj)ZJHm$}vku16fHD_s5?pw}**cXb|n;{2|$C=;Pl+;bGZH@`mm zOK994B@N72)AiEsVCADTssZ#9%L7PoG3e(vlPS~vCzV*3vEo*_SmJ@r&%=(b@1?)5 zgfVI;kim};5E=Y0kuI?;|5vK&Kk5KtnEpxZ zs~PzE(r^wJ4-b!UBAfqn?O^*+fI+=J;13i7MjvlO7l&h2)hILvby8`>Y>ytT;ayJ{ zx&%K%Sx`gb63gP8?oX^r_ke6Mathx2tmhUOL%sowN$#6n_rO}RH!vWL#hzVBO55!L zPUSbu_D_+&JvfZF@TR9X3k*dsqw5a`kdi*96~+H9k!oeVml%@Q2>Z8Bz^Rd(nUEcw zkV;?~ctn90hm$|WPCRZ->(fm#P7mB}_j0%;YkmiY{rh#&uxFrgoJ~Hq$X_7aSB5uQ z=o!N_9UL8{ckX4wV^ay>Esi)f+DS9ikAa7)&L!JgWLr)cSNlYN!aIwJq{iweLZL+< z`atpIFf25T+482VyNs2WAc7Kd)4e&j?fnP0@zvdO?s_DDt=`0E0&0RYPd=7`V!Kwa z&IPgzuN!@nXxL-zZZrAQ9sCV!Hj^lf%Xz`Mcuyhqxo0Us znHvS1XkQ(4&d)Wa*OPU&x7$eAt0(EwBk`UzC-98n4dk?Njxq!MRmW|Hb|_gNOiR(x z`0niMWZx8b`~^1x51->xi-EH}9>;Y%J)JgNW_l)KsT0W*FSo1ly%2RRwSJwR?lZgl ze&qt5V3!(b1gWEbNugw{dTV}lguk0M_a$&rPJxg+Wxloga&rG80p>D`@vX2zcpSi+ z<5YWK7wwm_rTxI;*Sq~w$Tjm6bcx{RlmeYG&4)+8^$T@Qa1y?o=7*Du&5pK5 zl)9QwDmiKqt2cC=2(LJTKWJ^8+gp&}@^iflxt+ibQIeCu zycF6&M0zu((*@OPQ&Hf{b=zw!EVFU#Zl6Pk(qiDv28i!PwzYP0~8AYBqr5<@8Y(10Mvj9`cCj=(CDhzdN ze%!gB05q@qE}`8R)u~B+j@J8DRa;Xi6L){NHurz;7?AxxS!BXS79QJ=_S}+Z)tf2$ zx6zKgh;Y!yMR54XK8Oasiz_Q@jKshdxZD2Mj(b|RcVzMkUMe23QGI8KTBiYeP~z(xv!1U@-Rgjw^v* z`h4X5sH(lv3=RoG4OBIG$CLpqw5y_MUo(+=^a0FOgOG9|M5G9ybF+ZLJ&i7y>H;9% zGBkmyi51d=p=L)2KGqVQUPiOKg3pGOuWcVbxJ~TuNtM*hEJp^Qt@nha%M3{Hz|UhR zJTIN_{|1M#TkKLe>?W@|N-{4G;mx0GPmEt-J(!0P)+E`_tgX(y@gy37Y6Ft1dAgdG2^P*1m=c2MzH$qz{h24O1?_$eDAe(JPWp^dMk)^w(hN zbOrh;YKxa`k$E0^Xmh)whwL2GRV|HZ3l+a#S2SZa_zdZyTxN{I8x=LAk#>3h713ea z`P86yjW)ps1-^V~B#M5HUV&>r?JrzKn^s5*TB>%<=2MU>Q&VWmIAe?;9A zHBYN3>8TVxFLpkl5LliwWmR2WNC00_ zTs|Gyr2AyPr;k}!waG^pawa#r%qb6FW=l6$hz8;Wa-Are*j}>Btk+Kl6XRt(#RNpm zs0)W;_gk`aSzLzHKKaygkn%(#F%bp5CDU2o-Xss`_VczMGEyIS^2F2RbK~B{ynj1O zb+0Odl=bFEXcQp}+&7v!a9+VN?YI$ab#c``132{_9k4zHai=HfP2JZ%ty*Vt<&3oY zcKsbQ+fC<6QKxWFPCvO_WSSuEr4DvT(q8jWV4WV_zuT?hvp3%TX35lk>Nx4;PLS-a<#FKv+MA7a-|)%M`q3Rwv9b2a zc!g_V1zGgYJk|e#X^WMNhZsBiso&i8D`M5Pi&pOqR?k*v%A@Z|I%2F|Z%HHsnD!P77}0qb z(s-A4=Z6y0^!HZ0-&HS5csTP<$ip!{nPN1%kbLIC-h{P2H&mO@?pfaNJWR6OYnM9} zW<(M6Wt$5p8&~ezUt`Uh=1!L^PUxLxGB};28{V>qLZyJnt&Rl{JeF2g?g5>q3+!+l zv<_HJK11sE>@%7E9EYv6S&tGdQ;U7aPLr9ntbvJD3Bm!ZOf`8;5ZdQfrbjH%KS@*B z960U|MQ>;5Dszn5`7zy_>|Ty=5h5U{b&ci4Qe7}m|32SvQm9LQ!|A=OrP=a5QGV^9 z%XS)S*h$^31R5=c<<>GD!91BQKhTMylKM8MlJ3YHPF&)kFl6!PPI!TNohr^}CH!sS zoZxk2yP2N8k(;HCU$TWt5+q*7as+L+jPrs!NNtsvF z&neEoVcf!V^Tcl;7`Qul`G9LvQ`u*~qP*1?j#euHe|cL!w~gHG`nrg2JdO3A!p-i-cD=sO7hS!2fW{(apHFs7 z9=EWs0w##0@}4nfwug%BSm2}{P(;*@-yYvDv)uLa;Wymk+dff5SiN$@3K{^Uf?R&P z+xoZ?GunEEue4KRp7O?Cal6pGMM$~3it#=#Jxn<1$3+c{x@oc`svt0LjIMWHiA#tZ zMaA@~X)5}Y;@Ug!XLVhjx}U{)H<&QTj8=fqhws52zb_9jkgu6hkna`9uE$c{ZD-WH zdz$*bf_!Ntnx5h?c|Y(2{6}`4y?w%?GiS^l z|K;Sl#dj>dV1J(P_uJcio-;tT`fSZ=IkW6Bk%q!p;<4*+f}fd_dU9qW%{dM9TD>P! zI;~7xm_Qo4r4M(y_8)&yTbs?zsxmC=hNr$Cqs&P`0C*jo?+dHhu|8sB+ToZ{vA`>l7zU(!3*}QF%>zYMX&7s zn6;iGXY}=&?DSlmOQX>_EOXtY;jE8f6^FWqC)9-1b=qgMz}{xcVyaDMJ+ZRhU&wcL zt)-#tvzP%C1R<`B+bCm8+PrOiUh8W^zN{fuY4ugaW_li+6Wo;s6SJzj3+dlVXr?=g zgLz%3@w{!klrdav*nup+RDiv(#LC7w4(!cyK&ip)`}7Bs|4K}At+idUU)X(vSK|P* z@0w72i6ypfJkO)h5A6LVs?2DSy4us{WxG3(!IGilh^v^rls)M8Lf>rb)St%p`0Vn_ z{weV}?G)8OM<^Zl!YfHfm8)Q~JEU9B4aG=(eYgm*3&)%@QfN&8`CvfE@eQOCOvK1@ z(d)%iXv(JeX3NyhKD8a|WxE}_N^}mYgn2aaPyslcD3N}qValK1)Dmq1TbLXG6M`8% zC41z)3SeQ*)_2D?bO{Bucw=`YdS?aM37R?UnWbKg+R^y${nv8qah{tI6DPkqzQ+Gn z;&9pHp2D35TCJ=YzG=rDx*F)5x{lSHET^NqF=!P(X6B1!R7 zk(ZO2!3O$e%tm&)bdabqLKG4EcLaCu+IY2#6Qt|$f-;gr9v&P3oGk*>3mPKqt*1&NSi43C6V`5TNLY_ zf|=2-Iy|r6Zd$qyFxNfqWj~?#a)QM;z{@!o0MZ4!eI#2j2v(KckhcYp0YDNgFBTX& zEJ@kiTM0a4-ucdZU=$Te;e9g9|McvaU;|lD7;aHID6k`Ds^iINT)W`24$HkMTJD2qq*%*LK{@~2MzWa1H| z?+pVb_Q~R0sap7M)8QXo^oVPh1cYXdbLOEYsRU+V& z8`uFwqa(S+sdu&wn~84`Y)7i93SO4$dyi82+vLmHqP&>Dm}zxIF#wmY7OY4>V+Cyv z#`fFVE17cck=RqwK*542O*vtIQqN4x+AH~^!SiDBG7aUmRYnKZ{!;y{sXp9xV7F7t z>Eay~0JO{bnK}HQpnSKTD1`puen4WkiL}?IBm`@pleN@XJ!C}YY>wQG`x!R7%$Ras zS@X-3TRL{8rZ($0S=5$F~BNv6CuE$T8`Ahr@KoivTub zbGjj0#0gL(xtYckCNNS2)XdOqYIg_geVR@e$#e!^%(W)`E^KIcJ*J)ZF#S^j!rp(U zf)yM4o0Qo!Ltoy!(JZYo4?O#0N?Ii1Xd$~fj)BrKE3cA=GVGlKK4s<#9p^)&3{m!M zLD{PIWB`~EI1T|kvxL%e1mUky3hntSkechwr&akAe};_nVxLA#=D7rmlnonqb6Hr3 z&sS1!K+yk}(K3vt@&{tI0nM!KG*DAhiW9Z(6cm=-qWsHgYN^u#pD!@!d@2#@pN$J)b3J{{#egI&NqZJGKVFHS$_=Do&v(`c z<0cuJL_55B7Ox|wte45HjGT#x2pJQld(*`;5N!}aS5{}vvhRVtO|BXxwdw5RHFh6O z(%-%SviQWy10`eSJb0OQ&~v}Ir(X)j@K?#R)6(#^zc!H1nUGODi|>saeAPvU4s(4E zAZ<^rD(HGq8gjJ^#ex_Ap2%rQHhiHue7#M!f&ED+2Wt-bL*$2tGH(UA&0#poi?5Sy zADQ>)e<@i)6z6)D1mR&B&V7yFWidCVq(rw9ZS2L^H@dG=oo^-`T~wH`hYBeDQYVSB z`yg zb+Eu8IJ4kRQ+BBE*uGVcCgM#@crP`()fGo82=L>!Z@|5043#CH?Cdv*{ECLnm#bvcMP+Ef}$Y0f-?W0&HOa zT|^>%0v{v^mVGm%@Pci$C(3KivsjCuWl*7$crwt42EmtO<5bh_wD-~DT=_O755NRT zf|1{~mVQ}vo5<8vgb^l9u>#OThR@h>s zO-htRvbS7ogwK1f?#6^Lk-mD$e-C8YL4e@l6^e`<1|rNHeT7h_d-97{&K zj>8LD&aQaeEJGN#V&QG^M0|aOnbP*b#$Ef3I|No#ollsYC&gVZPeM@40;OgSWJmCS z#m%wRrDt`Aa|;GzKug;1)%>Mf{&MzpWF@z{V184mW1bKnx#Pwa0Hx+e<#AHNO7#m` z0W1aJ-?gvc4G4DqPHJ^SdzkfdxFYU+SWZ!Fv8xYasZIs-=rdR7`X#HLVyWK0Ee2sh z(4UB2>}(wHp0Jyl@<2mF!2y&-Vhc)>w9NHWG)*&1);WH=ey+B%)wJA8Oc|3OTb;9N zmau#0KsDQk(jPLdB)&C(TG#_$pUVrbpARVTg5Rkq5MUjc;K?XCQY)L!zH=y!~T|MW)jLULtAAUg%%5JWnsJGpB z(oX32XF&wyhiw?i$!7sSHvujJwgbAH5uM?P+~X;Rz%RMpNQ%BAH902x4sWbr7@-;G z=!l?v{~f9I-6fTlM(wr-Nya1KgrV(SkZSbPY>4)#WL3v?#l~fvacobo-rj7Ghg9rs zITb(ep60?=rN%=GU!h$jqPO2SX?Vf6$5i9qrh5#?5%Iv&0@SPh4g} zj*0i+bmadQ%RXT0n`vnX?kKN+V%V#t^E22E?&m!Zocb*G9}T>8E3ygM9V)o)Cw1^Y z(a%F>H@ciUt~bbgty8A21|4&QIw$_i2=){R(Vp$js~(*(1>LM* zls_n?g8Vf&pc1=>6af={8YT5-cU#Wb`)0=r6ZM+gI;*sdwBDqX*e$EnH$K_70|cB# z6NHNSi4f-u#<3)Y`ZW%;H-0xAmRN4P z&YaxN^#MsR@ZDW;%N@*4)$SeH=*|%0!l^wzIYH^vmXbl$_c6fHwA66NwFtr>vYul|76!&jxBhYH8Zn?DE;sv#3Qs zs;^r@{>L4uQ&UHWm~@CR_k~>ctq?fX?SRD|2`JTnNWQn9(yex!^Lq`%jS7wVI-K24 z`Xh#Y=XC7Rr(Q~GEw%M6)=1Og3U+l(DGxmhn4C08;l0MY`appEw(Rz>ezmjMNgbR$ zmSCwlo@@6g*sVjf>#yZI!C7H@u;I%ZC1(#qv+7H@Vfn_Gsw0pr;j;61U$3~wZX~5d zIKIQx)w@gh!)$gGs?N&X++5!a2#2<_9Tsacga7O1o7rN{b#MQ}xt-8dAN!A;t4f1H z@59gD_uNwTm(eHg{8o#!q)+cQUM6N3K+Pxat9Ya2r2NrQq#skTOZ298hAu@OHx0BO zr)xW0hko<#;k(MCLc=XrYNZzNPoni_o(*HkPt8!ReTD_3lWZGy;aM zC`04*x{&{2V`^GyQ_PBYSB~Ui9|Jj3vJ}`j*Rn|}=egP3vA9h>n`%;z|BuDbv%anE zqqt{#Xegj5%=?ms$@fqLC)+_l(IfP1EPp@x5N7q8zmo%*nhIDFAUT%j%Z)Ya88

    !kA8)6{{v{$IZn7AS$N9}N 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�!q;%U@RPY= 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 literal 0 HcmV?d00001 diff --git a/board/k210-emulator/img/terminal.png b/board/k210-emulator/img/terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..d6752928fdab490df8c13f8c28322dc61ff2cb60 GIT binary patch literal 42816 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 O2s~Z=T-G@yGywn{=?|3v literal 0 HcmV?d00001 diff --git a/board/k210-emulator/img/vscode.jpg b/board/k210-emulator/img/vscode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9bacff78e4b635984f01459c6c41720bcd7f3c6 GIT binary patch literal 57472 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, -1); + /* Use memory barrier to keep coherency */ + mb(); + return res; +} + +static inline void spinlock_lock(spinlock_t *lock) +{ + while (spinlock_trylock(lock)); +} + +static inline void spinlock_unlock(spinlock_t *lock) +{ + /* Use memory barrier to keep coherency */ + mb(); + atomic_set(&lock->lock, 0); + asm volatile ("nop"); +} + +static inline void semaphore_signal(semaphore_t *semaphore, int i) +{ + spinlock_lock(&(semaphore->lock)); + semaphore->count += i; + spinlock_unlock(&(semaphore->lock)); +} + +static inline void semaphore_wait(semaphore_t *semaphore, int i) +{ + atomic_add(&(semaphore->waiting), 1); + while (1) + { + spinlock_lock(&(semaphore->lock)); + if (semaphore->count >= i) + { + semaphore->count -= i; + atomic_add(&(semaphore->waiting), -1); + spinlock_unlock(&(semaphore->lock)); + break; + } + spinlock_unlock(&(semaphore->lock)); + } +} + +static inline int semaphore_count(semaphore_t *semaphore) +{ + int res = 0; + + spinlock_lock(&(semaphore->lock)); + res = semaphore->count; + spinlock_unlock(&(semaphore->lock)); + return res; +} + +static inline int semaphore_waiting(semaphore_t *semaphore) +{ + return atomic_read(&(semaphore->waiting)); +} + +static inline int corelock_trylock(corelock_t *lock) +{ + int res = 0; + unsigned long core; + + asm volatile("csrr %0, mhartid;" + : "=r"(core)); + if(spinlock_trylock(&lock->lock)) + { + return -1; + } + + if (lock->count == 0) + { + /* First time get lock */ + lock->count++; + lock->core = core; + res = 0; + } + else if (lock->core == core) + { + /* Same core get lock */ + lock->count++; + res = 0; + } + else + { + /* Different core get lock */ + res = -1; + } + spinlock_unlock(&lock->lock); + + return res; +} + +static inline void corelock_lock(corelock_t *lock) +{ + unsigned long core; + + asm volatile("csrr %0, mhartid;" + : "=r"(core)); + spinlock_lock(&lock->lock); + + if (lock->count == 0) + { + /* First time get lock */ + lock->count++; + lock->core = core; + } + else if (lock->core == core) + { + /* Same core get lock */ + lock->count++; + } + else + { + /* Different core get lock */ + spinlock_unlock(&lock->lock); + + do + { + while (atomic_read(&lock->count)) + ; + } while (corelock_trylock(lock)); + return; + } + spinlock_unlock(&lock->lock); +} + +static inline void corelock_unlock(corelock_t *lock) +{ + unsigned long core; + + asm volatile("csrr %0, mhartid;" + : "=r"(core)); + spinlock_lock(&lock->lock); + + if (lock->core == core) + { + /* Same core release lock */ + lock->count--; + if (lock->count <= 0) + { + lock->core = -1; + lock->count = 0; + } + } + else + { + /* Different core release lock */ + spinlock_unlock(&lock->lock); + + register unsigned long a7 asm("a7") = 93; + register unsigned long a0 asm("a0") = 0; + register unsigned long a1 asm("a1") = 0; + register unsigned long a2 asm("a2") = 0; + + asm volatile("scall" + : "+r"(a0) + : "r"(a1), "r"(a2), "r"(a7)); + } + spinlock_unlock(&lock->lock); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_ATOMIC_H */ + diff --git a/board/k210-emulator/include/bsp.h b/board/k210-emulator/include/bsp.h new file mode 100644 index 00000000..ea1e7bc7 --- /dev/null +++ b/board/k210-emulator/include/bsp.h @@ -0,0 +1,31 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 bsp.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _KENDRYTE_BSP_H +#define _KENDRYTE_BSP_H +#include "atomic.h" +#include "entry.h" +#include "sleep.h" +#include "encoding.h" +#endif \ No newline at end of file diff --git a/board/k210-emulator/include/dump.h b/board/k210-emulator/include/dump.h new file mode 100644 index 00000000..8da4c223 --- /dev/null +++ b/board/k210-emulator/include/dump.h @@ -0,0 +1,150 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 dump.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _BSP_DUMP_H +#define _BSP_DUMP_H + +#include +#include +#include "syslog.h" +#include "hardware_uarths.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DUMP_PRINTF printk + +static inline void +dump_core(const char *reason, uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + static const char *const reg_usage[][2] = + { + {"zero ", "Hard-wired zero"}, + {"ra ", "Return address"}, + {"sp ", "Stack pointer"}, + {"gp ", "Global pointer"}, + {"tp ", "Task pointer"}, + {"t0 ", "Temporaries Caller"}, + {"t1 ", "Temporaries Caller"}, + {"t2 ", "Temporaries Caller"}, + {"s0/fp", "Saved register/frame pointer"}, + {"s1 ", "Saved register"}, + {"a0 ", "Function arguments/return values"}, + {"a1 ", "Function arguments/return values"}, + {"a2 ", "Function arguments values"}, + {"a3 ", "Function arguments values"}, + {"a4 ", "Function arguments values"}, + {"a5 ", "Function arguments values"}, + {"a6 ", "Function arguments values"}, + {"a7 ", "Function arguments values"}, + {"s2 ", "Saved registers"}, + {"s3 ", "Saved registers"}, + {"s4 ", "Saved registers"}, + {"s5 ", "Saved registers"}, + {"s6 ", "Saved registers"}, + {"s7 ", "Saved registers"}, + {"s8 ", "Saved registers"}, + {"s9 ", "Saved registers"}, + {"s10 ", "Saved registers"}, + {"s11 ", "Saved registers"}, + {"t3 ", "Temporaries Caller"}, + {"t4 ", "Temporaries Caller"}, + {"t5 ", "Temporaries Caller"}, + {"t6 ", "Temporaries Caller"}, + }; + + static const char *const regf_usage[][2] = + { + {"ft0 ", "FP temporaries"}, + {"ft1 ", "FP temporaries"}, + {"ft2 ", "FP temporaries"}, + {"ft3 ", "FP temporaries"}, + {"ft4 ", "FP temporaries"}, + {"ft5 ", "FP temporaries"}, + {"ft6 ", "FP temporaries"}, + {"ft7 ", "FP temporaries"}, + {"fs0 ", "FP saved registers"}, + {"fs1 ", "FP saved registers"}, + {"fa0 ", "FP arguments/return values"}, + {"fa1 ", "FP arguments/return values"}, + {"fa2 ", "FP arguments values"}, + {"fa3 ", "FP arguments values"}, + {"fa4 ", "FP arguments values"}, + {"fa5 ", "FP arguments values"}, + {"fa6 ", "FP arguments values"}, + {"fa7 ", "FP arguments values"}, + {"fs2 ", "FP Saved registers"}, + {"fs3 ", "FP Saved registers"}, + {"fs4 ", "FP Saved registers"}, + {"fs5 ", "FP Saved registers"}, + {"fs6 ", "FP Saved registers"}, + {"fs7 ", "FP Saved registers"}, + {"fs8 ", "FP Saved registers"}, + {"fs9 ", "FP Saved registers"}, + {"fs10", "FP Saved registers"}, + {"fs11", "FP Saved registers"}, + {"ft8 ", "FP Temporaries Caller"}, + {"ft9 ", "FP Temporaries Caller"}, + {"ft10", "FP Temporaries Caller"}, + {"ft11", "FP Temporaries Caller"}, + }; + + if (CONFIG_LOG_LEVEL >= LOG_ERROR) + { + const char unknown_reason[] = "unknown"; + + if (!reason) + reason = unknown_reason; + + DUMP_PRINTF("core dump: %s\r\n", reason); + DUMP_PRINTF("Cause 0x%016lx, EPC 0x%016lx\r\n", cause, epc); + + int i = 0; + for (i = 0; i < 32 / 2; i++) + { + DUMP_PRINTF( + "reg[%02d](%s) = 0x%016lx, reg[%02d](%s) = 0x%016lx\r\n", + i * 2, reg_usage[i * 2][0], regs[i * 2], + i * 2 + 1, reg_usage[i * 2 + 1][0], regs[i * 2 + 1]); + } + + for (i = 0; i < 32 / 2; i++) + { + DUMP_PRINTF( + "freg[%02d](%s) = 0x%016lx(%f), freg[%02d](%s) = 0x%016lx(%f)\r\n", + i * 2, regf_usage[i * 2][0], fregs[i * 2], (float)fregs[i * 2], + i * 2 + 1, regf_usage[i * 2 + 1][0], fregs[i * 2 + 1], (float)fregs[i * 2 + 1]); + } + } +} + +#undef DUMP_PRINTF + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_DUMP_H */ + diff --git a/board/k210-emulator/include/encoding.h b/board/k210-emulator/include/encoding.h new file mode 100644 index 00000000..6a5f1a62 --- /dev/null +++ b/board/k210-emulator/include/encoding.h @@ -0,0 +1,1336 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 encoding.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001U +#define MSTATUS_SIE 0x00000002U +#define MSTATUS_HIE 0x00000004U +#define MSTATUS_MIE 0x00000008U +#define MSTATUS_UPIE 0x00000010U +#define MSTATUS_SPIE 0x00000020U +#define MSTATUS_HPIE 0x00000040U +#define MSTATUS_MPIE 0x00000080U +#define MSTATUS_SPP 0x00000100U +#define MSTATUS_HPP 0x00000600U +#define MSTATUS_MPP 0x00001800U +#define MSTATUS_FS 0x00006000U +#define MSTATUS_XS 0x00018000U +#define MSTATUS_MPRV 0x00020000U +#define MSTATUS_PUM 0x00040000U +#define MSTATUS_MXR 0x00080000U +#define MSTATUS_VM 0x1F000000U +#define MSTATUS32_SD 0x80000000U +#define MSTATUS64_SD 0x8000000000000000U + +#define SSTATUS_UIE 0x00000001U +#define SSTATUS_SIE 0x00000002U +#define SSTATUS_UPIE 0x00000010U +#define SSTATUS_SPIE 0x00000020U +#define SSTATUS_SPP 0x00000100U +#define SSTATUS_FS 0x00006000U +#define SSTATUS_XS 0x00018000U +#define SSTATUS_PUM 0x00040000U +#define SSTATUS32_SD 0x80000000U +#define SSTATUS64_SD 0x8000000000000000U + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1U<<29) +#define DCSR_FULLRESET (1U<<28) +#define DCSR_EBREAKM (1U<<15) +#define DCSR_EBREAKH (1U<<14) +#define DCSR_EBREAKS (1U<<13) +#define DCSR_EBREAKU (1U<<12) +#define DCSR_STOPCYCLE (1U<<10) +#define DCSR_STOPTIME (1U<<9) +#define DCSR_CAUSE (7U<<6) +#define DCSR_DEBUGINT (1U<<5) +#define DCSR_HALT (1U<<3) +#define DCSR_STEP (1U<<2) +#define DCSR_PRV (3U<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_SELECT (1U<<19) +#define MCONTROL_TIMING (1U<<18) +#define MCONTROL_ACTION (0x3fU<<12) +#define MCONTROL_CHAIN (1U<<11) +#define MCONTROL_MATCH (0xfU<<7) +#define MCONTROL_M (1U<<6) +#define MCONTROL_H (1U<<5) +#define MCONTROL_S (1U<<4) +#define MCONTROL_U (1U<<3) +#define MCONTROL_EXECUTE (1U<<2) +#define MCONTROL_STORE (1U<<1) +#define MCONTROL_LOAD (1U<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1U << IRQ_S_SOFT) +#define MIP_HSIP (1U << IRQ_H_SOFT) +#define MIP_MSIP (1U << IRQ_M_SOFT) +#define MIP_STIP (1U << IRQ_S_TIMER) +#define MIP_HTIP (1U << IRQ_H_TIMER) +#define MIP_MTIP (1U << IRQ_M_TIMER) +#define MIP_SEIP (1U << IRQ_S_EXT) +#define MIP_HEIP (1U << IRQ_H_EXT) +#define MIP_MEIP (1U << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define VM_MBARE 0 +#define VM_MBB 1 +#define VM_MBBID 2 +#define VM_SV32 8 +#define VM_SV39 9 +#define VM_SV48 10 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000U +#define DEFAULT_NMIVEC 0x00001004U +#define DEFAULT_MTVEC 0x00001010U +#define CONFIG_STRING_ADDR 0x0000100CU +#define EXT_IO_BASE 0x40000000U +#define DRAM_BASE 0x80000000U + +/* page table entry (PTE) fields */ +#define PTE_V 0x001U /* Valid */ +#define PTE_R 0x002U /* Read */ +#define PTE_W 0x004U /* Write */ +#define PTE_X 0x008U /* Execute */ +#define PTE_U 0x010U /* User */ +#define PTE_G 0x020U /* Global */ +#define PTE_A 0x040U /* Accessed */ +#define PTE_D 0x080U /* Dirty */ +#define PTE_SOFT 0x300U /* Reserved for Software */ + +#define PTE_PPN_SHIFT 10 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#if defined(__riscv) + +#if defined(__riscv64) +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#if defined(__GNUC__) + +#define READ_CSR(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define WRITE_CSR(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ + else \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + __tmp; }) + +#define SET_CSR(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define CLEAR_CSR(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define read_time() READ_CSR(mtime) +#define read_cycle() READ_CSR(mcycle) +#define current_coreid() READ_CSR(mhartid) + +#endif + +#endif + +#endif + +#endif + +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63U +#define MASK_BEQ 0x707fU +#define MATCH_BNE 0x1063U +#define MASK_BNE 0x707fU +#define MATCH_BLT 0x4063U +#define MASK_BLT 0x707fU +#define MATCH_BGE 0x5063U +#define MASK_BGE 0x707fU +#define MATCH_BLTU 0x6063U +#define MASK_BLTU 0x707fU +#define MATCH_BGEU 0x7063U +#define MASK_BGEU 0x707fU +#define MATCH_JALR 0x67U +#define MASK_JALR 0x707fU +#define MATCH_JAL 0x6fU +#define MASK_JAL 0x7fU +#define MATCH_LUI 0x37U +#define MASK_LUI 0x7fU +#define MATCH_AUIPC 0x17U +#define MASK_AUIPC 0x7fU +#define MATCH_ADDI 0x13U +#define MASK_ADDI 0x707fU +#define MATCH_SLLI 0x1013U +#define MASK_SLLI 0xfc00707fU +#define MATCH_SLTI 0x2013U +#define MASK_SLTI 0x707fU +#define MATCH_SLTIU 0x3013U +#define MASK_SLTIU 0x707fU +#define MATCH_XORI 0x4013U +#define MASK_XORI 0x707fU +#define MATCH_SRLI 0x5013U +#define MASK_SRLI 0xfc00707fU +#define MATCH_SRAI 0x40005013U +#define MASK_SRAI 0xfc00707fU +#define MATCH_ORI 0x6013U +#define MASK_ORI 0x707fU +#define MATCH_ANDI 0x7013U +#define MASK_ANDI 0x707fU +#define MATCH_ADD 0x33U +#define MASK_ADD 0xfe00707fU +#define MATCH_SUB 0x40000033U +#define MASK_SUB 0xfe00707fU +#define MATCH_SLL 0x1033U +#define MASK_SLL 0xfe00707fU +#define MATCH_SLT 0x2033U +#define MASK_SLT 0xfe00707fU +#define MATCH_SLTU 0x3033U +#define MASK_SLTU 0xfe00707fU +#define MATCH_XOR 0x4033U +#define MASK_XOR 0xfe00707fU +#define MATCH_SRL 0x5033U +#define MASK_SRL 0xfe00707fU +#define MATCH_SRA 0x40005033U +#define MASK_SRA 0xfe00707fU +#define MATCH_OR 0x6033U +#define MASK_OR 0xfe00707fU +#define MATCH_AND 0x7033U +#define MASK_AND 0xfe00707fU +#define MATCH_ADDIW 0x1bU +#define MASK_ADDIW 0x707fU +#define MATCH_SLLIW 0x101bU +#define MASK_SLLIW 0xfe00707fU +#define MATCH_SRLIW 0x501bU +#define MASK_SRLIW 0xfe00707fU +#define MATCH_SRAIW 0x4000501bU +#define MASK_SRAIW 0xfe00707fU +#define MATCH_ADDW 0x3bU +#define MASK_ADDW 0xfe00707fU +#define MATCH_SUBW 0x4000003bU +#define MASK_SUBW 0xfe00707fU +#define MATCH_SLLW 0x103bU +#define MASK_SLLW 0xfe00707fU +#define MATCH_SRLW 0x503bU +#define MASK_SRLW 0xfe00707fU +#define MATCH_SRAW 0x4000503bU +#define MASK_SRAW 0xfe00707fU +#define MATCH_LB 0x3U +#define MASK_LB 0x707fU +#define MATCH_LH 0x1003U +#define MASK_LH 0x707fU +#define MATCH_LW 0x2003U +#define MASK_LW 0x707fU +#define MATCH_LD 0x3003U +#define MASK_LD 0x707fU +#define MATCH_LBU 0x4003U +#define MASK_LBU 0x707fU +#define MATCH_LHU 0x5003U +#define MASK_LHU 0x707fU +#define MATCH_LWU 0x6003U +#define MASK_LWU 0x707fU +#define MATCH_SB 0x23U +#define MASK_SB 0x707fU +#define MATCH_SH 0x1023U +#define MASK_SH 0x707fU +#define MATCH_SW 0x2023U +#define MASK_SW 0x707fU +#define MATCH_SD 0x3023U +#define MASK_SD 0x707fU +#define MATCH_FENCE 0xfU +#define MASK_FENCE 0x707fU +#define MATCH_FENCE_I 0x100fU +#define MASK_FENCE_I 0x707fU +#define MATCH_MUL 0x2000033U +#define MASK_MUL 0xfe00707fU +#define MATCH_MULH 0x2001033U +#define MASK_MULH 0xfe00707fU +#define MATCH_MULHSU 0x2002033U +#define MASK_MULHSU 0xfe00707fU +#define MATCH_MULHU 0x2003033U +#define MASK_MULHU 0xfe00707fU +#define MATCH_DIV 0x2004033U +#define MASK_DIV 0xfe00707fU +#define MATCH_DIVU 0x2005033U +#define MASK_DIVU 0xfe00707fU +#define MATCH_REM 0x2006033U +#define MASK_REM 0xfe00707fU +#define MATCH_REMU 0x2007033U +#define MASK_REMU 0xfe00707fU +#define MATCH_MULW 0x200003bU +#define MASK_MULW 0xfe00707fU +#define MATCH_DIVW 0x200403bU +#define MASK_DIVW 0xfe00707fU +#define MATCH_DIVUW 0x200503bU +#define MASK_DIVUW 0xfe00707fU +#define MATCH_REMW 0x200603bU +#define MASK_REMW 0xfe00707fU +#define MATCH_REMUW 0x200703bU +#define MASK_REMUW 0xfe00707fU +#define MATCH_AMOADD_W 0x202fU +#define MASK_AMOADD_W 0xf800707fU +#define MATCH_AMOXOR_W 0x2000202fU +#define MASK_AMOXOR_W 0xf800707fU +#define MATCH_AMOOR_W 0x4000202fU +#define MASK_AMOOR_W 0xf800707fU +#define MATCH_AMOAND_W 0x6000202fU +#define MASK_AMOAND_W 0xf800707fU +#define MATCH_AMOMIN_W 0x8000202fU +#define MASK_AMOMIN_W 0xf800707fU +#define MATCH_AMOMAX_W 0xa000202fU +#define MASK_AMOMAX_W 0xf800707fU +#define MATCH_AMOMINU_W 0xc000202fU +#define MASK_AMOMINU_W 0xf800707fU +#define MATCH_AMOMAXU_W 0xe000202fU +#define MASK_AMOMAXU_W 0xf800707fU +#define MATCH_AMOSWAP_W 0x800202fU +#define MASK_AMOSWAP_W 0xf800707fU +#define MATCH_LR_W 0x1000202fU +#define MASK_LR_W 0xf9f0707fU +#define MATCH_SC_W 0x1800202fU +#define MASK_SC_W 0xf800707fU +#define MATCH_AMOADD_D 0x302fU +#define MASK_AMOADD_D 0xf800707fU +#define MATCH_AMOXOR_D 0x2000302fU +#define MASK_AMOXOR_D 0xf800707fU +#define MATCH_AMOOR_D 0x4000302fU +#define MASK_AMOOR_D 0xf800707fU +#define MATCH_AMOAND_D 0x6000302fU +#define MASK_AMOAND_D 0xf800707fU +#define MATCH_AMOMIN_D 0x8000302fU +#define MASK_AMOMIN_D 0xf800707fU +#define MATCH_AMOMAX_D 0xa000302fU +#define MASK_AMOMAX_D 0xf800707fU +#define MATCH_AMOMINU_D 0xc000302fU +#define MASK_AMOMINU_D 0xf800707fU +#define MATCH_AMOMAXU_D 0xe000302fU +#define MASK_AMOMAXU_D 0xf800707fU +#define MATCH_AMOSWAP_D 0x800302fU +#define MASK_AMOSWAP_D 0xf800707fU +#define MATCH_LR_D 0x1000302fU +#define MASK_LR_D 0xf9f0707fU +#define MATCH_SC_D 0x1800302fU +#define MASK_SC_D 0xf800707fU +#define MATCH_ECALL 0x73U +#define MASK_ECALL 0xffffffffU +#define MATCH_EBREAK 0x100073U +#define MASK_EBREAK 0xffffffffU +#define MATCH_URET 0x200073U +#define MASK_URET 0xffffffffU +#define MATCH_SRET 0x10200073U +#define MASK_SRET 0xffffffffU +#define MATCH_HRET 0x20200073U +#define MASK_HRET 0xffffffffU +#define MATCH_MRET 0x30200073U +#define MASK_MRET 0xffffffffU +#define MATCH_DRET 0x7b200073U +#define MASK_DRET 0xffffffffU +#define MATCH_SFENCE_VM 0x10400073U +#define MASK_SFENCE_VM 0xfff07fffU +#define MATCH_WFI 0x10500073U +#define MASK_WFI 0xffffffffU +#define MATCH_CSRRW 0x1073U +#define MASK_CSRRW 0x707fU +#define MATCH_CSRRS 0x2073U +#define MASK_CSRRS 0x707fU +#define MATCH_CSRRC 0x3073U +#define MASK_CSRRC 0x707fU +#define MATCH_CSRRWI 0x5073U +#define MASK_CSRRWI 0x707fU +#define MATCH_CSRRSI 0x6073U +#define MASK_CSRRSI 0x707fU +#define MATCH_CSRRCI 0x7073U +#define MASK_CSRRCI 0x707fU +#define MATCH_FADD_S 0x53U +#define MASK_FADD_S 0xfe00007fU +#define MATCH_FSUB_S 0x8000053U +#define MASK_FSUB_S 0xfe00007fU +#define MATCH_FMUL_S 0x10000053U +#define MASK_FMUL_S 0xfe00007fU +#define MATCH_FDIV_S 0x18000053U +#define MASK_FDIV_S 0xfe00007fU +#define MATCH_FSGNJ_S 0x20000053U +#define MASK_FSGNJ_S 0xfe00707fU +#define MATCH_FSGNJN_S 0x20001053U +#define MASK_FSGNJN_S 0xfe00707fU +#define MATCH_FSGNJX_S 0x20002053U +#define MASK_FSGNJX_S 0xfe00707fU +#define MATCH_FMIN_S 0x28000053U +#define MASK_FMIN_S 0xfe00707fU +#define MATCH_FMAX_S 0x28001053U +#define MASK_FMAX_S 0xfe00707fU +#define MATCH_FSQRT_S 0x58000053U +#define MASK_FSQRT_S 0xfff0007fU +#define MATCH_FADD_D 0x2000053U +#define MASK_FADD_D 0xfe00007fU +#define MATCH_FSUB_D 0xa000053U +#define MASK_FSUB_D 0xfe00007fU +#define MATCH_FMUL_D 0x12000053U +#define MASK_FMUL_D 0xfe00007fU +#define MATCH_FDIV_D 0x1a000053U +#define MASK_FDIV_D 0xfe00007fU +#define MATCH_FSGNJ_D 0x22000053U +#define MASK_FSGNJ_D 0xfe00707fU +#define MATCH_FSGNJN_D 0x22001053U +#define MASK_FSGNJN_D 0xfe00707fU +#define MATCH_FSGNJX_D 0x22002053U +#define MASK_FSGNJX_D 0xfe00707fU +#define MATCH_FMIN_D 0x2a000053U +#define MASK_FMIN_D 0xfe00707fU +#define MATCH_FMAX_D 0x2a001053U +#define MASK_FMAX_D 0xfe00707fU +#define MATCH_FCVT_S_D 0x40100053U +#define MASK_FCVT_S_D 0xfff0007fU +#define MATCH_FCVT_D_S 0x42000053U +#define MASK_FCVT_D_S 0xfff0007fU +#define MATCH_FSQRT_D 0x5a000053U +#define MASK_FSQRT_D 0xfff0007fU +#define MATCH_FLE_S 0xa0000053U +#define MASK_FLE_S 0xfe00707fU +#define MATCH_FLT_S 0xa0001053U +#define MASK_FLT_S 0xfe00707fU +#define MATCH_FEQ_S 0xa0002053U +#define MASK_FEQ_S 0xfe00707fU +#define MATCH_FLE_D 0xa2000053U +#define MASK_FLE_D 0xfe00707fU +#define MATCH_FLT_D 0xa2001053U +#define MASK_FLT_D 0xfe00707fU +#define MATCH_FEQ_D 0xa2002053U +#define MASK_FEQ_D 0xfe00707fU +#define MATCH_FCVT_W_S 0xc0000053U +#define MASK_FCVT_W_S 0xfff0007fU +#define MATCH_FCVT_WU_S 0xc0100053U +#define MASK_FCVT_WU_S 0xfff0007fU +#define MATCH_FCVT_L_S 0xc0200053U +#define MASK_FCVT_L_S 0xfff0007fU +#define MATCH_FCVT_LU_S 0xc0300053U +#define MASK_FCVT_LU_S 0xfff0007fU +#define MATCH_FMV_X_S 0xe0000053U +#define MASK_FMV_X_S 0xfff0707fU +#define MATCH_FCLASS_S 0xe0001053U +#define MASK_FCLASS_S 0xfff0707fU +#define MATCH_FCVT_W_D 0xc2000053U +#define MASK_FCVT_W_D 0xfff0007fU +#define MATCH_FCVT_WU_D 0xc2100053U +#define MASK_FCVT_WU_D 0xfff0007fU +#define MATCH_FCVT_L_D 0xc2200053U +#define MASK_FCVT_L_D 0xfff0007fU +#define MATCH_FCVT_LU_D 0xc2300053U +#define MASK_FCVT_LU_D 0xfff0007fU +#define MATCH_FMV_X_D 0xe2000053U +#define MASK_FMV_X_D 0xfff0707fU +#define MATCH_FCLASS_D 0xe2001053U +#define MASK_FCLASS_D 0xfff0707fU +#define MATCH_FCVT_S_W 0xd0000053U +#define MASK_FCVT_S_W 0xfff0007fU +#define MATCH_FCVT_S_WU 0xd0100053U +#define MASK_FCVT_S_WU 0xfff0007fU +#define MATCH_FCVT_S_L 0xd0200053U +#define MASK_FCVT_S_L 0xfff0007fU +#define MATCH_FCVT_S_LU 0xd0300053U +#define MASK_FCVT_S_LU 0xfff0007fU +#define MATCH_FMV_S_X 0xf0000053U +#define MASK_FMV_S_X 0xfff0707fU +#define MATCH_FCVT_D_W 0xd2000053U +#define MASK_FCVT_D_W 0xfff0007fU +#define MATCH_FCVT_D_WU 0xd2100053U +#define MASK_FCVT_D_WU 0xfff0007fU +#define MATCH_FCVT_D_L 0xd2200053U +#define MASK_FCVT_D_L 0xfff0007fU +#define MATCH_FCVT_D_LU 0xd2300053U +#define MASK_FCVT_D_LU 0xfff0007fU +#define MATCH_FMV_D_X 0xf2000053U +#define MASK_FMV_D_X 0xfff0707fU +#define MATCH_FLW 0x2007U +#define MASK_FLW 0x707fU +#define MATCH_FLD 0x3007U +#define MASK_FLD 0x707fU +#define MATCH_FSW 0x2027U +#define MASK_FSW 0x707fU +#define MATCH_FSD 0x3027U +#define MASK_FSD 0x707fU +#define MATCH_FMADD_S 0x43U +#define MASK_FMADD_S 0x600007fU +#define MATCH_FMSUB_S 0x47U +#define MASK_FMSUB_S 0x600007fU +#define MATCH_FNMSUB_S 0x4bU +#define MASK_FNMSUB_S 0x600007fU +#define MATCH_FNMADD_S 0x4fU +#define MASK_FNMADD_S 0x600007fU +#define MATCH_FMADD_D 0x2000043U +#define MASK_FMADD_D 0x600007fU +#define MATCH_FMSUB_D 0x2000047U +#define MASK_FMSUB_D 0x600007fU +#define MATCH_FNMSUB_D 0x200004bU +#define MASK_FNMSUB_D 0x600007fU +#define MATCH_FNMADD_D 0x200004fU +#define MASK_FNMADD_D 0x600007fU +#define MATCH_C_NOP 0x1U +#define MASK_C_NOP 0xffffU +#define MATCH_C_ADDI16SP 0x6101U +#define MASK_C_ADDI16SP 0xef83U +#define MATCH_C_JR 0x8002U +#define MASK_C_JR 0xf07fU +#define MATCH_C_JALR 0x9002U +#define MASK_C_JALR 0xf07fU +#define MATCH_C_EBREAK 0x9002U +#define MASK_C_EBREAK 0xffffU +#define MATCH_C_LD 0x6000U +#define MASK_C_LD 0xe003U +#define MATCH_C_SD 0xe000U +#define MASK_C_SD 0xe003U +#define MATCH_C_ADDIW 0x2001U +#define MASK_C_ADDIW 0xe003U +#define MATCH_C_LDSP 0x6002U +#define MASK_C_LDSP 0xe003U +#define MATCH_C_SDSP 0xe002U +#define MASK_C_SDSP 0xe003U +#define MATCH_C_ADDI4SPN 0x0U +#define MASK_C_ADDI4SPN 0xe003U +#define MATCH_C_FLD 0x2000U +#define MASK_C_FLD 0xe003U +#define MATCH_C_LW 0x4000U +#define MASK_C_LW 0xe003U +#define MATCH_C_FLW 0x6000U +#define MASK_C_FLW 0xe003U +#define MATCH_C_FSD 0xa000U +#define MASK_C_FSD 0xe003U +#define MATCH_C_SW 0xc000U +#define MASK_C_SW 0xe003U +#define MATCH_C_FSW 0xe000U +#define MASK_C_FSW 0xe003U +#define MATCH_C_ADDI 0x1U +#define MASK_C_ADDI 0xe003U +#define MATCH_C_JAL 0x2001U +#define MASK_C_JAL 0xe003U +#define MATCH_C_LI 0x4001U +#define MASK_C_LI 0xe003U +#define MATCH_C_LUI 0x6001U +#define MASK_C_LUI 0xe003U +#define MATCH_C_SRLI 0x8001U +#define MASK_C_SRLI 0xec03U +#define MATCH_C_SRAI 0x8401U +#define MASK_C_SRAI 0xec03U +#define MATCH_C_ANDI 0x8801U +#define MASK_C_ANDI 0xec03U +#define MATCH_C_SUB 0x8c01U +#define MASK_C_SUB 0xfc63U +#define MATCH_C_XOR 0x8c21U +#define MASK_C_XOR 0xfc63U +#define MATCH_C_OR 0x8c41U +#define MASK_C_OR 0xfc63U +#define MATCH_C_AND 0x8c61U +#define MASK_C_AND 0xfc63U +#define MATCH_C_SUBW 0x9c01U +#define MASK_C_SUBW 0xfc63U +#define MATCH_C_ADDW 0x9c21U +#define MASK_C_ADDW 0xfc63U +#define MATCH_C_J 0xa001U +#define MASK_C_J 0xe003U +#define MATCH_C_BEQZ 0xc001U +#define MASK_C_BEQZ 0xe003U +#define MATCH_C_BNEZ 0xe001U +#define MASK_C_BNEZ 0xe003U +#define MATCH_C_SLLI 0x2U +#define MASK_C_SLLI 0xe003U +#define MATCH_C_FLDSP 0x2002U +#define MASK_C_FLDSP 0xe003U +#define MATCH_C_LWSP 0x4002U +#define MASK_C_LWSP 0xe003U +#define MATCH_C_FLWSP 0x6002U +#define MASK_C_FLWSP 0xe003U +#define MATCH_C_MV 0x8002U +#define MASK_C_MV 0xf003U +#define MATCH_C_ADD 0x9002U +#define MASK_C_ADD 0xf003U +#define MATCH_C_FSDSP 0xa002U +#define MASK_C_FSDSP 0xe003U +#define MATCH_C_SWSP 0xc002U +#define MASK_C_SWSP 0xe003U +#define MATCH_C_FSWSP 0xe002U +#define MASK_C_FSWSP 0xe003U +#define MATCH_CUSTOM0 0xbU +#define MASK_CUSTOM0 0x707fU +#define MATCH_CUSTOM0_RS1 0x200bU +#define MASK_CUSTOM0_RS1 0x707fU +#define MATCH_CUSTOM0_RS1_RS2 0x300bU +#define MASK_CUSTOM0_RS1_RS2 0x707fU +#define MATCH_CUSTOM0_RD 0x400bU +#define MASK_CUSTOM0_RD 0x707fU +#define MATCH_CUSTOM0_RD_RS1 0x600bU +#define MASK_CUSTOM0_RD_RS1 0x707fU +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700bU +#define MASK_CUSTOM0_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM1 0x2bU +#define MASK_CUSTOM1 0x707fU +#define MATCH_CUSTOM1_RS1 0x202bU +#define MASK_CUSTOM1_RS1 0x707fU +#define MATCH_CUSTOM1_RS1_RS2 0x302bU +#define MASK_CUSTOM1_RS1_RS2 0x707fU +#define MATCH_CUSTOM1_RD 0x402bU +#define MASK_CUSTOM1_RD 0x707fU +#define MATCH_CUSTOM1_RD_RS1 0x602bU +#define MASK_CUSTOM1_RD_RS1 0x707fU +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702bU +#define MASK_CUSTOM1_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM2 0x5bU +#define MASK_CUSTOM2 0x707fU +#define MATCH_CUSTOM2_RS1 0x205bU +#define MASK_CUSTOM2_RS1 0x707fU +#define MATCH_CUSTOM2_RS1_RS2 0x305bU +#define MASK_CUSTOM2_RS1_RS2 0x707fU +#define MATCH_CUSTOM2_RD 0x405bU +#define MASK_CUSTOM2_RD 0x707fU +#define MATCH_CUSTOM2_RD_RS1 0x605bU +#define MASK_CUSTOM2_RD_RS1 0x707fU +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705bU +#define MASK_CUSTOM2_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM3 0x7bU +#define MASK_CUSTOM3 0x707fU +#define MATCH_CUSTOM3_RS1 0x207bU +#define MASK_CUSTOM3_RS1 0x707fU +#define MATCH_CUSTOM3_RS1_RS2 0x307bU +#define MASK_CUSTOM3_RS1_RS2 0x707fU +#define MATCH_CUSTOM3_RD 0x407bU +#define MASK_CUSTOM3_RD 0x707fU +#define MATCH_CUSTOM3_RD_RS1 0x607bU +#define MASK_CUSTOM3_RD_RS1 0x707fU +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707bU +#define MASK_CUSTOM3_RD_RS1_RS2 0x707fU +#define CSR_FFLAGS 0x1U +#define CSR_FRM 0x2U +#define CSR_FCSR 0x3U +#define CSR_CYCLE 0xc00U +#define CSR_TIME 0xc01U +#define CSR_INSTRET 0xc02U +#define CSR_HPMCOUNTER3 0xc03U +#define CSR_HPMCOUNTER4 0xc04U +#define CSR_HPMCOUNTER5 0xc05U +#define CSR_HPMCOUNTER6 0xc06U +#define CSR_HPMCOUNTER7 0xc07U +#define CSR_HPMCOUNTER8 0xc08U +#define CSR_HPMCOUNTER9 0xc09U +#define CSR_HPMCOUNTER10 0xc0aU +#define CSR_HPMCOUNTER11 0xc0bU +#define CSR_HPMCOUNTER12 0xc0cU +#define CSR_HPMCOUNTER13 0xc0dU +#define CSR_HPMCOUNTER14 0xc0eU +#define CSR_HPMCOUNTER15 0xc0fU +#define CSR_HPMCOUNTER16 0xc10U +#define CSR_HPMCOUNTER17 0xc11U +#define CSR_HPMCOUNTER18 0xc12U +#define CSR_HPMCOUNTER19 0xc13U +#define CSR_HPMCOUNTER20 0xc14U +#define CSR_HPMCOUNTER21 0xc15U +#define CSR_HPMCOUNTER22 0xc16U +#define CSR_HPMCOUNTER23 0xc17U +#define CSR_HPMCOUNTER24 0xc18U +#define CSR_HPMCOUNTER25 0xc19U +#define CSR_HPMCOUNTER26 0xc1aU +#define CSR_HPMCOUNTER27 0xc1bU +#define CSR_HPMCOUNTER28 0xc1cU +#define CSR_HPMCOUNTER29 0xc1dU +#define CSR_HPMCOUNTER30 0xc1eU +#define CSR_HPMCOUNTER31 0xc1fU +#define CSR_SSTATUS 0x100U +#define CSR_SIE 0x104U +#define CSR_STVEC 0x105U +#define CSR_SSCRATCH 0x140U +#define CSR_SEPC 0x141U +#define CSR_SCAUSE 0x142U +#define CSR_SBADADDR 0x143U +#define CSR_SIP 0x144U +#define CSR_SPTBR 0x180U +#define CSR_MSTATUS 0x300U +#define CSR_MISA 0x301U +#define CSR_MEDELEG 0x302U +#define CSR_MIDELEG 0x303U +#define CSR_MIE 0x304U +#define CSR_MTVEC 0x305U +#define CSR_MSCRATCH 0x340U +#define CSR_MEPC 0x341U +#define CSR_MCAUSE 0x342U +#define CSR_MBADADDR 0x343U +#define CSR_MIP 0x344U +#define CSR_TSELECT 0x7a0U +#define CSR_TDATA1 0x7a1U +#define CSR_TDATA2 0x7a2U +#define CSR_TDATA3 0x7a3U +#define CSR_DCSR 0x7b0U +#define CSR_DPC 0x7b1U +#define CSR_DSCRATCH 0x7b2U +#define CSR_MCYCLE 0xb00U +#define CSR_MINSTRET 0xb02U +#define CSR_MHPMCOUNTER3 0xb03U +#define CSR_MHPMCOUNTER4 0xb04U +#define CSR_MHPMCOUNTER5 0xb05U +#define CSR_MHPMCOUNTER6 0xb06U +#define CSR_MHPMCOUNTER7 0xb07U +#define CSR_MHPMCOUNTER8 0xb08U +#define CSR_MHPMCOUNTER9 0xb09U +#define CSR_MHPMCOUNTER10 0xb0aU +#define CSR_MHPMCOUNTER11 0xb0bU +#define CSR_MHPMCOUNTER12 0xb0cU +#define CSR_MHPMCOUNTER13 0xb0dU +#define CSR_MHPMCOUNTER14 0xb0eU +#define CSR_MHPMCOUNTER15 0xb0fU +#define CSR_MHPMCOUNTER16 0xb10U +#define CSR_MHPMCOUNTER17 0xb11U +#define CSR_MHPMCOUNTER18 0xb12U +#define CSR_MHPMCOUNTER19 0xb13U +#define CSR_MHPMCOUNTER20 0xb14U +#define CSR_MHPMCOUNTER21 0xb15U +#define CSR_MHPMCOUNTER22 0xb16U +#define CSR_MHPMCOUNTER23 0xb17U +#define CSR_MHPMCOUNTER24 0xb18U +#define CSR_MHPMCOUNTER25 0xb19U +#define CSR_MHPMCOUNTER26 0xb1aU +#define CSR_MHPMCOUNTER27 0xb1bU +#define CSR_MHPMCOUNTER28 0xb1cU +#define CSR_MHPMCOUNTER29 0xb1dU +#define CSR_MHPMCOUNTER30 0xb1eU +#define CSR_MHPMCOUNTER31 0xb1fU +#define CSR_MUCOUNTEREN 0x320U +#define CSR_MSCOUNTEREN 0x321U +#define CSR_MHPMEVENT3 0x323U +#define CSR_MHPMEVENT4 0x324U +#define CSR_MHPMEVENT5 0x325U +#define CSR_MHPMEVENT6 0x326U +#define CSR_MHPMEVENT7 0x327U +#define CSR_MHPMEVENT8 0x328U +#define CSR_MHPMEVENT9 0x329U +#define CSR_MHPMEVENT10 0x32aU +#define CSR_MHPMEVENT11 0x32bU +#define CSR_MHPMEVENT12 0x32cU +#define CSR_MHPMEVENT13 0x32dU +#define CSR_MHPMEVENT14 0x32eU +#define CSR_MHPMEVENT15 0x32fU +#define CSR_MHPMEVENT16 0x330U +#define CSR_MHPMEVENT17 0x331U +#define CSR_MHPMEVENT18 0x332U +#define CSR_MHPMEVENT19 0x333U +#define CSR_MHPMEVENT20 0x334U +#define CSR_MHPMEVENT21 0x335U +#define CSR_MHPMEVENT22 0x336U +#define CSR_MHPMEVENT23 0x337U +#define CSR_MHPMEVENT24 0x338U +#define CSR_MHPMEVENT25 0x339U +#define CSR_MHPMEVENT26 0x33aU +#define CSR_MHPMEVENT27 0x33bU +#define CSR_MHPMEVENT28 0x33cU +#define CSR_MHPMEVENT29 0x33dU +#define CSR_MHPMEVENT30 0x33eU +#define CSR_MHPMEVENT31 0x33fU +#define CSR_MVENDORID 0xf11U +#define CSR_MARCHID 0xf12U +#define CSR_MIMPID 0xf13U +#define CSR_MHARTID 0xf14U +#define CSR_CYCLEH 0xc80U +#define CSR_TIMEH 0xc81U +#define CSR_INSTRETH 0xc82U +#define CSR_HPMCOUNTER3H 0xc83U +#define CSR_HPMCOUNTER4H 0xc84U +#define CSR_HPMCOUNTER5H 0xc85U +#define CSR_HPMCOUNTER6H 0xc86U +#define CSR_HPMCOUNTER7H 0xc87U +#define CSR_HPMCOUNTER8H 0xc88U +#define CSR_HPMCOUNTER9H 0xc89U +#define CSR_HPMCOUNTER10H 0xc8aU +#define CSR_HPMCOUNTER11H 0xc8bU +#define CSR_HPMCOUNTER12H 0xc8cU +#define CSR_HPMCOUNTER13H 0xc8dU +#define CSR_HPMCOUNTER14H 0xc8eU +#define CSR_HPMCOUNTER15H 0xc8fU +#define CSR_HPMCOUNTER16H 0xc90U +#define CSR_HPMCOUNTER17H 0xc91U +#define CSR_HPMCOUNTER18H 0xc92U +#define CSR_HPMCOUNTER19H 0xc93U +#define CSR_HPMCOUNTER20H 0xc94U +#define CSR_HPMCOUNTER21H 0xc95U +#define CSR_HPMCOUNTER22H 0xc96U +#define CSR_HPMCOUNTER23H 0xc97U +#define CSR_HPMCOUNTER24H 0xc98U +#define CSR_HPMCOUNTER25H 0xc99U +#define CSR_HPMCOUNTER26H 0xc9aU +#define CSR_HPMCOUNTER27H 0xc9bU +#define CSR_HPMCOUNTER28H 0xc9cU +#define CSR_HPMCOUNTER29H 0xc9dU +#define CSR_HPMCOUNTER30H 0xc9eU +#define CSR_HPMCOUNTER31H 0xc9fU +#define CSR_MCYCLEH 0xb80U +#define CSR_MINSTRETH 0xb82U +#define CSR_MHPMCOUNTER3H 0xb83U +#define CSR_MHPMCOUNTER4H 0xb84U +#define CSR_MHPMCOUNTER5H 0xb85U +#define CSR_MHPMCOUNTER6H 0xb86U +#define CSR_MHPMCOUNTER7H 0xb87U +#define CSR_MHPMCOUNTER8H 0xb88U +#define CSR_MHPMCOUNTER9H 0xb89U +#define CSR_MHPMCOUNTER10H 0xb8aU +#define CSR_MHPMCOUNTER11H 0xb8bU +#define CSR_MHPMCOUNTER12H 0xb8cU +#define CSR_MHPMCOUNTER13H 0xb8dU +#define CSR_MHPMCOUNTER14H 0xb8eU +#define CSR_MHPMCOUNTER15H 0xb8fU +#define CSR_MHPMCOUNTER16H 0xb90U +#define CSR_MHPMCOUNTER17H 0xb91U +#define CSR_MHPMCOUNTER18H 0xb92U +#define CSR_MHPMCOUNTER19H 0xb93U +#define CSR_MHPMCOUNTER20H 0xb94U +#define CSR_MHPMCOUNTER21H 0xb95U +#define CSR_MHPMCOUNTER22H 0xb96U +#define CSR_MHPMCOUNTER23H 0xb97U +#define CSR_MHPMCOUNTER24H 0xb98U +#define CSR_MHPMCOUNTER25H 0xb99U +#define CSR_MHPMCOUNTER26H 0xb9aU +#define CSR_MHPMCOUNTER27H 0xb9bU +#define CSR_MHPMCOUNTER28H 0xb9cU +#define CSR_MHPMCOUNTER29H 0xb9dU +#define CSR_MHPMCOUNTER30H 0xb9eU +#define CSR_MHPMCOUNTER31H 0xb9fU +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FAULT_FETCH 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_FAULT_LOAD 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_FAULT_STORE 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#endif +#if defined(DECLARE_INSN) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#if defined(DECLARE_CSR) +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(sbadaddr, CSR_SBADADDR) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(sptbr, CSR_SPTBR) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mbadaddr, CSR_MBADADDR) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) +DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#if defined(DECLARE_CAUSE) +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +#endif + diff --git a/board/k210-emulator/include/entry.h b/board/k210-emulator/include/entry.h new file mode 100644 index 00000000..58f48477 --- /dev/null +++ b/board/k210-emulator/include/entry.h @@ -0,0 +1,90 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 entry.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _BSP_ENTRY_H +#define _BSP_ENTRY_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*core_function)(void *ctx); + +typedef struct _core_instance_t +{ + core_function callback; + void *ctx; +} core_instance_t; + +int register_core1(core_function func, void *ctx); + +static inline void init_lma(void) +{ + extern unsigned int _data_lma; + extern unsigned int _data; + extern unsigned int _edata; + unsigned int *src, *dst; + + src = &_data_lma; + dst = &_data; + while (dst < &_edata) + *dst++ = *src++; +} + +static inline void InitBss(void) +{ + extern unsigned int _bss; + extern unsigned int _ebss; + unsigned int *dst; + + dst = &_bss; + while (dst < &_ebss) + *dst++ = 0; +} + +static inline void init_tls(void) +{ + register void *task_pointer asm("tp"); + extern char _tls_data; + + extern __thread char _tdata_begin, _tdata_end, _tbss_end; + + size_t tdata_size = &_tdata_end - &_tdata_begin; + + memcpy(task_pointer, &_tls_data, tdata_size); + + size_t tbss_size = &_tbss_end - &_tdata_end; + + memset(task_pointer + tdata_size, 0, tbss_size); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_ENTRY_H */ + diff --git a/board/k210-emulator/include/interrupt.h b/board/k210-emulator/include/interrupt.h new file mode 100644 index 00000000..847b5fde --- /dev/null +++ b/board/k210-emulator/include/interrupt.h @@ -0,0 +1,56 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 interrupt.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _BSP_INTERRUPT_H +#define _BSP_INTERRUPT_H + +#ifdef __cplusplus +extern "C" { +#endif +/* clang-format off */ +/* Machine interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_MACHINE_IRQ_MASK (0x1ULL << 63) + +/* Machine interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_MACHINE_IRQ_REASON_MASK (CAUSE_MACHINE_IRQ_MASK - 1) + +/* Hypervisor interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_HYPERVISOR_IRQ_MASK (0x1ULL << 63) + +/* Hypervisor interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_HYPERVISOR_IRQ_REASON_MASK (CAUSE_HYPERVISOR_IRQ_MASK - 1) + +/* Supervisor interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_SUPERVISOR_IRQ_MASK (0x1ULL << 63) + +/* Supervisor interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_SUPERVISOR_IRQ_REASON_MASK (CAUSE_SUPERVISOR_IRQ_MASK - 1) +/* clang-format on */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_INTERRUPT_H */ + diff --git a/board/k210-emulator/include/platform.h b/board/k210-emulator/include/platform.h new file mode 100644 index 00000000..7290cc9f --- /dev/null +++ b/board/k210-emulator/include/platform.h @@ -0,0 +1,108 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 platform.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _BSP_PLATFORM_H +#define _BSP_PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register base address */ + +/* Under Coreplex */ +#define CLINT_BASE_ADDR (0x02000000U) +#define PLIC_BASE_ADDR (0x0C000000U) + +/* Under TileLink */ +#define UARTHS_BASE_ADDR (0x10010000U) +#define GPIOHS_BASE_ADDR (0x38001000U) + +/* Under AXI 64 bit */ +#define RAM_BASE_ADDR (0x80000000U) +#define RAM_SIZE (6 * 1024 * 1024U) + +#define IO_BASE_ADDR (0x40000000U) +#define IO_SIZE (6 * 1024 * 1024U) + +#define AI_RAM_BASE_ADDR (0x80600000U) +#define AI_RAM_SIZE (2 * 1024 * 1024U) + +#define AI_IO_BASE_ADDR (0x40600000U) +#define AI_IO_SIZE (2 * 1024 * 1024U) + +#define AI_BASE_ADDR (0x40800000U) +#define AI_SIZE (12 * 1024 * 1024U) + +#define FFT_BASE_ADDR (0x42000000U) +#define FFT_SIZE (4 * 1024 * 1024U) + +#define ROM_BASE_ADDR (0x88000000U) +#define ROM_SIZE (128 * 1024U) + +/* Under AHB 32 bit */ +#define DMAC_BASE_ADDR (0x50000000U) + +/* Under APB1 32 bit */ +#define GPIO_BASE_ADDR (0x50200000U) +#define UART1_BASE_ADDR (0x50210000U) +#define UART2_BASE_ADDR (0x50220000U) +#define UART3_BASE_ADDR (0x50230000U) +#define SPI_SLAVE_BASE_ADDR (0x50240000U) +#define I2S0_BASE_ADDR (0x50250000U) +#define I2S1_BASE_ADDR (0x50260000U) +#define I2S2_BASE_ADDR (0x50270000U) +#define I2C0_BASE_ADDR (0x50280000U) +#define I2C1_BASE_ADDR (0x50290000U) +#define I2C2_BASE_ADDR (0x502A0000U) +#define FPIOA_BASE_ADDR (0x502B0000U) +#define SHA256_BASE_ADDR (0x502C0000U) +#define TIMER0_BASE_ADDR (0x502D0000U) +#define TIMER1_BASE_ADDR (0x502E0000U) +#define TIMER2_BASE_ADDR (0x502F0000U) + +/* Under APB2 32 bit */ +#define WDT0_BASE_ADDR (0x50400000U) +#define WDT1_BASE_ADDR (0x50410000U) +#define OTP_BASE_ADDR (0x50420000U) +#define DVP_BASE_ADDR (0x50430000U) +#define SYSCTL_BASE_ADDR (0x50440000U) +#define AES_BASE_ADDR (0x50450000U) +#define RTC_BASE_ADDR (0x50460000U) + + +/* Under APB3 32 bit */ +#define SPI0_BASE_ADDR (0x52000000U) +#define SPI1_BASE_ADDR (0x53000000U) +#define SPI3_BASE_ADDR (0x54000000U) + +/* clang-format on */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_PLATFORM_H */ + diff --git a/board/k210-emulator/include/printf.h b/board/k210-emulator/include/printf.h new file mode 100644 index 00000000..c41b3e4e --- /dev/null +++ b/board/k210-emulator/include/printf.h @@ -0,0 +1,218 @@ +/** + * File: printf.h + * + * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Kustaa Nyholm or SpareTimeLabs 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 COPYRIGHT HOLDER 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This library is really just two files: 'tinyprintf.h' and 'tinyprintf.c'. + * + * They provide a simple and small (+400 loc) printf functionality to be used + * in embedded systems. + * + * I've found them so useful in debugging that I do not bother with a debugger + * at all. + * + * They are distributed in source form, so to use them, just compile them into + * your project. + * + * Two printf variants are provided: printf and the 'sprintf' family of + * functions ('snprintf', 'sprintf', 'vsnprintf', 'vsprintf'). + * + * The formats supported by this implementation are: 'c' 'd' 'i' 'o' 'p' 'u' + * 's' 'x' 'X'. + * + * Zero padding, field width, and precision are also supported. + * + * If the library is compiled with 'PRINTF_SUPPORT_LONG' defined, then the + * long specifier is also supported. Note that this will pull in some long + * math routines (pun intended!) and thus make your executable noticeably + * longer. Likewise with 'PRINTF_LONG_LONG_SUPPORT' for the long long + * specifier, and with 'PRINTF_SIZE_T_SUPPORT' for the size_t specifier. + * + * The memory footprint of course depends on the target CPU, compiler and + * compiler options, but a rough guesstimate (based on a H8S target) is about + * 1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack + * space. Not too bad. Your mileage may vary. By hacking the source code you + * can get rid of some hundred bytes, I'm sure, but personally I feel the + * balance of functionality and flexibility versus code size is close to + * optimal for many embedded systems. + * + * To use the printf, you need to supply your own character output function, + * something like : + * + * void putc ( void* p, char c) { while (!SERIAL_PORT_EMPTY) ; + * SERIAL_PORT_TX_REGISTER = c; } + * + * Before you can call printf, you need to initialize it to use your character + * output function with something like: + * + * init_printf(NULL,putc); + * + * Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', + * the NULL (or any pointer) you pass into the 'init_printf' will eventually + * be passed to your 'putc' routine. This allows you to pass some storage + * space (or anything really) to the character output function, if necessary. + * This is not often needed but it was implemented like that because it made + * implementing the sprintf function so neat (look at the source code). + * + * The code is re-entrant, except for the 'init_printf' function, so it is + * safe to call it from interrupts too, although this may result in mixed + * output. If you rely on re-entrancy, take care that your 'putc' function is + * re-entrant! + * + * The printf and sprintf functions are actually macros that translate to + * 'tfp_printf' and 'tfp_sprintf' when 'TINYPRINTF_OVERRIDE_LIBC' is set + * (default). Setting it to 0 makes it possible to use them along with + * 'stdio.h' printf's in a single source file. When 'TINYPRINTF_OVERRIDE_LIBC' + * is set, please note that printf/sprintf are not function-like macros, so if + * you have variables or struct members with these names, things will explode + * in your face. Without variadic macros this is the best we can do to wrap + * these function. If it is a problem, just give up the macros and use the + * functions directly, or rename them. + * + * It is also possible to avoid defining tfp_printf and/or tfp_sprintf by + * clearing 'TINYPRINTF_DEFINE_TFP_PRINTF' and/or + * 'TINYPRINTF_DEFINE_TFP_SPRINTF' to 0. This allows for example to export + * only tfp_format, which is at the core of all the other functions. + * + * For further details see source code. + * + * regs Kusti, 23.10.2004 + */ + +/** +* @file printf.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _BSP_PRINTF_H +#define _BSP_PRINTF_H + +#include +#include + +/* Global configuration */ + +/* Set this to 0 if you do not want to provide tfp_printf */ +#ifndef TINYPRINTF_DEFINE_TFP_PRINTF +#define TINYPRINTF_DEFINE_TFP_PRINTF 1 +#endif + +/** + * Set this to 0 if you do not want to provide + * tfp_sprintf/snprintf/vsprintf/vsnprintf + */ +#ifndef TINYPRINTF_DEFINE_TFP_SPRINTF +#define TINYPRINTF_DEFINE_TFP_SPRINTF 1 +#endif + +/** + * Set this to 0 if you do not want tfp_printf and + * tfp_{vsn,sn,vs,s}printf to be also available as + * printf/{vsn,sn,vs,s}printf + */ +#ifndef TINYPRINTF_OVERRIDE_LIBC +#define TINYPRINTF_OVERRIDE_LIBC 0 +#endif + +/* Optional external types dependencies */ + +/* Declarations */ + +#if defined(__GNUC__) +#define _TFP_SPECIFY_PRINTF_FMT(fmt_idx, arg1_idx) \ + __attribute__((format(printf, fmt_idx, arg1_idx))) +#else +#define _TFP_SPECIFY_PRINTF_FMT(fmt_idx, arg1_idx) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*putcf)(void*, char); + +/** + * 'tfp_format' really is the central function for all tinyprintf. For + * each output character after formatting, the 'putf' callback is + * called with 2 args: + * - an arbitrary void* 'putp' param defined by the user and + * passed unmodified from 'tfp_format', + * - the character. + * The 'tfp_printf' and 'tfp_sprintf' functions simply define their own + * callback and pass to it the right 'putp' it is expecting. + */ +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va); + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap); +int tfp_snprintf(char *str, size_t size, const char *fmt, ...) + _TFP_SPECIFY_PRINTF_FMT(3, 4); +int tfp_vsprintf(char *str, const char *fmt, va_list ap); +int tfp_sprintf(char *str, const char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(2, 3); +#if TINYPRINTF_OVERRIDE_LIBC +#define vsnprintf tfp_vsnprintf +#define snprintf tfp_snprintf +#define vsprintf tfp_vsprintf +#define sprintf tfp_sprintf +#endif +#endif + +#if TINYPRINTF_DEFINE_TFP_PRINTF +void init_printf(void *putp, putcf putf); +void tfp_printf(char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); +#if TINYPRINTF_OVERRIDE_LIBC +#define printf tfp_printf + +#ifdef __cplusplus +#include +namespace std +{ + template + auto tfp_printf(Args&&... args) -> decltype(::tfp_printf(std::forward(args)...)) + { + return ::tfp_printf(std::forward(args)...); + } +} +#endif +#endif +#endif + +int printk(const char *format, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_PRINTF_H */ + diff --git a/board/k210-emulator/include/sleep.h b/board/k210-emulator/include/sleep.h new file mode 100644 index 00000000..a9da6630 --- /dev/null +++ b/board/k210-emulator/include/sleep.h @@ -0,0 +1,45 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 sleep.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _BSP_SLEEP_H +#define _BSP_SLEEP_H + +#include "encoding.h" +#include "clint.h" +#include "syscalls.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int usleep(uint64_t usec); +int msleep(uint64_t msec); +unsigned int sleep(unsigned int seconds); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_SLEEP_H */ + diff --git a/board/k210-emulator/include/syscalls.h b/board/k210-emulator/include/syscalls.h new file mode 100644 index 00000000..1134d515 --- /dev/null +++ b/board/k210-emulator/include/syscalls.h @@ -0,0 +1,54 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 syscalls.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _BSP_SYSCALLS_H +#define _BSP_SYSCALLS_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void __attribute__((noreturn)) sys_exit(int code); + +void setStats(int enable); + +#undef putchar +int putchar(int ch); +void printstr(const char *s); + +void printhex(uint64_t x); + + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_SYSCALLS_H */ + diff --git a/board/k210-emulator/include/syslog.h b/board/k210-emulator/include/syslog.h new file mode 100644 index 00000000..00d25ddf --- /dev/null +++ b/board/k210-emulator/include/syslog.h @@ -0,0 +1,151 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 syslog.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include +#include +#include "printf.h" +#include "encoding.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Logging library + * + * Log library has two ways of managing log verbosity: compile time, set via + * menuconfig + * + * At compile time, filtering is done using CONFIG_LOG_DEFAULT_LEVEL macro, set via + * menuconfig. All logging statments for levels higher than CONFIG_LOG_DEFAULT_LEVEL + * will be removed by the preprocessor. + * + * + * How to use this library: + * + * In each C file which uses logging functionality, define TAG variable like this: + * + * static const char *TAG = "MODULE_NAME"; + * + * then use one of logging macros to produce output, e.g: + * + * LOGW(TAG, "Interrupt error %d", error); + * + * Several macros are available for different verbosity levels: + * + * LOGE - error + * LOGW - warning + * LOGI - info + * LOGD - debug + * LOGV - verbose + * + * To override default verbosity level at file or component scope, define LOG_LEVEL macro. + * At file scope, define it before including esp_log.h, e.g.: + * + * #define LOG_LEVEL LOG_VERBOSE + * #include "dxx_log.h" + * + * At component scope, define it in component makefile: + * + * CFLAGS += -D LOG_LEVEL=LOG_DEBUG + * + * + */ + +/* clang-format off */ +typedef enum _kendryte_log_level +{ + LOG_NONE, /*!< No log output */ + LOG_ERROR, /*!< Critical errors, software module can not recover on its own */ + LOG_WARN, /*!< Error conditions from which recovery measures have been taken */ + LOG_INFO, /*!< Information messages which describe normal flow of events */ + LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ + LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */ +} kendryte_log_level_t ; +/* clang-format on */ + +/* clang-format off */ +#if CONFIG_LOG_COLORS +#define LOG_COLOR_BLACK "30" +#define LOG_COLOR_RED "31" +#define LOG_COLOR_GREEN "32" +#define LOG_COLOR_BROWN "33" +#define LOG_COLOR_BLUE "34" +#define LOG_COLOR_PURPLE "35" +#define LOG_COLOR_CYAN "36" +#define LOG_COLOR(COLOR) "\033[0;" COLOR "m" +#define LOG_BOLD(COLOR) "\033[1;" COLOR "m" +#define LOG_RESET_COLOR "\033[0m" +#define LOG_COLOR_E LOG_COLOR(LOG_COLOR_RED) +#define LOG_COLOR_W LOG_COLOR(LOG_COLOR_BROWN) +#define LOG_COLOR_I LOG_COLOR(LOG_COLOR_GREEN) +#define LOG_COLOR_D +#define LOG_COLOR_V +#else /* CONFIG_LOG_COLORS */ +#define LOG_COLOR_E +#define LOG_COLOR_W +#define LOG_COLOR_I +#define LOG_COLOR_D +#define LOG_COLOR_V +#define LOG_RESET_COLOR +#endif /* CONFIG_LOG_COLORS */ +/* clang-format on */ + +#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%lu) %s: " format LOG_RESET_COLOR "\n" + +#ifdef LOG_LEVEL +#undef CONFIG_LOG_LEVEL +#define CONFIG_LOG_LEVEL LOG_LEVEL +#endif + +#ifdef LOG_KERNEL +#define LOG_PRINTF printk +#else +#define LOG_PRINTF printf +#endif + +#ifdef CONFIG_LOG_ENABLE +#define LOGE(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_ERROR) LOG_PRINTF(LOG_FORMAT(E, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#define LOGW(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_WARN) LOG_PRINTF(LOG_FORMAT(W, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#define LOGI(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_INFO) LOG_PRINTF(LOG_FORMAT(I, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#define LOGD(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_DEBUG) LOG_PRINTF(LOG_FORMAT(D, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#define LOGV(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_VERBOSE) LOG_PRINTF(LOG_FORMAT(V, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#else +#define LOGE(tag, format, ...) +#define LOGW(tag, format, ...) +#define LOGI(tag, format, ...) +#define LOGD(tag, format, ...) +#define LOGV(tag, format, ...) +#endif /* LOG_ENABLE */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _SYSLOG_H */ + diff --git a/board/k210-emulator/include/util.h b/board/k210-emulator/include/util.h new file mode 100644 index 00000000..fb766b27 --- /dev/null +++ b/board/k210-emulator/include/util.h @@ -0,0 +1,207 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 util.h +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef _BSP_UTIL_H +#define _BSP_UTIL_H + + +#include +#if defined(__riscv) +#include "encoding.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +/** + * -------------------------------------------------------------------------- + * Macros + + * Set HOST_DEBUG to 1 if you are going to compile this for a host + * machine (ie Athena/Linux) for debug purposes and set HOST_DEBUG + * to 0 if you are compiling with the smips-gcc toolchain. + */ + +#ifndef HOST_DEBUG +#define HOST_DEBUG 0 +#endif + +/** + * Set PREALLOCATE to 1 if you want to preallocate the benchmark + * function before starting stats. If you have instruction/data + * caches and you don't want to count the overhead of misses, then + * you will need to use preallocation. +*/ + +#ifndef PREALLOCATE +#define PREALLOCATE 0 +#endif + + +#define static_assert(cond) \ + { \ + switch (0) \ + { \ + case 0: \ + case !!(long)(cond):; \ + } \ + } + +#define stringify_1(s) #s +#define stringify(s) stringify_1(s) +#define stats(code, iter) \ + do \ + { \ + unsigned long _c = -read_cycle(), _i = -READ_CSR(minstret); \ + code; \ + _c += read_cycle(), _i += READ_CSR(minstret); \ + if (cid == 0) \ + printf("\r\n%s: %ld cycles, %ld.%ld cycles/iter, %ld.%ld CPI\r\n", \ + stringify(code), _c, _c / iter, 10 * _c / iter % 10, _c / _i, 10 * _c / _i % 10); \ + } while (0) + + +/** + * Set SET_STATS to 1 if you want to carve out the piece that actually + * does the computation. + */ + +#if HOST_DEBUG +#include +static void setStats(int enable) {} +#else +extern void setStats(int enable); +#endif + + +static void printArray(const char name[], int n, const int arr[]) +{ +#if HOST_DEBUG + int i; + + printf(" %10s :", name); + for (i = 0; i < n; i++) + printf(" %3d ", arr[i]); + printf("\r\n"); +#endif +} + +static void printDoubleArray(const char name[], int n, const double arr[]) +{ +#if HOST_DEBUG + int i; + + printf(" %10s :", name); + for (i = 0; i < n; i++) + printf(" %g ", arr[i]); + printf("\r\n"); +#endif +} + +static int verify(int n, const volatile int *test, const int *verify) +{ + int i; + /* Unrolled for faster verification */ + for (i = 0; i < n / 2 * 2; i += 2) + { + int t0 = test[i], t1 = test[i + 1]; + int v0 = verify[i], v1 = verify[i + 1]; + + if (t0 != v0) + return i + 1; + if (t1 != v1) + return i + 2; + } + if (n % 2 != 0 && test[n - 1] != verify[n - 1]) + return n; + return 0; +} + +static int verifyDouble(int n, const volatile double *test, const double *verify) +{ + int i; + /* Unrolled for faster verification */ + for (i = 0; i < n / 2 * 2; i += 2) + { + double t0 = test[i], t1 = test[i + 1]; + double v0 = verify[i], v1 = verify[i + 1]; + int eq1 = t0 == v0, eq2 = t1 == v1; + + if (!(eq1 & eq2)) + return i + 1 + eq1; + } + if (n % 2 != 0 && test[n - 1] != verify[n - 1]) + return n; + return 0; +} + +static void __attribute__((noinline)) barrier(int ncores) +{ + static volatile int sense = 0; + static volatile int count = 0; + + static __thread int threadsense; + + __sync_synchronize(); + + threadsense = !threadsense; + if (__sync_fetch_and_add(&count, 1) == ncores - 1) + { + count = 0; + sense = threadsense; + } + else + { + while (sense != threadsense) + ; + } + + __sync_synchronize(); +} + +static uint64_t lfsr(uint64_t x) +{ + uint64_t bit = (x ^ (x >> 1)) & 1; + + return (x >> 1) | (bit << 62); +} + + +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Wunused-parameter" +#pragma GCC diagnostic warning "-Wunused-function" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_UTIL_H */ + diff --git a/board/k210-emulator/link.lds b/board/k210-emulator/link.lds new file mode 100644 index 00000000..f4c2764b --- /dev/null +++ b/board/k210-emulator/link.lds @@ -0,0 +1,118 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +__STACKSIZE__ = 4096; +OUTPUT_ARCH( "riscv" ) +MEMORY +{ + sram (wxa!ri): ORIGIN = 0x80000000, LENGTH = ( 6 * 1024 * 1024 ) +} + +ENTRY(_begin) +SECTIONS +{ + .start : + { + *(.start); + } > sram + + . = ALIGN(8); + + .text : + { + PROVIDE( _text = ABSOLUTE(.) ); + + *(.text .text.*) /* Normal code */ + *(.rodata .rodata*) /* read-only data (constants) */ + + /* section information for shell */ + . = ALIGN(8); + _shell_command_start = .; + KEEP (*(shellCommand)) + _shell_command_end = .; + . = ALIGN(8); + + PROVIDE(__ctors_start__ = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE(__ctors_end__ = .); + + . = ALIGN(4); + + __isrtbl_idx_start = .; + KEEP(*(.isrtbl.idx)) + __isrtbl_start = .; + KEEP(*(.isrtbl)) + __isrtbl_end = .; + . = ALIGN(8); + + PROVIDE(g_service_table_start = ABSOLUTE(.)); + KEEP(*(.g_service_table)) + PROVIDE(g_service_table_end = ABSOLUTE(.)); + + PROVIDE( _etext = ABSOLUTE(.) ); + } > sram + + . = ALIGN(8); + + .data : + { + PROVIDE( _sdata = ABSOLUTE(.) ); + + /* Writable data segment */ + *(.data .data.*) + + . = ALIGN(8); + PROVIDE( __global_pointer$ = ABSOLUTE(.) + 0x800 ); + + /* Writable small data segment (.sdata segment) */ + *(.sdata .sdata.*) + + PROVIDE( _edata = ABSOLUTE(.) ); + } > sram + + .bss : + { + __bss_start = ABSOLUTE(.); + + /* Writable uninitialized small data segment (.sbss segment)*/ + *(.sbss .sbss.*) + *(.scommon) + + /* Uninitialized writeable data section (.bss segment)*/ + *(.bss .bss.*) + *(COMMON) + + . = ALIGN(8); + __bss_end = ABSOLUTE(.); + } > sram + + .stack : + { + . = ALIGN(64); + PROVIDE(__stack_start__ = ABSOLUTE(.)); + + /* cpu0 stack top site */ + . = . + __STACKSIZE__; + __stack_tp0 = . ; + + /* cpu1 stack top site */ + . = . + __STACKSIZE__; + __stack_tp1 = . ; + + PROVIDE( __stack_end__ = ABSOLUTE(.) ); + } > sram + _end = ABSOLUTE(.); + + /* Stabs debugging sections. */ + +} diff --git a/board/k210-emulator/link_userspace.lds b/board/k210-emulator/link_userspace.lds new file mode 100644 index 00000000..53360021 --- /dev/null +++ b/board/k210-emulator/link_userspace.lds @@ -0,0 +1,70 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +OUTPUT_ARCH("riscv") +MEMORY +{ + usram (rw) : ORIGIN = 0x80101000, LENGTH = ( 5 * 1024 * 1024 - 4 * 1024 ) /* 5M -4k usram */ +} + +SECTIONS +{ + .userspace : + { + . = ALIGN(8); + KEEP(*(.userspace)) + } > usram + + .text : + { + _ustext = ABSOLUTE(.); + *(.text .text.*) + *(.rodata .rodata*) + *(.glue_7) + *(.glue_7t) + PROVIDE(_uetext = ABSOLUTE(.)); + } > usram + + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > usram + + __uexidx_start = ABSOLUTE(.); + + .ARM.exidx : + { + PROVIDE(__uexidx_start = ABSOLUTE(.)); + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + PROVIDE(__uexidx_end = ABSOLUTE(.)); + } > usram + + _ueronly = ABSOLUTE(.); + + .data : AT(_ueronly) + { + _usdata = ABSOLUTE(.); + *(.data .data.*) + . = ALIGN(8); + _uedata = ABSOLUTE(.); + } > usram + + .bss : { + . = ALIGN(8); + _usbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.sbss .sbss.*) + . = ALIGN(8); + _uebss = ABSOLUTE(.); + } > usram +} \ No newline at end of file diff --git a/board/k210-emulator/third_party_driver/Kconfig b/board/k210-emulator/third_party_driver/Kconfig new file mode 100755 index 00000000..00d8bdb1 --- /dev/null +++ b/board/k210-emulator/third_party_driver/Kconfig @@ -0,0 +1,45 @@ +menuconfig BSP_USING_DMA +bool "Using DMA device" +default y +if BSP_USING_DMA +source "$BSP_DIR/third_party_driver/dma/Kconfig" +endif + +menuconfig BSP_USING_GPIO +bool "Using GPIO device" +default y +select RESOURCES_PIN +if BSP_USING_GPIO +source "$BSP_DIR/third_party_driver/gpio/Kconfig" +endif + +menuconfig BSP_USING_PLIC +bool "Using PLIC device" +default y +if BSP_USING_PLIC +source "$BSP_DIR/third_party_driver/plic/Kconfig" +endif + +menuconfig BSP_USING_SYSCLOCK +bool "Using SYSCLOCK device" +default y +if BSP_USING_SYSCLOCK +source "$BSP_DIR/third_party_driver/sys_clock/Kconfig" +endif + +menuconfig BSP_USING_HWTIMER +bool "Using HWTIMER device" +default n +select RESOURCES_HWTIMER +if BSP_USING_HWTIMER +source "$BSP_DIR/third_party_driver/timer/Kconfig" +endif + +menuconfig BSP_USING_UART +bool "Using UART device" +default y +select RESOURCES_SERIAL +if BSP_USING_UART +source "$BSP_DIR/third_party_driver/uart/Kconfig" +endif + diff --git a/board/k210-emulator/third_party_driver/Makefile b/board/k210-emulator/third_party_driver/Makefile new file mode 100644 index 00000000..51543687 --- /dev/null +++ b/board/k210-emulator/third_party_driver/Makefile @@ -0,0 +1,35 @@ +SRC_FILES := sleep.c + +ifeq ($(CONFIG_BSP_USING_DMA),y) + SRC_DIR += dma +endif + +ifeq ($(CONFIG_BSP_USING_GPIO),y) + SRC_DIR += gpio +endif + +ifeq ($(CONFIG_BSP_USING_PLIC),y) + SRC_DIR += plic +endif + + + +ifeq ($(CONFIG_BSP_USING_SECURITY),y) + SRC_DIR += security +endif + + +ifeq ($(CONFIG_BSP_USING_SYSCLOCK),y) + SRC_DIR += sys_clock +endif + +ifeq ($(CONFIG_BSP_USING_HWTIMER),y) + SRC_DIR += timer +endif + +ifeq ($(CONFIG_BSP_USING_UART),y) + SRC_DIR += uart +endif + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/dma/Kconfig b/board/k210-emulator/third_party_driver/dma/Kconfig new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/board/k210-emulator/third_party_driver/dma/Kconfig @@ -0,0 +1 @@ + diff --git a/board/k210-emulator/third_party_driver/dma/Makefile b/board/k210-emulator/third_party_driver/dma/Makefile new file mode 100644 index 00000000..2929b905 --- /dev/null +++ b/board/k210-emulator/third_party_driver/dma/Makefile @@ -0,0 +1,6 @@ +SRC_FILES := dmac.c + + + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/dma/dmac.c b/board/k210-emulator/third_party_driver/dma/dmac.c new file mode 100644 index 00000000..b1903238 --- /dev/null +++ b/board/k210-emulator/third_party_driver/dma/dmac.c @@ -0,0 +1,802 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 dmac.c +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include "dmac.h" +#include "sysctl.h" +#include "fpioa.h" +#include "utils.h" +#include "plic.h" +#include "stdlib.h" + +volatile dmac_t *const dmac = (dmac_t *)DMAC_BASE_ADDR; + +typedef struct _dmac_context +{ + dmac_channel_number_t dmac_channel; + plic_irq_callback_t callback; + void *ctx; +} dmac_context_t; + +dmac_context_t dmac_context[6]; + +static int is_memory(uintptr_t address) +{ + enum { + mem_len = 6 * 1024 * 1024, + mem_no_cache_len = 8 * 1024 * 1024, + }; + return ((address >= 0x80000000) && (address < 0x80000000 + mem_len)) || ((address >= 0x40000000) && (address < 0x40000000 + mem_no_cache_len)) || (address == 0x50450040); +} + +uint64_t dmac_read_id(void) +{ + return dmac->id; +} + +uint64_t dmac_read_version(void) +{ + return dmac->compver; +} + +uint64_t dmac_read_channel_id(dmac_channel_number_t channel_num) +{ + return dmac->channel[channel_num].axi_id; +} + +static void dmac_enable(void) +{ + dmac_cfg_u_t dmac_cfg; + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 1; + dmac_cfg.cfg.int_en = 1; + writeq(dmac_cfg.data, &dmac->cfg); +} + +void dmac_disable(void) +{ + dmac_cfg_u_t dmac_cfg; + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 0; + dmac_cfg.cfg.int_en = 0; + writeq(dmac_cfg.data, &dmac->cfg); +} + +void src_transaction_complete_int_enable(dmac_channel_number_t channel_num) +{ + dmac_ch_intstatus_enable_u_t ch_intstat; + + ch_intstat.data = readq(&dmac->channel[channel_num].intstatus_en); + ch_intstat.ch_intstatus_enable.enable_src_transcomp_intstat = 1; + + writeq(ch_intstat.data, &dmac->channel[channel_num].intstatus_en); +} + +void dmac_channel_enable(dmac_channel_number_t channel_num) +{ + dmac_chen_u_t chen; + + chen.data = readq(&dmac->chen); + + switch (channel_num) { + case DMAC_CHANNEL0: + chen.dmac_chen.ch1_en = 1; + chen.dmac_chen.ch1_en_we = 1; + break; + case DMAC_CHANNEL1: + chen.dmac_chen.ch2_en = 1; + chen.dmac_chen.ch2_en_we = 1; + break; + case DMAC_CHANNEL2: + chen.dmac_chen.ch3_en = 1; + chen.dmac_chen.ch3_en_we = 1; + break; + case DMAC_CHANNEL3: + chen.dmac_chen.ch4_en = 1; + chen.dmac_chen.ch4_en_we = 1; + break; + case DMAC_CHANNEL4: + chen.dmac_chen.ch5_en = 1; + chen.dmac_chen.ch5_en_we = 1; + break; + case DMAC_CHANNEL5: + chen.dmac_chen.ch6_en = 1; + chen.dmac_chen.ch6_en_we = 1; + break; + default: + break; + } + + writeq(chen.data, &dmac->chen); +} + +void dmac_channel_disable(dmac_channel_number_t channel_num) +{ + dmac_chen_u_t chen; + + chen.data = readq(&dmac->chen); + + switch (channel_num) + { + case DMAC_CHANNEL0: + chen.dmac_chen.ch1_en = 0; + chen.dmac_chen.ch1_en_we = 1; + break; + case DMAC_CHANNEL1: + chen.dmac_chen.ch2_en = 0; + chen.dmac_chen.ch2_en_we = 1; + break; + case DMAC_CHANNEL2: + chen.dmac_chen.ch3_en = 0; + chen.dmac_chen.ch3_en_we = 1; + break; + case DMAC_CHANNEL3: + chen.dmac_chen.ch4_en = 0; + chen.dmac_chen.ch4_en_we = 1; + break; + case DMAC_CHANNEL4: + chen.dmac_chen.ch5_en = 0; + chen.dmac_chen.ch5_en_we = 1; + break; + case DMAC_CHANNEL5: + chen.dmac_chen.ch6_en = 0; + chen.dmac_chen.ch6_en_we = 1; + break; + default: + break; + } + + writeq(chen.data, &dmac->chen); +} + +int32_t dmac_check_channel_busy(dmac_channel_number_t channel_num) +{ + int32_t ret = 0; + dmac_chen_u_t chen_u; + + chen_u.data = readq(&dmac->chen); + switch (channel_num) { + case DMAC_CHANNEL0: + if (chen_u.dmac_chen.ch1_en == 1) + ret = 1; + break; + case DMAC_CHANNEL1: + if (chen_u.dmac_chen.ch2_en == 1) + ret = 1; + break; + case DMAC_CHANNEL2: + if (chen_u.dmac_chen.ch3_en == 1) + ret = 1; + break; + case DMAC_CHANNEL3: + if (chen_u.dmac_chen.ch4_en == 1) + ret = 1; + break; + case DMAC_CHANNEL4: + if (chen_u.dmac_chen.ch5_en == 1) + ret = 1; + break; + case DMAC_CHANNEL5: + if (chen_u.dmac_chen.ch6_en == 1) + ret = 1; + break; + default: + break; + } + + writeq(chen_u.data, &dmac->chen); + + return ret; +} + +int32_t dmac_set_list_master_select(dmac_channel_number_t channel_num, + dmac_src_dst_select_t sd_sel, dmac_master_number_t mst_num) +{ + int32_t ret = 0; + uint64_t tmp = 0; + dmac_ch_ctl_u_t ctl; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ret = dmac_check_channel_busy(channel_num); + if (ret == 0) { + if (sd_sel == DMAC_SRC || sd_sel == DMAC_SRC_DST) + ctl.ch_ctl.sms = mst_num; + + if (sd_sel == DMAC_DST || sd_sel == DMAC_SRC_DST) + ctl.ch_ctl.dms = mst_num; + tmp |= *(uint64_t *)&dmac->channel[channel_num].ctl; + writeq(ctl.data, &dmac->channel[channel_num].ctl); + } + + return ret; +} + +void dmac_enable_common_interrupt_status(void) +{ + dmac_commonreg_intstatus_enable_u_t intstatus; + + intstatus.data = readq(&dmac->com_intstatus_en); + intstatus.intstatus_enable.enable_slvif_dec_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_wr2ro_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_rd2wo_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_wronhold_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_undefinedreg_dec_err_intstat = 1; + + writeq(intstatus.data, &dmac->com_intstatus_en); +} + +void dmac_enable_common_interrupt_signal(void) +{ + dmac_commonreg_intsignal_enable_u_t intsignal; + + intsignal.data = readq(&dmac->com_intsignal_en); + intsignal.intsignal_enable.enable_slvif_dec_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_wr2ro_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_rd2wo_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_wronhold_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_undefinedreg_dec_err_intsignal = 1; + + writeq(intsignal.data, &dmac->com_intsignal_en); +} + +static void dmac_enable_channel_interrupt(dmac_channel_number_t channel_num) +{ + writeq(0xffffffff, &dmac->channel[channel_num].intclear); + writeq(0x2, &dmac->channel[channel_num].intstatus_en); +} + +void dmac_disable_channel_interrupt(dmac_channel_number_t channel_num) +{ + writeq(0, &dmac->channel[channel_num].intstatus_en); +} + +static void dmac_chanel_interrupt_clear(dmac_channel_number_t channel_num) +{ + writeq(0xffffffff, &dmac->channel[channel_num].intclear); +} + +int dmac_set_channel_config(dmac_channel_number_t channel_num, + dmac_channel_config_t *cfg_param) +{ + dmac_ch_ctl_u_t ctl; + dmac_ch_cfg_u_t cfg; + dmac_ch_llp_u_t ch_llp; + + if (cfg_param->ctl_sms > DMAC_MASTER2) + return -1; + if (cfg_param->ctl_dms > DMAC_MASTER2) + return -1; + if (cfg_param->ctl_src_msize > DMAC_MSIZE_256) + return -1; + if (cfg_param->ctl_drc_msize > DMAC_MSIZE_256) + return -1; + + /** + * cfg register must configure before ts_block and + * sar dar register + */ + cfg.data = readq(&dmac->channel[channel_num].cfg); + + cfg.ch_cfg.hs_sel_src = cfg_param->cfg_hs_sel_src; + cfg.ch_cfg.hs_sel_dst = cfg_param->cfg_hs_sel_dst; + cfg.ch_cfg.src_hwhs_pol = cfg_param->cfg_src_hs_pol; + cfg.ch_cfg.dst_hwhs_pol = cfg_param->cfg_dst_hs_pol; + cfg.ch_cfg.src_per = cfg_param->cfg_src_per; + cfg.ch_cfg.dst_per = cfg_param->cfg_dst_per; + cfg.ch_cfg.ch_prior = cfg_param->cfg_ch_prior; + cfg.ch_cfg.tt_fc = cfg_param->ctl_tt_fc; + + cfg.ch_cfg.src_multblk_type = cfg_param->cfg_src_multblk_type; + cfg.ch_cfg.dst_multblk_type = cfg_param->cfg_dst_multblk_type; + + writeq(cfg.data, &dmac->channel[channel_num].cfg); + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = cfg_param->ctl_sms; + ctl.ch_ctl.dms = cfg_param->ctl_dms; + /* master select */ + ctl.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl.ch_ctl.dinc = cfg_param->ctl_dinc; + /* address incrememt */ + ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + /* transfer width */ + ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + /* Burst transaction length */ + ctl.ch_ctl.ioc_blktfr = cfg_param->ctl_ioc_blktfr; + /* interrupt on completion of block transfer */ + /* 0x1 enable BLOCK_TFR_DONE_IntStat field */ + + writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts); + /* the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */ + /* transferred in a dma block transfer */ + + dmac->channel[channel_num].sar = cfg_param->sar; + dmac->channel[channel_num].dar = cfg_param->dar; + + ch_llp.data = readq(&dmac->channel[channel_num].llp); + ch_llp.llp.loc = cfg_param->llp_loc; + ch_llp.llp.lms = cfg_param->llp_lms; + writeq(ch_llp.data, &dmac->channel[channel_num].llp); + writeq(ctl.data, &dmac->channel[channel_num].ctl); + readq(&dmac->channel[channel_num].swhssrc); + + return 0; +} + +int dmac_set_channel_param(dmac_channel_number_t channel_num, + const void *src, void *dest, dmac_address_increment_t src_inc, dmac_address_increment_t dest_inc, + dmac_burst_trans_length_t dmac_burst_size, + dmac_transfer_width_t dmac_trans_width, + uint32_t blockSize) +{ + dmac_ch_ctl_u_t ctl; + dmac_ch_cfg_u_t cfg_u; + + int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest); + dmac_transfer_flow_t flow_control; + if (mem_type_src == 0 && mem_type_dest == 0) + { + flow_control = DMAC_PRF2PRF_DMA; + }else if (mem_type_src == 1 && mem_type_dest == 0) + flow_control = DMAC_MEM2PRF_DMA; + else if (mem_type_src == 0 && mem_type_dest == 1) + flow_control = DMAC_PRF2MEM_DMA; + else + flow_control = DMAC_MEM2MEM_DMA; + + /** + * cfg register must configure before ts_block and + * sar dar register + */ + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + + cfg_u.ch_cfg.tt_fc = flow_control; + cfg_u.ch_cfg.hs_sel_src = mem_type_src ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE; + cfg_u.ch_cfg.hs_sel_dst = mem_type_dest ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE; + cfg_u.ch_cfg.src_per = channel_num; + cfg_u.ch_cfg.dst_per = channel_num; + cfg_u.ch_cfg.src_multblk_type = 0; + cfg_u.ch_cfg.dst_multblk_type = 0; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); + + dmac->channel[channel_num].sar = (uint64_t)src; + dmac->channel[channel_num].dar = (uint64_t)dest; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = DMAC_MASTER1; + ctl.ch_ctl.dms = DMAC_MASTER2; + /* master select */ + ctl.ch_ctl.sinc = src_inc; + ctl.ch_ctl.dinc = dest_inc; + /* address incrememt */ + ctl.ch_ctl.src_tr_width = dmac_trans_width; + ctl.ch_ctl.dst_tr_width = dmac_trans_width; + /* transfer width */ + ctl.ch_ctl.src_msize = dmac_burst_size; + ctl.ch_ctl.dst_msize = dmac_burst_size; + + writeq(ctl.data, &dmac->channel[channel_num].ctl); + + writeq(blockSize - 1, &dmac->channel[channel_num].block_ts); + /*the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */ + /* transferred in a dma block transfer */ + return 0; +} + +int dmac_get_channel_config(dmac_channel_number_t channel_num, + dmac_channel_config_t *cfg_param) +{ + dmac_ch_ctl_u_t ctl; + dmac_ch_cfg_u_t cfg; + dmac_ch_llp_u_t ch_llp; + + if (cfg_param == 0) + return -1; + if (channel_num < DMAC_CHANNEL0 || + channel_num > DMAC_CHANNEL3) + return -1; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + + cfg_param->ctl_sms = ctl.ch_ctl.sms; + cfg_param->ctl_dms = ctl.ch_ctl.dms; + cfg_param->ctl_sinc = ctl.ch_ctl.sinc; + cfg_param->ctl_dinc = ctl.ch_ctl.dinc; + cfg_param->ctl_src_tr_width = ctl.ch_ctl.src_tr_width; + cfg_param->ctl_dst_tr_width = ctl.ch_ctl.dst_tr_width; + cfg_param->ctl_src_msize = ctl.ch_ctl.src_msize; + cfg_param->ctl_drc_msize = ctl.ch_ctl.dst_msize; + cfg_param->ctl_ioc_blktfr = ctl.ch_ctl.ioc_blktfr; + + cfg.data = readq(&dmac->channel[channel_num].cfg); + cfg_param->cfg_hs_sel_src = cfg.ch_cfg.hs_sel_src; + cfg_param->cfg_hs_sel_dst = cfg.ch_cfg.hs_sel_dst; + cfg_param->cfg_src_hs_pol = cfg.ch_cfg.src_hwhs_pol; + cfg_param->cfg_dst_hs_pol = cfg.ch_cfg.dst_hwhs_pol; + cfg_param->cfg_src_per = cfg.ch_cfg.src_per; + cfg_param->cfg_dst_per = cfg.ch_cfg.dst_per; + cfg_param->cfg_ch_prior = cfg.ch_cfg.ch_prior; + cfg_param->cfg_src_multblk_type = cfg.ch_cfg.src_multblk_type; + cfg_param->cfg_dst_multblk_type = cfg.ch_cfg.dst_multblk_type; + + cfg_param->sar = dmac->channel[channel_num].sar; + cfg_param->dar = dmac->channel[channel_num].dar; + + ch_llp.data = readq(&dmac->channel[channel_num].llp); + cfg_param->llp_loc = ch_llp.llp.loc; + cfg_param->llp_lms = ch_llp.llp.lms; + + cfg_param->ctl_block_ts = readq(&dmac->channel[channel_num].block_ts); + + return 0; +} + +void dmac_set_address(dmac_channel_number_t channel_num, uint64_t src_addr, + uint64_t dst_addr) +{ + writeq(src_addr, &dmac->channel[channel_num].sar); + writeq(dst_addr, &dmac->channel[channel_num].dar); +} + +void dmac_set_block_ts(dmac_channel_number_t channel_num, + uint32_t BlockSize) +{ + uint32_t block_ts; + + block_ts = BlockSize & 0x3fffff; + writeq(block_ts, &dmac->channel[channel_num].block_ts); +} + +void dmac_source_control(dmac_channel_number_t channel_num, + dmac_master_number_t master_select, + dmac_address_increment_t address_mode, + dmac_transfer_width_t tr_width, + dmac_burst_trans_length_t burst_length) +{ + dmac_ch_ctl_u_t ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.sms = master_select; + ctl_u.ch_ctl.sinc = address_mode; + ctl_u.ch_ctl.src_tr_width = tr_width; + ctl_u.ch_ctl.src_msize = burst_length; + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_master_control(dmac_channel_number_t channel_num, + dmac_master_number_t master_select, + dmac_address_increment_t address_mode, + dmac_transfer_width_t tr_width, + dmac_burst_trans_length_t burst_length) +{ + dmac_ch_ctl_u_t ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.dms = master_select; + ctl_u.ch_ctl.dinc = address_mode; + ctl_u.ch_ctl.dst_tr_width = tr_width; + ctl_u.ch_ctl.dst_msize = burst_length; + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_set_source_transfer_control(dmac_channel_number_t channel_num, + dmac_multiblk_transfer_type_t transfer_type, + dmac_sw_hw_hs_select_t handshak_select) +{ + dmac_ch_cfg_u_t cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.src_multblk_type = transfer_type; + cfg_u.ch_cfg.hs_sel_src = handshak_select; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_destination_transfer_control(dmac_channel_number_t channel_num, + dmac_multiblk_transfer_type_t transfer_type, + dmac_sw_hw_hs_select_t handshak_select) +{ + dmac_ch_cfg_u_t cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.dst_multblk_type = transfer_type; + cfg_u.ch_cfg.hs_sel_dst = handshak_select; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_flow_control(dmac_channel_number_t channel_num, + dmac_transfer_flow_t flow_control) +{ + dmac_ch_cfg_u_t cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.tt_fc = flow_control; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_linked_list_addr_point(dmac_channel_number_t channel_num, + uint64_t *addr) +{ + dmac_ch_llp_u_t llp_u; + + llp_u.data = readq(&dmac->channel[channel_num].llp); + /* Cast pointer to uint64_t */ + llp_u.llp.loc = (uint64_t)addr; + writeq(llp_u.data, &dmac->channel[channel_num].llp); +} + +void DmacInit(void) +{ + uint64_t tmp; + dmac_commonreg_intclear_u_t intclear; + dmac_cfg_u_t dmac_cfg; + dmac_reset_u_t dmac_reset; + + sysctl_clock_enable(SYSCTL_CLOCK_DMA); + + dmac_reset.data = readq(&dmac->reset); + dmac_reset.reset.rst = 1; + writeq(dmac_reset.data, &dmac->reset); + while (dmac_reset.reset.rst) + dmac_reset.data = readq(&dmac->reset); + + /*reset dmac */ + + intclear.data = readq(&dmac->com_intclear); + intclear.com_intclear.cear_slvif_dec_err_intstat = 1; + intclear.com_intclear.clear_slvif_wr2ro_err_intstat = 1; + intclear.com_intclear.clear_slvif_rd2wo_err_intstat = 1; + intclear.com_intclear.clear_slvif_wronhold_err_intstat = 1; + intclear.com_intclear.clear_slvif_undefinedreg_dec_err_intstat = 1; + writeq(intclear.data, &dmac->com_intclear); + /* clear common register interrupt */ + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 0; + dmac_cfg.cfg.int_en = 0; + writeq(dmac_cfg.data, &dmac->cfg); + /* disable dmac and disable interrupt */ + + while (readq(&dmac->cfg)) + ; + tmp = readq(&dmac->chen); + tmp &= ~0xf; + writeq(tmp, &dmac->chen); + /* disable all channel before configure */ + dmac_enable(); +} + +static void list_add(struct list_head_t *new, struct list_head_t *prev, + struct list_head_t *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +void list_add_tail(struct list_head_t *new, struct list_head_t *head) +{ + list_add(new, head->prev, head); +} + +void INIT_LIST_HEAD(struct list_head_t *list) +{ + list->next = list; + list->prev = list; +} + +void dmac_link_list_item(dmac_channel_number_t channel_num, + uint8_t LLI_row_num, int8_t LLI_last_row, + dmac_lli_item_t *lli_item, + dmac_channel_config_t *cfg_param) +{ + dmac_ch_ctl_u_t ctl; + dmac_ch_llp_u_t llp_u; + + lli_item[LLI_row_num].sar = cfg_param->sar; + lli_item[LLI_row_num].dar = cfg_param->dar; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = cfg_param->ctl_sms; + ctl.ch_ctl.dms = cfg_param->ctl_dms; + ctl.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl.ch_ctl.dinc = cfg_param->ctl_dinc; + ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + ctl.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en; + ctl.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en; + + if (LLI_last_row != LAST_ROW) { + ctl.ch_ctl.shadowreg_or_lli_valid = 1; + ctl.ch_ctl.shadowreg_or_lli_last = 0; + } else { + ctl.ch_ctl.shadowreg_or_lli_valid = 1; + ctl.ch_ctl.shadowreg_or_lli_last = 1; + } + + lli_item[LLI_row_num].ctl = ctl.data; + + lli_item[LLI_row_num].ch_block_ts = cfg_param->ctl_block_ts; + lli_item[LLI_row_num].sstat = 0; + lli_item[LLI_row_num].dstat = 0; + + llp_u.data = readq(&dmac->channel[channel_num].llp); + + if (LLI_last_row != LAST_ROW) + llp_u.llp.loc = ((uint64_t)&lli_item[LLI_row_num + 1]) >> 6; + else + llp_u.llp.loc = 0; + + lli_item[LLI_row_num].llp = llp_u.data; +} + +void dmac_update_shandow_register(dmac_channel_number_t channel_num, + int8_t last_block, dmac_channel_config_t *cfg_param) +{ + dmac_ch_ctl_u_t ctl_u; + + do { + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + } while (ctl_u.ch_ctl.shadowreg_or_lli_valid); + + writeq(cfg_param->sar, &dmac->channel[channel_num].sar); + writeq(cfg_param->dar, &dmac->channel[channel_num].dar); + writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts); + + ctl_u.ch_ctl.sms = cfg_param->ctl_sms; + ctl_u.ch_ctl.dms = cfg_param->ctl_dms; + ctl_u.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl_u.ch_ctl.dinc = cfg_param->ctl_dinc; + ctl_u.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl_u.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + ctl_u.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl_u.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + ctl_u.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en; + ctl_u.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en; + if (last_block != LAST_ROW) + { + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 0; + } else { + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 1; + } + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); + writeq(0, &dmac->channel[channel_num].blk_tfr); +} + +void dmac_set_shadow_invalid_flag(dmac_channel_number_t channel_num) +{ + dmac_ch_ctl_u_t ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 0; + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_set_single_mode(dmac_channel_number_t channel_num, + const void *src, void *dest, dmac_address_increment_t src_inc, + dmac_address_increment_t dest_inc, + dmac_burst_trans_length_t dmac_burst_size, + dmac_transfer_width_t dmac_trans_width, + size_t BlockSize) { + dmac_chanel_interrupt_clear(channel_num); + dmac_channel_disable(channel_num); + dmac_wait_idle(channel_num); + dmac_set_channel_param(channel_num, src, dest, src_inc, dest_inc, + dmac_burst_size, dmac_trans_width, BlockSize); + dmac_enable(); + dmac_channel_enable(channel_num); +} + +int dmac_is_done(dmac_channel_number_t channel_num) +{ + if(readq(&dmac->channel[channel_num].intstatus) & 0x2) + return 1; + else + return 0; +} + +void dmac_wait_done(dmac_channel_number_t channel_num) +{ + dmac_wait_idle(channel_num); +} + +int dmac_is_idle(dmac_channel_number_t channel_num) +{ + dmac_chen_u_t chen; + chen.data = readq(&dmac->chen); + if((chen.data >> channel_num) & 0x1UL) + return 0; + else + return 1; +} + +void dmac_wait_idle(dmac_channel_number_t channel_num) +{ + while(!dmac_is_idle(channel_num)); + dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */ +} + +void dmac_set_src_dest_length(dmac_channel_number_t channel_num, const void *src, void *dest, size_t len) +{ + if(src != NULL) + dmac->channel[channel_num].sar = (uint64_t)src; + if(dest != NULL) + dmac->channel[channel_num].dar = (uint64_t)dest; + if(len > 0) + dmac_set_block_ts(channel_num, len - 1); + dmac_channel_enable(channel_num); +} + +static int dmac_irq_callback(void *ctx) +{ + dmac_context_t *v_dmac_context = (dmac_context_t *)(ctx); + dmac_channel_number_t v_dmac_channel = v_dmac_context->dmac_channel; + dmac_chanel_interrupt_clear(v_dmac_channel); + if(v_dmac_context->callback != NULL) + v_dmac_context->callback(v_dmac_context->ctx); + + return 0; +} + +void dmac_irq_register(dmac_channel_number_t channel_num , plic_irq_callback_t dmac_callback, void *ctx, uint32_t priority) +{ + dmac_context[channel_num].dmac_channel = channel_num; + dmac_context[channel_num].callback = dmac_callback; + dmac_context[channel_num].ctx = ctx; + dmac_enable_channel_interrupt(channel_num); + plic_set_priority(IRQN_DMA0_INTERRUPT + channel_num, priority); + plic_irq_enable(IRQN_DMA0_INTERRUPT + channel_num); + plic_irq_register(IRQN_DMA0_INTERRUPT + channel_num, dmac_irq_callback, &dmac_context[channel_num]); +} + +void __attribute__((weak, alias("dmac_irq_register"))) dmac_set_irq(dmac_channel_number_t channel_num , plic_irq_callback_t dmac_callback, void *ctx, uint32_t priority); + +void dmac_irq_unregister(dmac_channel_number_t channel_num) +{ + dmac_context[channel_num].callback = NULL; + dmac_context[channel_num].ctx = NULL; + dmac_disable_channel_interrupt(channel_num); + plic_irq_unregister(IRQN_DMA0_INTERRUPT + channel_num); +} + +void __attribute__((weak, alias("dmac_irq_unregister"))) dmac_free_irq(dmac_channel_number_t channel_num); + diff --git a/board/k210-emulator/third_party_driver/gpio/Kconfig b/board/k210-emulator/third_party_driver/gpio/Kconfig new file mode 100644 index 00000000..35dce739 --- /dev/null +++ b/board/k210-emulator/third_party_driver/gpio/Kconfig @@ -0,0 +1,11 @@ +config PIN_BUS_NAME + string "pin bus name" + default "pin" + +config PIN_DRIVER_NAME + string "pin driver name" + default "pin_drv" + +config PIN_DEVICE_NAME + string "pin device name" + default "pin_dev" diff --git a/board/k210-emulator/third_party_driver/gpio/Makefile b/board/k210-emulator/third_party_driver/gpio/Makefile new file mode 100644 index 00000000..e017f079 --- /dev/null +++ b/board/k210-emulator/third_party_driver/gpio/Makefile @@ -0,0 +1,8 @@ +SRC_FILES := connect_gpio.c drv_io_config.c fpioa.c gpio.c gpiohs.c utils.c + + + + + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/gpio/connect_gpio.c b/board/k210-emulator/third_party_driver/gpio/connect_gpio.c new file mode 100644 index 00000000..23fd3222 --- /dev/null +++ b/board/k210-emulator/third_party_driver/gpio/connect_gpio.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-03-19 ZYH first version + */ + +/** +* @file connect_gpio.c +* @brief support gpio function using bus driver framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: connect_gpio.c +Description: support gpio configure and register to bus framework +Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_gpio.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: add bus driver framework support for gpio +*************************************************/ + +#include +#include +#include +#include +#include "drv_io_config.h" +#include +#include +#include "connect_gpio.h" + +#define FUNC_GPIOHS(n) (FUNC_GPIOHS0 + n) + +static int pin_alloc_table[FPIOA_NUM_IO]; +static uint32_t free_pin = 0; + +static int AllocPinChannel(x_base pin_index) +{ + if (free_pin == 31) { + SYS_ERR("no free gpiohs channel to alloc"); + return -1; + } + + if (pin_alloc_table[pin_index] != -1) { + SYS_WARN("already alloc gpiohs channel for pin %d", pin_index); + return pin_alloc_table[pin_index]; + } + + pin_alloc_table[pin_index] = free_pin; + free_pin++; + + FpioaSetFunction(pin_index, FUNC_GPIOHS(pin_alloc_table[pin_index])); + return pin_alloc_table[pin_index]; +} + +static int GetPinChannel(x_base pin_index) +{ + return pin_alloc_table[pin_index]; +} + +static uint32 GpioConfigMode(int mode, uint8_t pin_channel) +{ + switch (mode) + { + case GPIO_CFG_OUTPUT: + gpiohs_set_drive_mode(pin_channel, GPIO_DM_OUTPUT); + break; + case GPIO_CFG_INPUT: + gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT); + break; + case GPIO_CFG_INPUT_PULLUP: + gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT_PULL_UP); + break; + case GPIO_CFG_INPUT_PULLDOWN: + gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT_PULL_DOWN); + break; + case GPIO_CFG_OUTPUT_OD: + break; + default: + break; + } + return EOK; + +} + +static struct +{ + void (*hdr)(void *args); + void *args; + GpioPinEdgeT edge; +} IrqTable[32]; + +static void pin_irq(int vector, void *param) +{ + int pin_channel = vector - IRQN_GPIOHS0_INTERRUPT; + if (IrqTable[pin_channel].edge & GPIO_PE_FALLING) { + set_gpio_bit(gpiohs->fall_ie.u32, pin_channel, 0); + set_gpio_bit(gpiohs->fall_ip.u32, pin_channel, 1); + set_gpio_bit(gpiohs->fall_ie.u32, pin_channel, 1); + } + + if (IrqTable[pin_channel].edge & GPIO_PE_RISING) { + set_gpio_bit(gpiohs->rise_ie.u32, pin_channel, 0); + set_gpio_bit(gpiohs->rise_ip.u32, pin_channel, 1); + set_gpio_bit(gpiohs->rise_ie.u32, pin_channel, 1); + } + + if (IrqTable[pin_channel].edge & GPIO_PE_LOW) { + set_gpio_bit(gpiohs->low_ie.u32, pin_channel, 0); + set_gpio_bit(gpiohs->low_ip.u32, pin_channel, 1); + set_gpio_bit(gpiohs->low_ie.u32, pin_channel, 1); + } + + if (IrqTable[pin_channel].edge & GPIO_PE_HIGH) { + set_gpio_bit(gpiohs->high_ie.u32, pin_channel, 0); + set_gpio_bit(gpiohs->high_ip.u32, pin_channel, 1); + set_gpio_bit(gpiohs->high_ie.u32, pin_channel, 1); + } + + if (IrqTable[pin_channel].hdr) { + IrqTable[pin_channel].hdr(IrqTable[pin_channel].args); + } +} + +static uint32 GpioIrqRegister(int32 pin_channel, int32 mode, void (*hdr)(void *args), void *args) +{ + IrqTable[pin_channel].hdr = hdr; + IrqTable[pin_channel].args = args; + switch (mode) + { + case GPIO_IRQ_EDGE_RISING: + IrqTable[pin_channel].edge = GPIO_PE_RISING; + break; + case GPIO_IRQ_EDGE_FALLING: + IrqTable[pin_channel].edge = GPIO_PE_FALLING; + break; + case GPIO_IRQ_EDGE_BOTH: + IrqTable[pin_channel].edge = GPIO_PE_BOTH; + break; + case GPIO_IRQ_LEVEL_HIGH: + IrqTable[pin_channel].edge = GPIO_PE_LOW; + break; + case GPIO_IRQ_LEVEL_LOW: + IrqTable[pin_channel].edge = GPIO_PE_HIGH; + break; + default: + break; + } + gpiohs_set_pin_edge(pin_channel, IrqTable[pin_channel].edge); + + isrManager.done->registerIrq(IRQN_GPIOHS0_INTERRUPT + pin_channel, pin_irq, NONE); + + return EOK; +} + +static uint32 GpioIrqFree(int32 pin_channel) +{ + IrqTable[pin_channel].hdr = NONE; + IrqTable[pin_channel].args = NONE; + return EOK; +} + +static uint32 GpioIrqEnable(int32 pin_channel) +{ + isrManager.done->enableIrq(IRQN_GPIOHS0_INTERRUPT + pin_channel); + + return EOK; +} + +static uint32 GpioIrqDisable(int32 pin_channel) +{ + isrManager.done->disableIrq(IRQN_GPIOHS0_INTERRUPT + pin_channel); + return EOK; +} + +static uint32 PinConfigure(struct PinParam *param) +{ + NULL_PARAM_CHECK(param); + int ret = EOK; + + int pin_channel = GetPinChannel(param->pin); + if (pin_channel == -1) { + pin_channel = AllocPinChannel(param->pin); + if (pin_channel == -1) { + return ERROR; + } + } + + switch (param->cmd) + { + case GPIO_CONFIG_MODE: + GpioConfigMode(param->mode, pin_channel); + break; + case GPIO_IRQ_REGISTER: + ret = GpioIrqRegister(pin_channel,param->irq_set.irq_mode,param->irq_set.hdr,param->irq_set.args); + break; + case GPIO_IRQ_FREE: + ret = GpioIrqFree(pin_channel); + break; + case GPIO_IRQ_ENABLE: + ret = GpioIrqEnable(pin_channel); + break; + case GPIO_IRQ_DISABLE: + ret = GpioIrqDisable(pin_channel); + break; + default: + ret = -EINVALED; + break; + } + + return ret; +} + +static uint32 GpioDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + struct PinParam *param; + + switch (configure_info->configure_cmd) + { + case OPE_CFG: + param = (struct PinParam *)configure_info->private_data; + ret = PinConfigure(param); + break; + default: + break; + } + + return ret; +} + +uint32 PinWrite(void *dev, struct BusBlockWriteParam *write_param) +{ + NULL_PARAM_CHECK(dev); + NULL_PARAM_CHECK(write_param); + struct PinStat *pinstat = (struct PinStat *)write_param->buffer; + + int pin_channel = GetPinChannel(pinstat->pin); + if (pin_channel == -1) { + SYS_ERR("pin %d not set mode", pinstat->pin); + return ERROR; + } + gpiohs_set_pin(pin_channel, pinstat->val == GPIO_HIGH ? GPIO_PV_HIGH : GPIO_PV_LOW); +} + +uint32 PinRead(void *dev, struct BusBlockReadParam *read_param) +{ + NULL_PARAM_CHECK(dev); + NULL_PARAM_CHECK(read_param); + struct PinStat *pinstat = (struct PinStat *)read_param->buffer; + + int pin_channel = GetPinChannel(pinstat->pin); + if (pin_channel == -1) { + SYS_ERR("pin %d not set mode", pinstat->pin); + return ERROR; + } + + if (gpiohs_get_pin(pin_channel) == GPIO_PV_HIGH){ + pinstat->val = GPIO_HIGH; + return GPIO_HIGH; + } else { + pinstat->val = GPIO_LOW; + return GPIO_LOW; + } +} + +static const struct PinDevDone dev_done = +{ + .open = NONE, + .close = NONE, + .write = PinWrite, + .read = PinRead, +}; + +int HwGpioInit(void) +{ + x_err_t ret = EOK; + + static struct PinBus pin; + + memset(pin_alloc_table, -1, sizeof pin_alloc_table); + free_pin = GPIO_ALLOC_START; + + ret = PinBusInit(&pin, PIN_BUS_NAME); + if (ret != EOK) { + KPrintf("gpio bus init error %d\n", ret); + return ERROR; + } + + static struct PinDriver drv; + drv.configure = &GpioDrvConfigure; + + ret = PinDriverInit(&drv, PIN_DRIVER_NAME, NONE); + if (ret != EOK) { + KPrintf("pin driver init error %d\n", ret); + return ERROR; + } + + ret = PinDriverAttachToBus(PIN_DRIVER_NAME, PIN_BUS_NAME); + if (ret != EOK) { + KPrintf("pin driver attach error %d\n", ret); + return ERROR; + } + + static struct PinHardwareDevice dev; + dev.dev_done = &dev_done; + + ret = PinDeviceRegister(&dev, NONE, PIN_DEVICE_NAME); + if (ret != EOK) { + KPrintf("pin device register error %d\n", ret); + return ERROR; + } + + ret = PinDeviceAttachToBus(PIN_DEVICE_NAME, PIN_BUS_NAME); + if (ret != EOK) { + KPrintf("pin device register error %d\n", ret); + return ERROR; + } + + return ret; +} \ No newline at end of file diff --git a/board/k210-emulator/third_party_driver/gpio/drv_io_config.c b/board/k210-emulator/third_party_driver/gpio/drv_io_config.c new file mode 100644 index 00000000..f1b55e18 --- /dev/null +++ b/board/k210-emulator/third_party_driver/gpio/drv_io_config.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-03-19 ZYH first version + */ + +/** +* @file drv_io_config.c +* @brief support kd233-board io configure +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: drv_io_config.c +Description: support kd233-board io configure +Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_io_config.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: support kd233-board io configure +*************************************************/ + +#include +#include +#include "drv_io_config.h" +#include + + +//#define LED_TEST + +#define HS_GPIO(n) (FUNC_GPIOHS0 + n) + +#define IOCONFIG(pin,func) {pin, func, #func} + +static struct io_config +{ + int io_num; + fpioa_function_t func; + const char * FuncName; +} io_config[] = +{ +#ifdef BSP_USING_LCD + IOCONFIG(BSP_LCD_CS_PIN, FUNC_SPI0_SS0), + IOCONFIG(BSP_LCD_WR_PIN, FUNC_SPI0_SCLK), + IOCONFIG(BSP_LCD_DC_PIN, HS_GPIO(LCD_DC_PIN)), +#endif + +#ifdef BSP_USING_CAMERA + IOCONFIG(BSP_CAMERA_SCCB_SDA_PIN, FUNC_SCCB_SDA), + IOCONFIG(BSP_CAMERA_SCCB_SCLK_PIN, FUNC_SCCB_SCLK), + IOCONFIG(BSP_CAMERA_CMOS_RST_PIN, FUNC_CMOS_RST), + IOCONFIG(BSP_CAMERA_CMOS_VSYNC_PIN, FUNC_CMOS_VSYNC), + IOCONFIG(BSP_CAMERA_CMOS_PWDN_PIN, FUNC_CMOS_PWDN), + IOCONFIG(BSP_CAMERA_CMOS_XCLK_PIN, FUNC_CMOS_XCLK), + IOCONFIG(BSP_CAMERA_CMOS_PCLK_PIN, FUNC_CMOS_PCLK), + IOCONFIG(BSP_CAMERA_CMOS_HREF_PIN, FUNC_CMOS_HREF), +#endif + +#ifdef BSP_USING_SPI1 + IOCONFIG(BSP_SPI1_CLK_PIN, FUNC_SPI1_SCLK), + IOCONFIG(BSP_SPI1_D0_PIN, FUNC_SPI1_D0), + IOCONFIG(BSP_SPI1_D1_PIN, FUNC_SPI1_D1), +#ifdef BSP_USING_SPI1_AS_QSPI + IOCONFIG(BSP_SPI1_D2_PIN, FUNC_SPI1_D2), + IOCONFIG(BSP_SPI1_D3_PIN, FUNC_SPI1_D3), +#endif +#ifdef BSP_SPI1_USING_SS0 + IOCONFIG(BSP_SPI1_SS0_PIN, HS_GPIO(SPI1_CS0_PIN)), +#endif +#ifdef BSP_SPI1_USING_SS1 + IOCONFIG(BSP_SPI1_SS1_PIN, HS_GPIO(SPI1_CS1_PIN)), +#endif +#ifdef BSP_SPI1_USING_SS2 + IOCONFIG(BSP_SPI1_SS2_PIN, HS_GPIO(SPI1_CS2_PIN)), +#endif +#ifdef BSP_SPI1_USING_SS3 + IOCONFIG(BSP_SPI1_SS3_PIN, HS_GPIO(SPI1_CS3_PIN)), +#endif +#endif + +#ifdef BSP_USING_UART1 + IOCONFIG(BSP_UART1_TXD_PIN, FUNC_UART1_TX), + IOCONFIG(BSP_UART1_RXD_PIN, FUNC_UART1_RX), +#endif +#ifdef BSP_USING_UART2 + IOCONFIG(BSP_UART2_TXD_PIN, FUNC_UART2_TX), + IOCONFIG(BSP_UART2_RXD_PIN, FUNC_UART2_RX), +#endif +#ifdef BSP_USING_UART3 + IOCONFIG(BSP_UART3_TXD_PIN, FUNC_UART3_TX), + IOCONFIG(BSP_UART3_RXD_PIN, FUNC_UART3_RX), +#endif + +// #ifdef LED_TEST +// IOCONFIG(LED0, FUNC_GPIOHS0), +// #endif + IOCONFIG(18, FUNC_GPIOHS18), + IOCONFIG(19, FUNC_GPIOHS19), +}; + +static int PrintIoConfig() +{ + int i; + KPrintf("IO Configuration Table\n"); + KPrintf("┌───────┬────────────────────────┐\n"); + KPrintf("│Pin │Function │\n"); + KPrintf("├───────┼────────────────────────┤\n"); + for(i = 0; i < sizeof io_config / sizeof io_config[0]; i++) + { + KPrintf("│%-2d │%-24.24s│\n", io_config[i].io_num, io_config[i].FuncName); + } + KPrintf("└───────┴────────────────────────┘\n"); + return 0; +} + + + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0), + io,PrintIoConfig,print io config); + + +int IoConfigInit(void) +{ + int count = sizeof(io_config) / sizeof(io_config[0]); + int i; + int ret = 0; + + sysctl_set_power_mode(SYSCTL_POWER_BANK0, SYSCTL_POWER_V18); + sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V18); + sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V18); +#ifdef BSP_USING_UART2 + // for IO-27/28 + sysctl_set_power_mode(SYSCTL_POWER_BANK4, SYSCTL_POWER_V33); +#endif +#if defined(BSP_USING_UART1) || defined(BSP_USING_UART3) + // for IO-20~23 + sysctl_set_power_mode(SYSCTL_POWER_BANK3, SYSCTL_POWER_V33); +#endif + + for(i = 0; i < count; i++) + { + ret = FpioaSetFunction(io_config[i].io_num, io_config[i].func); + if(ret != 0) + return ret; + } + +#if defined(BSP_USING_CAMERA) || defined(BSP_USING_LCD) + sysctl_set_spi0_dvp_data(1); +#endif + + return ret; +} + diff --git a/board/k210-emulator/third_party_driver/gpio/fpioa.c b/board/k210-emulator/third_party_driver/gpio/fpioa.c new file mode 100644 index 00000000..eff2d6ac --- /dev/null +++ b/board/k210-emulator/third_party_driver/gpio/fpioa.c @@ -0,0 +1,5439 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 fpioa.c +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include "sysctl.h" +#include "fpioa.h" + +volatile fpioa_t *const fpioa = (volatile fpioa_t *)FPIOA_BASE_ADDR; + +/** + * @brief Internal used FPIOA function initialize cell + * + * This is NOT fpioa_io_config_t, can't assign directly + * + */ +typedef struct _fpioa_assign_t +{ + uint32_t ch_sel : 8; + /* Channel select from 256 input. */ + uint32_t ds : 4; + /* Driving selector. */ + uint32_t oe_en : 1; + /* Static output enable, will AND with OE_INV. */ + uint32_t oe_inv : 1; + /* Invert output enable. */ + uint32_t do_sel : 1; + /* Data output select: 0 for DO, 1 for OE. */ + uint32_t do_inv : 1; + /* Invert the result of data output select (DO_SEL). */ + uint32_t pu : 1; + /* Pull up enable. 0 for nothing, 1 for pull up. */ + uint32_t pd : 1; + /* Pull down enable. 0 for nothing, 1 for pull down. */ + uint32_t resv0 : 1; + /* Reserved bits. */ + uint32_t sl : 1; + /* Slew rate control enable. */ + uint32_t ie_en : 1; + /* Static input enable, will AND with IE_INV. */ + uint32_t ie_inv : 1; + /* Invert input enable. */ + uint32_t di_inv : 1; + /* Invert Data input. */ + uint32_t st : 1; + /* Schmitt trigger. */ + uint32_t tie_en : 1; + /* Input tie enable, 1 for enable, 0 for disable. */ + uint32_t tie_val : 1; + /* Input tie value, 1 for high, 0 for low. */ + uint32_t resv1 : 5; + /* Reserved bits. */ + uint32_t pad_di : 1; + /* Read current PAD's data input. */ +} __attribute__((packed, aligned(4))) fpioa_assign_t; + +/* Function list */ +static const fpioa_assign_t function_config[FUNC_MAX] = +{ + { + .ch_sel = FUNC_JTAG_TCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TDI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TMS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TDO, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_ARB, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 1, + .tie_val = 1, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UARTHS_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UARTHS_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV6, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV7, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_SPI1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_I2C1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS9, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS10, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS11, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS12, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS13, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS15, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS16, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS17, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS18, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS19, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS20, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS21, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS22, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS23, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS24, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS25, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS26, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS27, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS28, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS29, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS30, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS31, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_ARB, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 1, + .tie_val = 1, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_SS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_SCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV4, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV5, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C0_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C0_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C1_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C1_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C2_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C2_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_XCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_RST, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_PWDN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_VSYNC, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_HREF, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_PCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D4, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D5, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D6, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D7, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SCCB_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SCCB_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_SPI2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_I2C2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL9, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL10, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL11, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL12, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL13, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL15, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL16, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL17, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CONSTANT, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL18, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG9, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG10, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG11, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG12, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG13, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG15, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG16, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG17, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG18, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG19, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG20, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG21, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG22, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG23, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG24, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG25, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG26, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG27, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG28, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG29, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG30, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG31, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, +}; + +int FpioaInit(void) +{ + int i = 0; + + /* Enable fpioa clock in system controller */ + sysctl_clock_enable(SYSCTL_CLOCK_FPIOA); + + /* Initialize tie */ + fpioa_tie_t tie = { 0 }; + + /* Set tie enable and tie value */ + for (i = 0; i < FUNC_MAX; i++) + { + tie.en[i / 32] |= (function_config[i].tie_en << (i % 32)); + tie.val[i / 32] |= (function_config[i].tie_val << (i % 32)); + } + + /* Atomic write every 32bit register to fpioa function */ + for (i = 0; i < FUNC_MAX / 32; i++) + { + /* Set value before enable */ + fpioa->tie.val[i] = tie.val[i]; + fpioa->tie.en[i] = tie.en[i]; + } + + return 0; +} + +int fpioa_get_io(int number, fpioa_io_config_t *cfg) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || cfg == NULL) + return -1; + /* Atomic read register */ + *cfg = fpioa->io[number]; + return 0; +} + +int fpioa_set_io(int number, fpioa_io_config_t *cfg) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || cfg == NULL) + return -1; + /* Atomic write register */ + fpioa->io[number] = *cfg; + return 0; +} + +int fpioa_set_io_pull(int number, fpioa_pull_t pull) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || pull >= FPIOA_PULL_MAX) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + + switch (pull) + { + case FPIOA_PULL_NONE: + cfg.pu = 0; + cfg.pd = 0; + break; + case FPIOA_PULL_DOWN: + cfg.pu = 0; + cfg.pd = 1; + break; + case FPIOA_PULL_UP: + cfg.pu = 1; + cfg.pd = 0; + break; + default: + break; + } + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_get_io_pull(int number) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO) + return -1; + + fpioa_pull_t pull; + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + + if (cfg.pu == 0 && cfg.pd == 1) + pull = FPIOA_PULL_DOWN; + else if (cfg.pu == 1 && cfg.pd == 0) + pull = FPIOA_PULL_UP; + else + pull = FPIOA_PULL_NONE; + return pull; +} + +int fpioa_set_io_driving(int number, fpioa_driving_t driving) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || driving >= FPIOA_DRIVING_MAX) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO driving */ + cfg.ds = driving; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_set_sl(int number, uint8_t sl_enable) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO slew rate */ + cfg.sl = sl_enable; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_set_st(int number, uint8_t st_enable) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO schmitt trigger */ + cfg.st = st_enable; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + + +int fpioa_get_io_driving(int number) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO) + return -1; + + return fpioa->io[number].ds; +} + +int fpioa_set_function_raw(int number, fpioa_function_t function) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX) + return -1; + /* Atomic write register */ + fpioa->io[number] =(const fpioa_io_config_t) + { + .ch_sel = function_config[function].ch_sel, + .ds = function_config[function].ds, + .oe_en = function_config[function].oe_en, + .oe_inv = function_config[function].oe_inv, + .do_sel = function_config[function].do_sel, + .do_inv = function_config[function].do_inv, + .pu = function_config[function].pu, + .pd = function_config[function].pd, + .sl = function_config[function].sl, + .ie_en = function_config[function].ie_en, + .ie_inv = function_config[function].ie_inv, + .di_inv = function_config[function].di_inv, + .st = function_config[function].st, + /* resv and pad_di do not need initialization */ + }; + return 0; +} + +int FpioaSetFunction(int number, fpioa_function_t function) +{ + uint8_t index = 0; + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX) + return -1; + if (function == FUNC_RESV0) + { + fpioa_set_function_raw(number, FUNC_RESV0); + return 0; + } + /* Compare all IO */ + for (index = 0; index < FPIOA_NUM_IO; index++) + { + if ((fpioa->io[index].ch_sel == function) && (index != number)) + fpioa_set_function_raw(index, FUNC_RESV0); + } + fpioa_set_function_raw(number, function); + return 0; +} + +int fpioa_set_tie_enable(fpioa_function_t function, int enable) +{ + /* Check parameters */ + if (function < 0 || function >= FUNC_MAX) + return -1; + /* Set tie enable */ + if (enable) + fpioa->tie.en[function / 32] |= (1UL << (function % 32)); + else + fpioa->tie.en[function / 32] &= (~(1UL << (function % 32))); + return 0; +} + +int fpioa_set_tie_value(fpioa_function_t function, int value) +{ + /* Check parameters */ + if (function < 0 || function >= FUNC_MAX) + return -1; + /* Set tie value */ + if (value) + fpioa->tie.val[function / 32] |= (1UL << (function % 32)); + else + fpioa->tie.val[function / 32] &= (~(1UL << (function % 32))); + return 0; +} + +int fpioa_get_io_by_function(fpioa_function_t function) +{ + int index = 0; + for (index = 0; index < FPIOA_NUM_IO; index++) + { + if (fpioa->io[index].ch_sel == function) + return index; + } + + return -1; +} diff --git a/board/k210-emulator/third_party_driver/gpio/gpio.c b/board/k210-emulator/third_party_driver/gpio/gpio.c new file mode 100644 index 00000000..1a775249 --- /dev/null +++ b/board/k210-emulator/third_party_driver/gpio/gpio.c @@ -0,0 +1,89 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 gpio.c +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include "gpio.h" +#include "utils.h" +#include "fpioa.h" +#include "sysctl.h" +#define GPIO_MAX_PINNO 8 + +volatile gpio_t* const gpio = (volatile gpio_t*)GPIO_BASE_ADDR; + +int gpio_init(void) +{ + return sysctl_clock_enable(SYSCTL_CLOCK_GPIO); +} + +void gpio_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode) +{ + configASSERT(pin < GPIO_MAX_PINNO); + int io_number = fpioa_get_io_by_function(FUNC_GPIO0 + pin); + configASSERT(io_number >= 0); + + fpioa_pull_t pull; + uint32_t dir; + + switch (mode) + { + case GPIO_DM_INPUT: + pull = FPIOA_PULL_NONE; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_DOWN: + pull = FPIOA_PULL_DOWN; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_UP: + pull = FPIOA_PULL_UP; + dir = 0; + break; + case GPIO_DM_OUTPUT: + pull = FPIOA_PULL_DOWN; + dir = 1; + break; + default: + configASSERT(!"GPIO drive mode is not supported.") break; + } + + fpioa_set_io_pull(io_number, pull); + set_gpio_bit(gpio->direction.u32, pin, dir); +} + +gpio_pin_value_t gpio_get_pin(uint8_t pin) +{ + configASSERT(pin < GPIO_MAX_PINNO); + uint32_t dir = get_gpio_bit(gpio->direction.u32, pin); + volatile uint32_t *reg = dir ? gpio->data_output.u32 : gpio->data_input.u32; + return get_gpio_bit(reg, pin); +} + +void gpio_set_pin(uint8_t pin, gpio_pin_value_t value) +{ + configASSERT(pin < GPIO_MAX_PINNO); + uint32_t dir = get_gpio_bit(gpio->direction.u32, pin); + volatile uint32_t *reg = dir ? gpio->data_output.u32 : gpio->data_input.u32; + configASSERT(dir == 1); + set_gpio_bit(reg, pin, value); +} + diff --git a/board/k210-emulator/third_party_driver/gpio/gpiohs.c b/board/k210-emulator/third_party_driver/gpio/gpiohs.c new file mode 100644 index 00000000..27f4b219 --- /dev/null +++ b/board/k210-emulator/third_party_driver/gpio/gpiohs.c @@ -0,0 +1,228 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 gpiohs.c +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include "gpiohs.h" +#include "utils.h" +#include "fpioa.h" +#include "sysctl.h" +#define GPIOHS_MAX_PINNO 32 + +volatile gpiohs_t* const gpiohs = (volatile gpiohs_t*)GPIOHS_BASE_ADDR; + +typedef struct _gpiohs_pin_instance +{ + size_t pin; + GpioPinEdgeT edge; + void (*callback)(); + plic_irq_callback_t gpiohs_callback; + void *context; +} gpiohs_pin_instance_t; + +static gpiohs_pin_instance_t pin_instance[32]; + +void gpiohs_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + int io_number = fpioa_get_io_by_function(FUNC_GPIOHS0 + pin); + configASSERT(io_number >= 0); + + fpioa_pull_t pull; + uint32_t dir; + + switch (mode) + { + case GPIO_DM_INPUT: + pull = FPIOA_PULL_NONE; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_DOWN: + pull = FPIOA_PULL_DOWN; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_UP: + pull = FPIOA_PULL_UP; + dir = 0; + break; + case GPIO_DM_OUTPUT: + pull = FPIOA_PULL_DOWN; + dir = 1; + break; + default: + configASSERT(!"GPIO drive mode is not supported.") break; + } + + fpioa_set_io_pull(io_number, pull); + volatile uint32_t *reg = dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32; + volatile uint32_t *reg_d = !dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32; + set_gpio_bit(reg_d, pin, 0); + set_gpio_bit(reg, pin, 1); +} + +gpio_pin_value_t gpiohs_get_pin(uint8_t pin) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + return get_gpio_bit(gpiohs->input_val.u32, pin); +} + +void gpiohs_set_pin(uint8_t pin, gpio_pin_value_t value) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + set_gpio_bit(gpiohs->output_val.u32, pin, value); +} + +void gpiohs_set_pin_edge(uint8_t pin, GpioPinEdgeT edge) +{ + set_gpio_bit(gpiohs->rise_ie.u32, pin, 0); + set_gpio_bit(gpiohs->rise_ip.u32, pin, 1); + + set_gpio_bit(gpiohs->fall_ie.u32, pin, 0); + set_gpio_bit(gpiohs->fall_ip.u32, pin, 1); + + set_gpio_bit(gpiohs->low_ie.u32, pin, 0); + set_gpio_bit(gpiohs->low_ip.u32, pin, 1); + + set_gpio_bit(gpiohs->high_ie.u32, pin, 0); + set_gpio_bit(gpiohs->high_ip.u32, pin, 1); + + if(edge & GPIO_PE_FALLING) + { + set_gpio_bit(gpiohs->fall_ie.u32, pin, 1); + } + else + { + set_gpio_bit(gpiohs->fall_ie.u32, pin, 0); + } + + if(edge & GPIO_PE_RISING) + { + set_gpio_bit(gpiohs->rise_ie.u32, pin, 1); + } + else + { + set_gpio_bit(gpiohs->rise_ie.u32, pin, 0); + } + + if(edge & GPIO_PE_LOW) + { + set_gpio_bit(gpiohs->low_ie.u32, pin, 1); + } + else + { + set_gpio_bit(gpiohs->low_ie.u32, pin, 0); + } + + if(edge & GPIO_PE_HIGH) + { + set_gpio_bit(gpiohs->high_ie.u32, pin, 1); + } + else + { + set_gpio_bit(gpiohs->high_ie.u32, pin, 0); + } + + pin_instance[pin].edge = edge; +} + +int gpiohs_pin_onchange_isr(void *userdata) +{ + gpiohs_pin_instance_t *ctx = (gpiohs_pin_instance_t *)userdata; + size_t pin = ctx->pin; + + if(ctx->edge & GPIO_PE_FALLING) + { + set_gpio_bit(gpiohs->fall_ie.u32, pin, 0); + set_gpio_bit(gpiohs->fall_ip.u32, pin, 1); + set_gpio_bit(gpiohs->fall_ie.u32, pin, 1); + } + + if(ctx->edge & GPIO_PE_RISING) + { + set_gpio_bit(gpiohs->rise_ie.u32, pin, 0); + set_gpio_bit(gpiohs->rise_ip.u32, pin, 1); + set_gpio_bit(gpiohs->rise_ie.u32, pin, 1); + } + + if(ctx->edge & GPIO_PE_LOW) + { + set_gpio_bit(gpiohs->low_ie.u32, pin, 0); + set_gpio_bit(gpiohs->low_ip.u32, pin, 1); + set_gpio_bit(gpiohs->low_ie.u32, pin, 1); + } + + if(ctx->edge & GPIO_PE_HIGH) + { + set_gpio_bit(gpiohs->high_ie.u32, pin, 0); + set_gpio_bit(gpiohs->high_ip.u32, pin, 1); + set_gpio_bit(gpiohs->high_ie.u32, pin, 1); + } + + if (ctx->callback) + ctx->callback(); + if(ctx->gpiohs_callback) + ctx->gpiohs_callback(ctx->context); + + return 0; +} + +void gpiohs_set_irq(uint8_t pin, uint32_t priority, void (*func)()) +{ + + pin_instance[pin].pin = pin; + pin_instance[pin].callback = func; + + plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority); + plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_instance[pin])); + plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin); +} + +void gpiohs_irq_register(uint8_t pin, uint32_t priority, plic_irq_callback_t callback, void *ctx) +{ + pin_instance[pin].pin = pin; + pin_instance[pin].gpiohs_callback = callback; + pin_instance[pin].context = ctx; + + plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority); + plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_instance[pin])); + plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin); +} + +void gpiohs_irq_unregister(uint8_t pin) +{ + pin_instance[pin] = (gpiohs_pin_instance_t){ + .callback = NULL, + .gpiohs_callback = NULL, + .context = NULL, + }; + set_gpio_bit(gpiohs->rise_ie.u32, pin, 0); + set_gpio_bit(gpiohs->fall_ie.u32, pin, 0); + set_gpio_bit(gpiohs->low_ie.u32, pin, 0); + set_gpio_bit(gpiohs->high_ie.u32, pin, 0); + plic_irq_unregister(IRQN_GPIOHS0_INTERRUPT + pin); +} + +void gpiohs_irq_disable(size_t pin) +{ + plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + pin); +} + diff --git a/board/k210-emulator/third_party_driver/gpio/utils.c b/board/k210-emulator/third_party_driver/gpio/utils.c new file mode 100644 index 00000000..ad504666 --- /dev/null +++ b/board/k210-emulator/third_party_driver/gpio/utils.c @@ -0,0 +1,54 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 utils.c +* @brief add from Canaan K210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include "encoding.h" +#include "utils.h" + +void set_bit(volatile uint32_t *bits, uint32_t mask, uint32_t value) +{ + uint32_t org = (*bits) & ~mask; + *bits = org | (value & mask); +} + +void set_bit_offset(volatile uint32_t *bits, uint32_t mask, size_t offset, uint32_t value) +{ + set_bit(bits, mask << offset, value << offset); +} + +void set_gpio_bit(volatile uint32_t *bits, size_t offset, uint32_t value) +{ + set_bit_offset(bits, 1, offset, value); +} + +uint32_t get_bit(volatile uint32_t *bits, uint32_t mask, size_t offset) +{ + return ((*bits) & (mask << offset)) >> offset; +} + +uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset) +{ + return get_bit(bits, 1, offset); +} + diff --git a/board/k210-emulator/third_party_driver/i2c/Kconfig b/board/k210-emulator/third_party_driver/i2c/Kconfig new file mode 100644 index 00000000..c9353696 --- /dev/null +++ b/board/k210-emulator/third_party_driver/i2c/Kconfig @@ -0,0 +1,17 @@ +if BSP_USING_I2C + config BSP_I2C_SDA + int "SDA pin number for I2C" + default 15 + config BSP_I2C_SCL + int "SCLK pin number for I2C" + default 17 + config I2C_BUS_NAME_1 + string "i2c bus 1 name" + default "i2c1" + config I2C_DRV_NAME_1 + string "i2c bus 1 driver name" + default "i2c1_drv" + config I2C_1_DEVICE_NAME_0 + string "i2c bus 1 device 0 name" + default "i2c1_dev0" +endif diff --git a/board/k210-emulator/third_party_driver/i2c/Makefile b/board/k210-emulator/third_party_driver/i2c/Makefile new file mode 100644 index 00000000..b2bf4364 --- /dev/null +++ b/board/k210-emulator/third_party_driver/i2c/Makefile @@ -0,0 +1,6 @@ +SRC_FILES := connect_i2c.c hardware_i2c.c + + + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/i2c/connect_i2c.c b/board/k210-emulator/third_party_driver/i2c/connect_i2c.c new file mode 100644 index 00000000..65fb2088 --- /dev/null +++ b/board/k210-emulator/third_party_driver/i2c/connect_i2c.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2020 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2012-04-25 weety first version + */ + +/** +* @file connect_i2c.c +* @brief support kd233-board i2c function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: connect_i2c.c +Description: support kd233-board i2c configure and i2c bus register function +Others: take RT-Thread v4.0.2/components/drivers/i2c/i2c-bit-ops.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. support kd233-board i2c bit configure, write and read +2. support kd233-board i2c bus device and driver register +*************************************************/ + +#include + #include "gpio_common.h" + #include"fpioa.h" +#include "connect_i2c.h" +#include +#include "sysctl.h" +#include "gpio.h" + +#ifndef BSP_USING_I2C1 +#define BSP_USING_I2C1 +#endif + +#define I2C_SDA_FUNC_GPIO 3 +#define I2C_SCL_FUNC_GPIO 4 + +static I2cBusParam i2c_bus_param = +{ + I2C_SDA_FUNC_GPIO, + I2C_SCL_FUNC_GPIO, +}; + +#define SET_SDA(done, val) done->SetSdaState(done->data, val) +#define SET_SCL(done, val) done->SetSclState(done->data, val) +#define GET_SDA(done) done->GetSdaState(done->data) +#define GET_SCL(done) done->GetSclState(done->data) +#define SdaLow(done) SET_SDA(done, 0) +#define SdaHigh(done) SET_SDA(done, 1) +#define SclLow(done) SET_SCL(done, 0) + +void I2cGpioInit(const I2cBusParam *bus_param) +{ + gpio_init (); + FpioaSetFunction(BSP_I2C_SDA , FUNC_GPIO3 );//RISC-V FPIOA CFG + FpioaSetFunction(BSP_I2C_SCL , FUNC_GPIO4 );//RISC-V FPIOA CFG + gpio_set_drive_mode(bus_param->i2c_sda_pin , GPIO_DM_OUTPUT ); + gpio_set_drive_mode(bus_param->i2c_scl_pin, GPIO_DM_OUTPUT ); + gpio_set_pin(bus_param->i2c_sda_pin , GPIO_PV_HIGH ); + gpio_set_pin(bus_param->i2c_scl_pin , GPIO_PV_HIGH ); +} + +static void SetSdaState(void *data, uint8 sda_state) +{ + I2cBusParam *bus_param = (I2cBusParam *)data; + if (sda_state) { + gpio_set_drive_mode(bus_param->i2c_sda_pin, GPIO_DM_OUTPUT ); + gpio_set_pin(bus_param->i2c_sda_pin , GPIO_PV_HIGH ); + } else { + gpio_set_drive_mode(bus_param->i2c_sda_pin, GPIO_DM_OUTPUT ); + gpio_set_pin(bus_param->i2c_sda_pin , GPIO_PV_LOW ); + } +} + +static void SetSclState(void *data, uint8 scl_state) +{ + I2cBusParam *bus_param = (I2cBusParam *)data; + if (scl_state) { + gpio_set_drive_mode(bus_param->i2c_scl_pin, GPIO_DM_OUTPUT ); + gpio_set_pin(bus_param->i2c_scl_pin , GPIO_PV_HIGH ); + } else { + gpio_set_drive_mode(bus_param->i2c_scl_pin, GPIO_DM_OUTPUT ); + gpio_set_pin(bus_param->i2c_scl_pin , GPIO_PV_LOW ); + } +} + +static uint8 GetSdaState(void *data) +{ + I2cBusParam *bus_param = (I2cBusParam *)data; + gpio_set_drive_mode (bus_param->i2c_sda_pin, GPIO_DM_INPUT_PULL_UP ); + return gpio_get_pin(bus_param->i2c_sda_pin); +} + +static uint8 GetSclState(void *data) +{ + I2cBusParam *bus_param = (I2cBusParam *)data; + gpio_set_drive_mode (bus_param->i2c_scl_pin, GPIO_DM_INPUT_PULL_UP ); + return gpio_get_pin(bus_param->i2c_scl_pin); +} + +static const struct I2cHalDrvDone I2cDrvDone = +{ + .data = (&i2c_bus_param), + .SetSdaState = SetSdaState, + .SetSclState = SetSclState, + .GetSdaState = GetSdaState, + .GetSclState = GetSclState, + .udelay = usleep, + .delay_us = 1, + .timeout = 100 +}; + +static x_err_t I2cBusReset(const I2cBusParam *bus_param) +{ + int32 i = 0; + gpio_set_drive_mode(bus_param->i2c_sda_pin, GPIO_DM_INPUT_PULL_UP ); + if (GPIO_LOW == gpio_get_pin(bus_param->i2c_sda_pin)) { + while (i++ < 9) { + gpio_set_drive_mode(bus_param->i2c_scl_pin, GPIO_DM_OUTPUT ); + gpio_set_pin(bus_param->i2c_scl_pin , GPIO_PV_HIGH ); + usleep(100); + gpio_set_pin(bus_param->i2c_scl_pin , GPIO_PV_LOW ); + usleep(100); + } + } + gpio_set_drive_mode(bus_param->i2c_sda_pin, GPIO_DM_INPUT_PULL_UP ); + if (GPIO_LOW == gpio_get_pin(bus_param->i2c_sda_pin)) { + return -ERROR; + } + return EOK; +} + +static __inline void I2cDelay(struct I2cHalDrvDone *done) +{ + done->udelay((done->delay_us + 1) >> 1); +} + +static __inline void I2cDelay2(struct I2cHalDrvDone *done) +{ + done->udelay(done->delay_us); +} + +static x_err_t SclHigh(struct I2cHalDrvDone *done) +{ + x_ticks_t start; + + SET_SCL(done, 1); + + if (!done->GetSclState) + goto done; + + start = CurrentTicksGain(); + while (!GET_SCL(done)) { + if ((CurrentTicksGain() - start) > done->timeout) + return -ETIMEOUT; + DelayKTask((done->timeout + 1) >> 1); + } + +done: + I2cDelay(done); + + return EOK; +} + +static void I2cStart(struct I2cHalDrvDone *done) +{ + SdaLow(done); + I2cDelay(done); + SclLow(done); +} + +static void I2cRestart(struct I2cHalDrvDone *done) +{ + SdaHigh(done); + SclHigh(done); + I2cDelay(done); + SdaLow(done); + I2cDelay(done); + SclLow(done); +} + +static void I2cStop(struct I2cHalDrvDone *done) +{ + SdaLow(done); + I2cDelay(done); + SclHigh(done); + I2cDelay(done); + SdaHigh(done); + I2cDelay2(done); +} + +static __inline x_bool I2cWaitack(struct I2cHalDrvDone *done) +{ + x_bool ack; + + SdaHigh(done); + GET_SDA(done); + I2cDelay(done); + + if (SclHigh(done) < 0) { + KPrintf("wait ack timeout"); + return -ETIMEOUT; + } + + ack = !GET_SDA(done); + + SclLow(done); + + return ack; +} + +static int32 I2cWriteb(struct I2cBus *bus, uint8 data) +{ + int32 i; + uint8 bit; + + struct I2cHalDrvDone *done = (struct I2cHalDrvDone *)bus->private_data; + + for (i = 7; i >= 0; i--) { + SclLow(done); + bit = (data >> i) & 1; + SET_SDA(done, bit); + I2cDelay(done); + if (SclHigh(done) < 0) { + KPrintf("I2cWriteb: 0x%02x, " + "wait scl pin high timeout at bit %d", + data, i); + + return -ETIMEOUT; + } + } + SclLow(done); + I2cDelay(done); + + return I2cWaitack(done); +} + +static int32 I2cReadb(struct I2cBus *bus) +{ + uint8 i; + uint8 data = 0; + struct I2cHalDrvDone *done = (struct I2cHalDrvDone *)bus->private_data; + + SdaHigh(done); + GET_SDA(done); + I2cDelay(done); + for (i = 0; i < 8; i++) { + data <<= 1; + + if (SclHigh(done) < 0) { + KPrintf("I2cReadb: wait scl pin high " + "timeout at bit %d", 7 - i); + + return -ETIMEOUT; + } + + if (GET_SDA(done)) + data |= 1; + SclLow(done); + I2cDelay2(done); + } + + return data; +} + +static x_size_t I2cSendBytes(struct I2cBus *bus, struct I2cDataStandard *msg) +{ + int32 ret; + x_size_t bytes = 0; + const uint8 *ptr = msg->buf; + int32 count = msg->len; + uint16 ignore_nack = msg->flags & I2C_IGNORE_NACK; + + while (count > 0) { + ret = I2cWriteb(bus, *ptr); + + if ((ret > 0) || (ignore_nack && (ret == 0))) { + count --; + ptr ++; + bytes ++; + } else if (ret == 0) { + return 0; + } else { + KPrintf("send bytes: error %d", ret); + + return ret; + } + } + + return bytes; +} + +static x_err_t I2cSendAckOrNack(struct I2cBus *bus, int ack) +{ + struct I2cHalDrvDone *done = (struct I2cHalDrvDone *)bus->private_data; + + if (ack) + SET_SDA(done, 0); + I2cDelay(done); + if (SclHigh(done) < 0) { + KPrintf("ACK or NACK timeout."); + + return -ETIMEOUT; + } + SclLow(done); + + return EOK; +} + +static x_size_t I2cRecvBytes(struct I2cBus *bus, struct I2cDataStandard *msg) +{ + int32 val; + int32 bytes = 0; + uint8 *ptr = msg->buf; + int32 count = msg->len; + const uint32 flags = msg->flags; + + while (count > 0) { + val = I2cReadb(bus); + if (val >= 0) { + *ptr = val; + bytes ++; + } else { + break; + } + + ptr ++; + count --; + + if (!(flags & I2C_NO_READ_ACK)) { + val = I2cSendAckOrNack(bus, count); + if (val < 0) + return val; + } + } + + return bytes; +} + +static int32 I2cSendAddress(struct I2cBus *bus, uint8 addr, int32 retries) +{ + struct I2cHalDrvDone *done = (struct I2cHalDrvDone *)bus->private_data; + int32 i; + x_err_t ret = 0; + + for (i = 0; i <= retries; i++) { + ret = I2cWriteb(bus, addr); + if (ret == 1 || i == retries) + break; + I2cStop(done); + I2cDelay2(done); + I2cStart(done); + } + + return ret; +} + +static x_err_t I2cBitSendAddress(struct I2cBus *bus, struct I2cDataStandard *msg) +{ + uint16 flags = msg->flags; + uint16 ignore_nack = msg->flags & I2C_IGNORE_NACK; + struct I2cHalDrvDone *done = (struct I2cHalDrvDone *)bus->private_data; + + uint8 addr1, addr2; + int32 retries; + x_err_t ret; + + retries = ignore_nack ? 0 : msg->retries; + + if (flags & I2C_ADDR_10BIT) { + addr1 = 0xf0 | ((msg->addr >> 7) & 0x06); + addr2 = msg->addr & 0xff; + + ret = I2cSendAddress(bus, addr1, retries); + if ((ret != 1) && !ignore_nack) { + + return -EPIO; + } + + ret = I2cWriteb(bus, addr2); + if ((ret != 1) && !ignore_nack) { + + return -EPIO; + } + + if (flags & I2C_RD) { + I2cRestart(done); + addr1 |= 0x01; + ret = I2cSendAddress(bus, addr1, retries); + if ((ret != 1) && !ignore_nack) { + + return -EPIO; + } + } + } else { + addr1 = msg->addr << 1; + if (flags & I2C_RD) + addr1 |= 1; + ret = I2cSendAddress(bus, addr1, retries); + if ((ret != 1) && !ignore_nack) + return -EPIO; + } + + return EOK; +} + +static uint32 I2cWriteData(struct I2cHardwareDevice *i2c_dev, struct I2cDataStandard *msg) +{ + struct I2cBus *bus = (struct I2cBus *)i2c_dev->haldev.owner_bus; + bus->private_data = i2c_dev->haldev.owner_bus->private_data; + struct I2cHalDrvDone *done = (struct I2cHalDrvDone *)bus->private_data; + int32 ret; + int32 i = 0; + uint16 ignore_nack; + + I2cStart(done); + while (NONE != msg) { + ignore_nack = msg->flags & I2C_IGNORE_NACK; + if (!(msg->flags & I2C_NO_START)) { + if (i) { + I2cRestart(done); + } + ret = I2cBitSendAddress(bus, msg); + if ((ret != EOK) && !ignore_nack) { + goto out; + } + } + + if (msg->flags & I2C_WR) { + ret = I2cSendBytes(bus, msg); + if (ret >= 1) + //KPrintf("write %d byte%s", ret, ret == 1 ? "" : "s"); + if (ret < msg->len) { + if (ret >= 0) + ret = -ERROR; + goto out; + } + } + msg = msg->next; + i++; + } + ret = i; + +out: + I2cStop(done); + + return ret; +} + +static uint32 I2cReadData(struct I2cHardwareDevice *i2c_dev, struct I2cDataStandard *msg) +{ + struct I2cBus *bus = (struct I2cBus *)i2c_dev->haldev.owner_bus; + bus->private_data = i2c_dev->haldev.owner_bus->private_data; + struct I2cHalDrvDone *done = (struct I2cHalDrvDone *)bus->private_data; + int32 ret; + int32 i = 0; + uint16 ignore_nack; + + I2cStart(done); + while (NONE != msg) { + ignore_nack = msg->flags & I2C_IGNORE_NACK; + if (!(msg->flags & I2C_NO_START)) { + if (i) { + I2cRestart(done); + } + + ret = I2cBitSendAddress(bus, msg); + if ((ret != EOK) && !ignore_nack) { + goto out; + } + } + + if (msg->flags & I2C_RD) { + ret = I2cRecvBytes(bus, msg); + if (ret >= 1) + //KPrintf("read %d byte%s", ret, ret == 1 ? "" : "s"); + if (ret < msg->len) { + if (ret >= 0) + ret = -EPIO; + goto out; + } + } + msg = msg->next; + i++; + } + ret = i; + +out: + I2cStop(done); + + return ret; +} + +/*manage the i2c device operations*/ +static const struct I2cDevDone i2c_dev_done = +{ + .open = NONE, + .close = NONE, + .write = I2cWriteData, + .read = I2cReadData, +}; + +/*Init i2c bus*/ +static int BoardI2cBusInit(struct I2cBus *i2c_bus, struct I2cDriver *i2c_driver) +{ + x_err_t ret = EOK; + + /*Init the i2c bus */ + i2c_bus->private_data = (void *)&I2cDrvDone; + ret = I2cBusInit(i2c_bus, I2C_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_i2c_init I2cBusInit error %d\n", ret); + return ERROR; + } + + /*Init the i2c driver*/ + i2c_driver->private_data = (void *)&I2cDrvDone; + ret = I2cDriverInit(i2c_driver, I2C_DRV_NAME_1); + if (EOK != ret) { + KPrintf("board_i2c_init I2cDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the i2c driver to the i2c bus*/ + ret = I2cDriverAttachToBus(I2C_DRV_NAME_1, I2C_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_i2c_init I2cDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the i2c device to the i2c bus*/ +static int BoardI2cDevBend(void) +{ + x_err_t ret = EOK; + static struct I2cHardwareDevice i2c_device0; + memset(&i2c_device0, 0, sizeof(struct I2cHardwareDevice)); + + i2c_device0.i2c_dev_done = &i2c_dev_done; + + ret = I2cDeviceRegister(&i2c_device0, NONE, I2C_1_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("board_i2c_init I2cDeviceInit device %s error %d\n", I2C_1_DEVICE_NAME_0, ret); + return ERROR; + } + + ret = I2cDeviceAttachToBus(I2C_1_DEVICE_NAME_0, I2C_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_i2c_init I2cDeviceAttachToBus device %s error %d\n", I2C_1_DEVICE_NAME_0, ret); + return ERROR; + } + + return ret; +} + +/*KD233 BOARD I2C INIT*/ +int HwI2cInit(void) +{ + x_err_t ret = EOK; + static struct I2cBus i2c_bus; + memset(&i2c_bus, 0, sizeof(struct I2cBus)); + + static struct I2cDriver i2c_driver; + memset(&i2c_driver, 0, sizeof(struct I2cDriver)); + +#ifdef BSP_USING_I2C1 + I2cGpioInit(&i2c_bus_param); + + ret = BoardI2cBusInit(&i2c_bus, &i2c_driver); + if (EOK != ret) { + KPrintf("board_i2c_Init error ret %u\n", ret); + return ERROR; + } + + ret = BoardI2cDevBend(); + if (EOK != ret) { + KPrintf("board_i2c_Init error ret %u\n", ret); + return ERROR; + } + + I2cBusReset(&i2c_bus_param); +#endif + + return ret; +} diff --git a/board/k210-emulator/third_party_driver/i2c/hardware_i2c.c b/board/k210-emulator/third_party_driver/i2c/hardware_i2c.c new file mode 100644 index 00000000..a4c2bdf9 --- /dev/null +++ b/board/k210-emulator/third_party_driver/i2c/hardware_i2c.c @@ -0,0 +1,371 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_i2c.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include "hardware_i2c.h" +#include "utils.h" +#include "fpioa.h" +#include "platform.h" +#include "stdlib.h" +#include "string.h" +#include "sysctl.h" +#include "bsp.h" + +typedef struct _i2c_slave_instance +{ + uint32_t i2c_num; + const i2c_slave_handler_t *slave_handler; +} i2c_slave_instance_t; + +static i2c_slave_instance_t slave_instance[I2C_MAX_NUM]; + +typedef struct _i2c_instance +{ + i2c_device_number_t i2c_num; + i2c_transfer_mode_t TransferMode; + dmac_channel_number_t dmac_channel; + plic_instance_t i2c_int_instance; + spinlock_t lock; +} i2c_instance_t; + +static i2c_instance_t g_i2c_instance[3]; + +volatile i2c_t* const i2c[3] = +{ + (volatile i2c_t*)I2C0_BASE_ADDR, + (volatile i2c_t*)I2C1_BASE_ADDR, + (volatile i2c_t*)I2C2_BASE_ADDR +}; + +static void i2c_clk_init(i2c_device_number_t i2c_num) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + sysctl_clock_enable(SYSCTL_CLOCK_I2C0 + i2c_num); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2C0 + i2c_num, 3); +} + +void i2c_init(i2c_device_number_t i2c_num, uint32_t slave_address, uint32_t address_width, + uint32_t i2c_clk) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + configASSERT(address_width == 7 || address_width == 10); + + volatile i2c_t *i2c_adapter = i2c[i2c_num]; + + i2c_clk_init(i2c_num); + + uint32_t v_i2c_freq = SysctlClockGetFreq(SYSCTL_CLOCK_I2C0 + i2c_num); + uint16_t v_period_clk_cnt = v_i2c_freq / i2c_clk / 2; + + if(v_period_clk_cnt == 0) + v_period_clk_cnt = 1; + + i2c_adapter->enable = 0; + i2c_adapter->con = I2C_CON_MASTER_MODE | I2C_CON_SLAVE_DISABLE | I2C_CON_RESTART_EN | + (address_width == 10 ? I2C_CON_10BITADDR_SLAVE : 0) | I2C_CON_SPEED(1); + i2c_adapter->ss_scl_hcnt = I2C_SS_SCL_HCNT_COUNT(v_period_clk_cnt); + i2c_adapter->ss_scl_lcnt = I2C_SS_SCL_LCNT_COUNT(v_period_clk_cnt); + + i2c_adapter->tar = I2C_TAR_ADDRESS(slave_address); + i2c_adapter->intr_mask = 0; + i2c_adapter->dma_cr = 0x3; + i2c_adapter->dma_rdlr = 0; + i2c_adapter->dma_tdlr = 4; + i2c_adapter->enable = I2C_ENABLE_ENABLE; +} + +static int i2c_slave_irq(void *userdata) +{ + i2c_slave_instance_t *instance = (i2c_slave_instance_t *)userdata; + volatile i2c_t *i2c_adapter = i2c[instance->i2c_num]; + uint32_t status = i2c_adapter->intr_stat; + if (status & I2C_INTR_STAT_START_DET) + { + instance->slave_handler->on_event(I2C_EV_START); + readl(&i2c_adapter->clr_start_det); + } + if (status & I2C_INTR_STAT_STOP_DET) + { + instance->slave_handler->on_event(I2C_EV_STOP); + readl(&i2c_adapter->clr_stop_det); + } + if (status & I2C_INTR_STAT_RX_FULL) + { + instance->slave_handler->on_receive(i2c_adapter->data_cmd); + } + if (status & I2C_INTR_STAT_RD_REQ) + { + i2c_adapter->data_cmd = instance->slave_handler->on_transmit(); + readl(&i2c_adapter->clr_rd_req); + } + return 0; +} + +void i2c_init_as_slave(i2c_device_number_t i2c_num, uint32_t slave_address, uint32_t address_width, + const i2c_slave_handler_t *handler) +{ + configASSERT(address_width == 7 || address_width == 10); + volatile i2c_t *i2c_adapter = i2c[i2c_num]; + slave_instance[i2c_num].i2c_num = i2c_num; + slave_instance[i2c_num].slave_handler = handler; + + i2c_clk_init(i2c_num); + i2c_adapter->enable = 0; + i2c_adapter->con = (address_width == 10 ? I2C_CON_10BITADDR_SLAVE : 0) | I2C_CON_SPEED(1) | I2C_CON_STOP_DET_IFADDRESSED; + i2c_adapter->ss_scl_hcnt = I2C_SS_SCL_HCNT_COUNT(37); + i2c_adapter->ss_scl_lcnt = I2C_SS_SCL_LCNT_COUNT(40); + i2c_adapter->sar = I2C_SAR_ADDRESS(slave_address); + i2c_adapter->rx_tl = I2C_RX_TL_VALUE(0); + i2c_adapter->tx_tl = I2C_TX_TL_VALUE(0); + i2c_adapter->intr_mask = I2C_INTR_MASK_RX_FULL | I2C_INTR_MASK_START_DET | I2C_INTR_MASK_STOP_DET | I2C_INTR_MASK_RD_REQ; + + plic_set_priority(IRQN_I2C0_INTERRUPT + i2c_num, 1); + plic_irq_register(IRQN_I2C0_INTERRUPT + i2c_num, i2c_slave_irq, slave_instance + i2c_num); + plic_irq_enable(IRQN_I2C0_INTERRUPT + i2c_num); + + i2c_adapter->enable = I2C_ENABLE_ENABLE; +} + +int i2c_send_data(i2c_device_number_t i2c_num, const uint8_t *SendBuf, size_t send_buf_len) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + size_t fifo_len, index; + i2c_adapter->clr_tx_abrt = i2c_adapter->clr_tx_abrt; + while (send_buf_len) + { + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = send_buf_len < fifo_len ? send_buf_len : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*SendBuf++); + if (i2c_adapter->tx_abrt_source != 0) + return 1; + send_buf_len -= fifo_len; + } + while ((i2c_adapter->status & I2C_STATUS_ACTIVITY) || !(i2c_adapter->status & I2C_STATUS_TFE)) + ; + + if (i2c_adapter->tx_abrt_source != 0) + return 1; + + return 0; +} + +void i2c_send_data_dma(dmac_channel_number_t dma_channel_num, i2c_device_number_t i2c_num, const uint8_t *SendBuf, + size_t send_buf_len) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + i2c_adapter->clr_tx_abrt = i2c_adapter->clr_tx_abrt; + uint32_t *buf = malloc(send_buf_len * sizeof(uint32_t)); + int i; + for (i = 0; i < send_buf_len; i++) + { + buf[i] = SendBuf[i]; + } + + sysctl_dma_select((sysctl_dma_channel_t)dma_channel_num, SYSCTL_DMA_SELECT_I2C0_TX_REQ + i2c_num * 2); + dmac_set_single_mode(dma_channel_num, buf, (void *)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, send_buf_len); + + dmac_wait_done(dma_channel_num); + free((void *)buf); + + while ((i2c_adapter->status & I2C_STATUS_ACTIVITY) || !(i2c_adapter->status & I2C_STATUS_TFE)) + { + if (i2c_adapter->tx_abrt_source != 0) + return; + } +} + +int i2c_recv_data(i2c_device_number_t i2c_num, const uint8_t *SendBuf, size_t send_buf_len, uint8_t *receive_buf, + size_t receive_buf_len) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + + size_t fifo_len, index; + size_t rx_len = receive_buf_len; + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + + while (send_buf_len) + { + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = send_buf_len < fifo_len ? send_buf_len : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*SendBuf++); + if (i2c_adapter->tx_abrt_source != 0) + return 1; + send_buf_len -= fifo_len; + } + + while (receive_buf_len || rx_len) + { + fifo_len = i2c_adapter->rxflr; + fifo_len = rx_len < fifo_len ? rx_len : fifo_len; + for (index = 0; index < fifo_len; index++) + *receive_buf++ = (uint8_t)i2c_adapter->data_cmd; + rx_len -= fifo_len; + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = receive_buf_len < fifo_len ? receive_buf_len : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_CMD; + if (i2c_adapter->tx_abrt_source != 0) + return 1; + receive_buf_len -= fifo_len; + } + return 0; +} + +void i2c_recv_data_dma(dmac_channel_number_t dma_send_channel_num, dmac_channel_number_t dma_receive_channel_num, + i2c_device_number_t i2c_num, const uint8_t *SendBuf, size_t send_buf_len, + uint8_t *receive_buf, size_t receive_buf_len) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + + uint32_t *write_cmd = malloc(sizeof(uint32_t) * (send_buf_len + receive_buf_len)); + size_t i; + for(i = 0; i < send_buf_len; i++) + write_cmd[i] = *SendBuf++; + for (i = 0; i < receive_buf_len; i++) + write_cmd[i + send_buf_len] = I2C_DATA_CMD_CMD; + + sysctl_dma_select((sysctl_dma_channel_t)dma_send_channel_num, SYSCTL_DMA_SELECT_I2C0_TX_REQ + i2c_num * 2); + sysctl_dma_select((sysctl_dma_channel_t)dma_receive_channel_num, SYSCTL_DMA_SELECT_I2C0_RX_REQ + i2c_num * 2); + + dmac_set_single_mode(dma_receive_channel_num, (void *)(&i2c_adapter->data_cmd), write_cmd, DMAC_ADDR_NOCHANGE, + DMAC_ADDR_INCREMENT,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, receive_buf_len); + + dmac_set_single_mode(dma_send_channel_num, write_cmd, (void *)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, + DMAC_ADDR_NOCHANGE,DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, receive_buf_len + send_buf_len); + + dmac_wait_done(dma_send_channel_num); + dmac_wait_done(dma_receive_channel_num); + + for (i = 0; i < receive_buf_len; i++) + { + receive_buf[i] = (uint8_t)write_cmd[i]; + } + + free(write_cmd); +} + +static int i2c_dma_irq(void *ctx) +{ + i2c_instance_t *v_instance = (i2c_instance_t *)ctx; + volatile i2c_t* i2c_adapter = i2c[v_instance->i2c_num]; + dmac_irq_unregister(v_instance->dmac_channel); + if(v_instance->TransferMode == I2C_SEND) + { + while ((i2c_adapter->status & I2C_STATUS_ACTIVITY) || !(i2c_adapter->status & I2C_STATUS_TFE)) + { + if (i2c_adapter->tx_abrt_source != 0) + { + spinlock_unlock(&v_instance->lock); + return -1; + } + } + } + spinlock_unlock(&v_instance->lock); + if(v_instance->i2c_int_instance.callback) + { + v_instance->i2c_int_instance.callback(v_instance->i2c_int_instance.ctx); + } + return 0; +} + +void i2c_handle_data_dma(i2c_device_number_t i2c_num, i2c_data_t data, plic_interrupt_t *cb) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + configASSERT(data.tx_channel < DMAC_CHANNEL_MAX && data.rx_channel < DMAC_CHANNEL_MAX); + + spinlock_lock(&g_i2c_instance[i2c_num].lock); + if(cb) + { + g_i2c_instance[i2c_num].i2c_int_instance.callback = cb->callback; + g_i2c_instance[i2c_num].i2c_int_instance.ctx = cb->ctx; + } + + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + if(data.TransferMode == I2C_SEND) + { + configASSERT(data.tx_buf && data.tx_len); + + i2c_adapter->clr_tx_abrt = i2c_adapter->clr_tx_abrt; + if(cb) + { + g_i2c_instance[i2c_num].dmac_channel = data.tx_channel; + g_i2c_instance[i2c_num].TransferMode = I2C_SEND; + dmac_irq_register(data.tx_channel, i2c_dma_irq, &g_i2c_instance[i2c_num], cb->priority); + } + sysctl_dma_select((sysctl_dma_channel_t)data.tx_channel, SYSCTL_DMA_SELECT_I2C0_TX_REQ + i2c_num * 2); + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + if(!cb) + { + dmac_wait_done(data.tx_channel); + while ((i2c_adapter->status & I2C_STATUS_ACTIVITY) || !(i2c_adapter->status & I2C_STATUS_TFE)) + { + if (i2c_adapter->tx_abrt_source != 0) + configASSERT(!"source abort"); + } + } + } + else + { + configASSERT(data.rx_buf && data.rx_len); + if(data.tx_len) + configASSERT(data.tx_buf); + if(cb) + { + g_i2c_instance[i2c_num].dmac_channel = data.rx_channel; + g_i2c_instance[i2c_num].TransferMode = I2C_RECEIVE; + dmac_irq_register(data.rx_channel, i2c_dma_irq, &g_i2c_instance[i2c_num], cb->priority); + } + sysctl_dma_select((sysctl_dma_channel_t)data.rx_channel, SYSCTL_DMA_SELECT_I2C0_RX_REQ + i2c_num * 2); + dmac_set_single_mode(data.rx_channel, (void *)(&i2c_adapter->data_cmd), data.rx_buf, DMAC_ADDR_NOCHANGE, + DMAC_ADDR_INCREMENT,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + + sysctl_dma_select((sysctl_dma_channel_t)data.tx_channel, SYSCTL_DMA_SELECT_I2C0_TX_REQ + i2c_num * 2); + if(data.tx_len) + { + configASSERT(data.tx_buf); + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, + DMAC_ADDR_NOCHANGE,DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + dmac_wait_done(data.tx_channel); + } + static uint32_t s_read_cmd = I2C_DATA_CMD_CMD; + dmac_set_single_mode(data.tx_channel, &s_read_cmd, (void *)(&i2c_adapter->data_cmd), DMAC_ADDR_NOCHANGE, + DMAC_ADDR_NOCHANGE,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + + if(!cb) + { + dmac_wait_done(data.tx_channel); + dmac_wait_done(data.rx_channel); + } + } + if(!cb) + spinlock_unlock(&g_i2c_instance[i2c_num].lock); +} diff --git a/board/k210-emulator/third_party_driver/include/clint.h b/board/k210-emulator/third_party_driver/include/clint.h new file mode 100644 index 00000000..58cccf47 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/clint.h @@ -0,0 +1,323 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 clint.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __CLINT_H__ +#define __CLINT_H__ + +#include +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define CLINT_MSIP (0x0000) +#define CLINT_MSIP_SIZE (0x4) +#define CLINT_MTIMECMP (0x4000) +#define CLINT_MTIMECMP_SIZE (0x8) +#define CLINT_MTIME (0xBFF8) +#define CLINT_MTIME_SIZE (0x8) +/* Max number of cores */ +#define CLINT_MAX_CORES (4095) +/* Real number of cores */ +#define CLINT_NUM_CORES (2) +/* Clock frequency division factor */ +#define CLINT_CLOCK_DIV (50) +/* clang-format on */ + +/** + * @brief MSIP Registers + * + * Machine-mode software interrupts are generated by writing to a + * per-core memory-mapped control register. The msip registers are + * 32-bit wide WARL registers, where the LSB is reflected in the + * msip bit of the associated core’s mip register. Other bits in + * the msip registers are hardwired to zero. The mapping supports + * up to 4095 machine-mode cores. + */ +typedef struct _clint_msip +{ + uint32_t msip : 1; /*!< Bit 0 is msip */ + uint32_t zero : 31; /*!< Bits [32:1] is 0 */ +} __attribute__((packed, aligned(4))) clint_msip_t; + +/** + * @brief Timer compare Registers Machine-mode timer interrupts are + * generated by a real-time counter and a per-core comparator. The + * mtime register is a 64-bit read-only register that contains the + * current value of the real-time counter. Each mtimecmp register + * holds its core’s time comparator. A timer interrupt is pending + * whenever mtime is greater than or equal to the value in a + * core’s mtimecmp register. The timer interrupt is reflected in + * the mtip bit of the associated core’s mip register. + */ +typedef uint64_t clint_mtimecmp_t; + +/** + * @brief Timer Registers + * + * The mtime register has a 64-bit precision on all RV32, RV64, + * and RV128 systems. Platforms provide a 64-bit memory-mapped + * machine-mode timer compare register (mtimecmp), which causes a + * timer interrupt to be posted when the mtime register contains a + * value greater than or equal to the value in the mtimecmp + * register. The interrupt remains posted until it is cleared by + * writing the mtimecmp register. The interrupt will only be taken + * if interrupts are enabled and the MTIE bit is set in the mie + * register. + */ +typedef uint64_t clint_mtime_t; + +/** + * @brief CLINT object + * + * Coreplex-Local INTerrupts, which includes software interrupts, + * local timer interrupts, and other interrupts routed directly to + * a core. + */ +typedef struct _clint +{ + /* 0x0000 to 0x3FF8, MSIP Registers */ + clint_msip_t msip[CLINT_MAX_CORES]; + /* Resverd space, do not use */ + uint32_t resv0; + /* 0x4000 to 0xBFF0, Timer Compare Registers */ + clint_mtimecmp_t mtimecmp[CLINT_MAX_CORES]; + /* 0xBFF8, Time Register */ + clint_mtime_t mtime; +} __attribute__((packed, aligned(4))) clint_t; + +/** + * @brief Clint object instanse + */ +extern volatile clint_t* const clint; + +/** + * @brief Definitions for the timer callbacks + */ +typedef int (*clint_timer_callback_t)(void *ctx); + +/** + * @brief Definitions for local interprocessor interrupt callbacks + */ +typedef int (*clint_ipi_callback_t)(void *ctx); + +typedef struct _clint_timer_instance +{ + uint64_t interval; + uint64_t cycles; + uint64_t single_shot; + clint_timer_callback_t callback; + void *ctx; +} clint_timer_instance_t; + +typedef struct _clint_ipi_instance +{ + clint_ipi_callback_t callback; + void *ctx; +} clint_ipi_instance_t; + +/** + * @brief Get the time form CLINT timer register + * + * @note The CLINT must init to get right time + * + * @return 64bit Time + */ +uint64_t clint_get_time(void); + +/** + * @brief Init the CLINT timer + * + * @note MIP_MTIP will be clear after init. The MSTATUS_MIE must set by + * user. + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_init(void); + +/** + * @brief Stop the CLINT timer + * + * @note MIP_MTIP will be clear after stop + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_stop(void); + +/** + * @brief Start the CLINT timer + * + * @param[in] interval The interval with Millisecond(ms) + * @param[in] single_shot Single shot or repeat + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_start(uint64_t interval, int single_shot); + +/** + * @brief Get the interval of timer + * + * @return The interval with Millisecond(ms) + */ +uint64_t clint_timer_get_interval(void); + +/** + * @brief Set the interval with Millisecond(ms) + * + * @param[in] interval The interval with Millisecond(ms) + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_set_interval(uint64_t interval); + +/** + * @brief Get whether the timer is a single shot timer + * + * @return result + * - 0 It is a repeat timer + * - 1 It is a single shot timer + */ +int clint_timer_get_single_shot(void); + +/** + * @brief Set the timer working as a single shot timer or repeat timer + * + * @param[in] single_shot Single shot or repeat + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_set_single_shot(int single_shot); + +/** + * @brief Set user callback function when timer is timeout + * + * @param[in] callback The callback function + * @param[in] ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_register(clint_timer_callback_t callback, void *ctx); + +/** + * @brief Deregister user callback function + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_unregister(void); + +/** + * @brief Initialize local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_init(void); + +/** + * @brief Enable local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_enable(void); + +/** + * @brief Disable local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_disable(void); + +/** + * @brief Send local interprocessor interrupt to core by core id + * + * @param[in] core_id The core identifier + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_send(size_t core_id); + +/** + * @brief Clear local interprocessor interrupt + * + * @param[in] core_id The core identifier + * + * @return result + * - 1 An IPI was pending + * - 0 Non IPI was pending + * - -1 Fail + */ +int clint_ipi_clear(size_t core_id); + +/** + * @brief Set user callback function when interprocessor interrupt + * + * @param[in] callback The callback function + * @param[in] ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_register(clint_ipi_callback_t callback, void *ctx); + +/** + * @brief Deregister user callback function + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_unregister(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __CLINT_H__ */ + diff --git a/board/k210-emulator/third_party_driver/include/connect_gpio.h b/board/k210-emulator/third_party_driver/include/connect_gpio.h new file mode 100644 index 00000000..b6bae7b1 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/connect_gpio.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_gpio.h +* @brief define kd233-board gpio function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_GPIO_H +#define CONNECT_GPIO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int HwGpioInit(void); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/board/k210-emulator/third_party_driver/include/connect_hwtimer.h b/board/k210-emulator/third_party_driver/include/connect_hwtimer.h new file mode 100644 index 00000000..1303bff3 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/connect_hwtimer.h @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_hwtimer.h +* @brief define kd233-board hwtimer function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_HWTIMER_H +#define CONNECT_HWTIMER_H + +#include +#include "hardware_hwtimer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int HwTimerInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/board/k210-emulator/third_party_driver/include/connect_i2c.h b/board/k210-emulator/third_party_driver/include/connect_i2c.h new file mode 100644 index 00000000..650dafa7 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/connect_i2c.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_i2c.h +* @brief define kd233-board i2c function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_I2C_H +#define CONNECT_I2C_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int HwI2cInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/board/k210-emulator/third_party_driver/include/connect_rtc.h b/board/k210-emulator/third_party_driver/include/connect_rtc.h new file mode 100644 index 00000000..fb1da41a --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/connect_rtc.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_rtc.h +* @brief define kd233-board rtc function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_RTC_H +#define CONNECT_RTC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int HwRtcInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/board/k210-emulator/third_party_driver/include/connect_spi.h b/board/k210-emulator/third_party_driver/include/connect_spi.h new file mode 100644 index 00000000..6df5442e --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/connect_spi.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_spi.h +* @brief define kd233-board spi function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_SPI_H +#define CONNECT_SPI_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int HwSpiInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/board/k210-emulator/third_party_driver/include/connect_uart.h b/board/k210-emulator/third_party_driver/include/connect_uart.h new file mode 100644 index 00000000..8a336c3a --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/connect_uart.h @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_uart.h +* @brief define kd233-board uart function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_UART_H +#define CONNECT_UART_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define KERNEL_CONSOLE_BUS_NAME SERIAL_BUS_NAME_0 +#define KERNEL_CONSOLE_DRV_NAME SERIAL_DRV_NAME_0 +#define KERNEL_CONSOLE_DEVICE_NAME SERIAL_0_DEVICE_NAME_0 + +int HwUartInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/board/k210-emulator/third_party_driver/include/connect_wdt.h b/board/k210-emulator/third_party_driver/include/connect_wdt.h new file mode 100644 index 00000000..d0053bc7 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/connect_wdt.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_wdt.h +* @brief define kd233-board wdt function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_WDT_H +#define CONNECT_WDT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int HwWdtInit(void); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/board/k210-emulator/third_party_driver/include/dmac.h b/board/k210-emulator/third_party_driver/include/dmac.h new file mode 100644 index 00000000..607802ba --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/dmac.h @@ -0,0 +1,1552 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 dmac.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __DMAC_H__ +#define __DMAC_H__ + +#include +#include "io.h" +#include "platform.h" +#include "stdbool.h" +#include "plic.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* DMAC */ +#define DMAC_CHANNEL_COUNT (DMAC_CHANNEL_MAX) +#define LAST_ROW (-1) + +typedef enum _dmac_channel_number +{ + DMAC_CHANNEL0 = 0, + DMAC_CHANNEL1 = 1, + DMAC_CHANNEL2 = 2, + DMAC_CHANNEL3 = 3, + DMAC_CHANNEL4 = 4, + DMAC_CHANNEL5 = 5, + DMAC_CHANNEL_MAX +} dmac_channel_number_t; + +typedef enum _dmac_src_dst_select +{ + DMAC_SRC = 0x1, + DMAC_DST = 0x2, + DMAC_SRC_DST = 0x3 +} dmac_src_dst_select_t; + +typedef enum _state_value +{ + clear = 0, + set = 1 +} state_value_t; + +typedef enum _dmac_lock_bus_ch +{ + DMAC_LOCK_BUS = 0x1, + DMAC_LOCK_CHANNEL = 0x2, + DMAC_LOCK_BUS_CH = 0x3 +} dmac_lock_bus_ch_t; + +typedef enum _dmac_sw_hw_hs_select +{ + DMAC_HS_HARDWARE = 0x0, + DMAC_HS_SOFTWARE = 0x1 +} dmac_sw_hw_hs_select_t; + +typedef enum _dmac_scatter_gather_param +{ + DMAC_SG_COUNT = 0x0, + DMAC_SG_INTERVAL = 0x1 +} dmac_scatter_gather_param_t; + +typedef enum _dmac_irq +{ + /* no interrupts */ + DMAC_IRQ_NONE = 0x00, + /* transfer complete */ + DMAC_IRQ_TFR = 0x01, + /* block transfer complete */ + DMAC_IRQ_BLOCK = 0x02, + /* source transaction complete */ + DMAC_IRQ_SRCTRAN = 0x04, + /* destination transaction complete */ + DMAC_IRQ_DSTTRAN = 0x08, + /* error */ + DMAC_IRQ_ERR = 0x10, + /* all interrupts */ + DMAC_IRQ_ALL = 0x1f +} dmac_irq_t; + +typedef enum _dmac_software_req +{ + /* ReqSrcReq/ReqDstReq */ + DMAC_REQUEST = 0x1, + /* SglReqSrcReq/SglReqDstReq */ + DMAC_SINGLE_REQUEST = 0x2, + /* LstReqSrcReq/LstReqDstReq */ + DMAC_LAST_REQUEST = 0x4 +} dmac_software_req_t; + +typedef enum _dmac_master_number +{ + DMAC_MASTER1 = 0x0, + DMAC_MASTER2 = 0x1 +} dmac_master_number_t; + +typedef enum _dmac_transfer_flow +{ + /* mem to mem - DMAC flow ctlr */ + DMAC_MEM2MEM_DMA = 0x0, + /* mem to prf - DMAC flow ctlr */ + DMAC_MEM2PRF_DMA = 0x1, + /* prf to mem - DMAC flow ctlr */ + DMAC_PRF2MEM_DMA = 0x2, + /* prf to prf - DMAC flow ctlr */ + DMAC_PRF2PRF_DMA = 0x3, + /* prf to mem - periph flow ctlr */ + DMAC_PRF2MEM_PRF = 0x4, + /* prf to prf - source flow ctlr */ + DMAC_PRF2PRF_SRCPRF = 0x5, + /* mem to prf - periph flow ctlr */ + DMAC_MEM2PRF_PRF = 0x6, + /* prf to prf - dest flow ctlr */ + DMAC_PRF2PRF_DSTPRF = 0x7 +} dmac_transfer_flow_t; + +typedef enum _dmac_burst_trans_length +{ + DMAC_MSIZE_1 = 0x0, + DMAC_MSIZE_4 = 0x1, + DMAC_MSIZE_8 = 0x2, + DMAC_MSIZE_16 = 0x3, + DMAC_MSIZE_32 = 0x4, + DMAC_MSIZE_64 = 0x5, + DMAC_MSIZE_128 = 0x6, + DMAC_MSIZE_256 = 0x7 +} dmac_burst_trans_length_t; + +typedef enum _dmac_address_increment +{ + DMAC_ADDR_INCREMENT = 0x0, + DMAC_ADDR_NOCHANGE = 0x1 +} dmac_address_increment_t; + +typedef enum _dmac_transfer_width +{ + DMAC_TRANS_WIDTH_8 = 0x0, + DMAC_TRANS_WIDTH_16 = 0x1, + DMAC_TRANS_WIDTH_32 = 0x2, + DMAC_TRANS_WIDTH_64 = 0x3, + DMAC_TRANS_WIDTH_128 = 0x4, + DMAC_TRANS_WIDTH_256 = 0x5 +} dmac_transfer_width_t; + +typedef enum _dmac_hs_interface +{ + DMAC_HS_IF0 = 0x0, + DMAC_HS_IF1 = 0x1, + DMAC_HS_IF2 = 0x2, + DMAC_HS_IF3 = 0x3, + DMAC_HS_IF4 = 0x4, + DMAC_HS_IF5 = 0x5, + DMAC_HS_IF6 = 0x6, + DMAC_HS_IF7 = 0x7, + DMAC_HS_IF8 = 0x8, + DMAC_HS_IF9 = 0x9, + DMAC_HS_IF10 = 0xa, + DMAC_HS_IF11 = 0xb, + DMAC_HS_IF12 = 0xc, + DMAC_HS_IF13 = 0xd, + DMAC_HS_IF14 = 0xe, + DMAC_HS_IF15 = 0xf +} dmac_hs_interface_t; + +typedef enum _dmac_multiblk_transfer_type +{ + CONTIGUOUS = 0, + RELOAD = 1, + SHADOWREGISTER = 2, + LINKEDLIST = 3 +} dmac_multiblk_transfer_type_t; + +typedef enum _dmac_multiblk_type +{ + DMAC_SRC_DST_CONTINUE = 0, + DMAC_SRC_CONTINUE_DST_RELAOD = 2, + DMAC_SRC_CONTINUE_DST_LINKEDLIST = 3, + DMAC_SRC_RELOAD_DST_CONTINUE = 4, + DMAC_SRC_RELOAD_DST_RELOAD = 5, + DMAC_SRC_RELOAD_DST_LINKEDLIST = 6, + DMAC_SRC_LINKEDLIST_DST_CONTINUE = 7, + DMAC_SRC_LINKEDLIST_DST_RELOAD = 8, + DMAC_SRC_LINKEDLIST_DST_LINKEDLIST = 9, + DMAC_SRC_SHADOWREG_DST_CONTINUE = 10 +} dmac_multiblk_type_t; + +typedef enum _dmac_transfer_type +{ + DMAC_TRANSFER_ROW1 = 0x1, + DMAC_TRANSFER_ROW2 = 0x2, + DMAC_TRANSFER_ROW3 = 0x3, + DMAC_TRANSFER_ROW4 = 0x4, + DMAC_TRANSFER_ROW5 = 0x5, + DMAC_TRANSFER_ROW6 = 0x6, + DMAC_TRANSFER_ROW7 = 0x7, + DMAC_TRANSFER_ROW8 = 0x8, + DMAC_TRANSFER_ROW9 = 0x9, + DMAC_TRANSFER_ROW10 = 0xa +} dmac_transfer_type_t; + +typedef enum _dmac_prot_level +{ + /* default prot level */ + DMAC_NONCACHE_NONBUFF_NONPRIV_OPCODE = 0x0, + DMAC_NONCACHE_NONBUFF_NONPRIV_DATA = 0x1, + DMAC_NONCACHE_NONBUFF_PRIV_OPCODE = 0x2, + DMAC_NONCACHE_NONBUFF_PRIV_DATA = 0x3, + DMAC_NONCACHE_BUFF_NONPRIV_OPCODE = 0x4, + DMAC_NONCACHE_BUFF_NONPRIV_DATA = 0x5, + DMAC_NONCACHE_BUFF_PRIV_OPCODE = 0x6, + DMAC_NONCACHE_BUFF_PRIV_DATA = 0x7, + DMAC_CACHE_NONBUFF_NONPRIV_OPCODE = 0x8, + DMAC_CACHE_NONBUFF_NONPRIV_DATA = 0x9, + DMAC_CACHE_NONBUFF_PRIV_OPCODE = 0xa, + DMAC_CACHE_NONBUFF_PRIV_DATA = 0xb, + DMAC_CACHE_BUFF_NONPRIV_OPCODE = 0xc, + DMAC_CACHE_BUFF_NONPRIV_DATA = 0xd, + DMAC_CACHE_BUFF_PRIV_OPCODE = 0xe, + DMAC_CACHE_BUFF_PRIV_DATA = 0xf +} dmac_prot_level_t; + +typedef enum _dmac_fifo_mode +{ + DMAC_FIFO_MODE_SINGLE = 0x0, + DMAC_FIFO_MODE_HALF = 0x1 +} dmac_fifo_mode_t; + +typedef enum _dw_dmac_flow_ctl_mode +{ + DMAC_DATA_PREFETCH_ENABLED = 0x0, + DMAC_DATA_PREFETCH_DISABLED = 0x1 +} dw_dmac_flow_ctl_mode_t; + +typedef enum _dmac_polarity_level +{ + DMAC_ACTIVE_HIGH = 0x0, + DMAC_ACTIVE_LOW = 0x1 +} dmac_polarity_level_t; + +typedef enum _dmac_lock_level +{ + DMAC_LOCK_LEVEL_DMA_TRANSFER = 0x0, + DMAC_LOCK_LEVEL_BLOCK_TRANSFER = 0x1, + DMAC_LOCK_LEVEL_TRANSACTION = 0x2 +} dmac_lock_level_t; + +typedef enum _dmac_channel_priority +{ + DMAC_PRIORITY_0 = 0x0, + DMAC_PRIORITY_1 = 0x1, + DMAC_PRIORITY_2 = 0x2, + DMAC_PRIORITY_3 = 0x3, + DMAC_PRIORITY_4 = 0x4, + DMAC_PRIORITY_5 = 0x5, + DMAC_PRIORITY_6 = 0x6, + DMAC_PRIORITY_7 = 0x7 +} dmac_channel_priority_t; + +typedef enum _dmac_state +{ + ZERO, + ONE +} dmac_state_t; + +typedef enum _dmac_common_int +{ + SLVIF_COMMON_DEC_ERR = 0, + SLVIF_COMMON_WR2RO_ERR = 1, + SLVIF_COMMON_RD2WO_ERR = 2, + SLVIF_COMMON__WRONHOLD_ERR = 3, + SLVIF_UNDEFINED_DEC_ERR = 4, + SLVIF_ALL_INT = 5 +} dmac_common_int_t; + +typedef struct _dmac_cfg +{ + /** + * Bit 0 is used to enable dmac + * 0x1 for enable, 0x0 for disable + */ + uint64_t dmac_en : 1; + /** + * Bit 1 is used to glabally enable interrupt generation + * 0x1 for enable interrupt, 0x0 for disable interrupt + */ + uint64_t int_en : 1; + /* Bits [63:2] is reserved */ + uint64_t rsvd : 62; +} __attribute__((packed, aligned(8))) dmac_cfg_t; + +typedef union _dmac_cfg_u +{ + dmac_cfg_t cfg; + uint64_t data; +} dmac_cfg_u_t; + +typedef struct _damc_chen +{ + /** + * Bit 0 is used to enable channel 1 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch1_en : 1; + /** + * Bit 1 is used to enable channel 2 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch2_en : 1; + /** + * Bit 2 is used to enable channel 3 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch3_en : 1; + /** + * Bit 3 is used to enable channel 4 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch4_en : 1; + /** + * Bit 4 is used to enable channel 5 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch5_en : 1; + /** + * Bit 5 is used to enable channel 6 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch6_en : 1; + /* Bits [7:6] is reserved */ + uint64_t rsvd1 : 2; + /** + * Bit 8 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch1_en_we : 1; + /** + * Bit 9 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch2_en_we : 1; + /** + * Bit 10 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch3_en_we : 1; + /** + * Bit 11 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch4_en_we : 1; + /** + * Bit 12 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch5_en_we : 1; + /** + * Bit 13 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch6_en_we : 1; + /* Bits [15:14] is reserved */ + uint64_t rsvd2 : 2; + /** + * Bit 16 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch1_susp : 1; + /** + * Bit 17 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch2_susp : 1; + /* Bit 18 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch3_susp : 1; + /** + * Bit 19 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch4_susp : 1; + /** + * Bit 20 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch5_susp : 1; + /** + * Bit 21 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch6_susp : 1; + /* Bits [23:22] is reserved */ + uint64_t rsvd3 : 2; + /** + * Bit 24 is write enable to the channel suspend bit + * 0x1 for enable write to CH1_SUSP bit + * 0x0 for disable write to CH1_SUSP bit + */ + uint64_t ch1_susp_we : 1; + /** + * Bit 25 is write enable to the channel suspend bit + * 0x1 for enable write to CH2_SUSP bit + * 0x0 for disable write to CH2_SUSP bit + */ + uint64_t ch2_susp_we : 1; + /** + * Bit 26 is write enable to the channel suspend bit + * 0x1 for enable write to CH3_SUSP bit + * 0x0 for disable write to CH3_SUSP bit + */ + uint64_t ch3_susp_we : 1; + /** + * Bit 27 is write enable to the channel suspend bit + * 0x1 for enable write to CH4_SUSP bit + * 0x0 for disable write to CH4_SUSP bit + */ + uint64_t ch4_susp_we : 1; + /** + * Bit 28 is write enable to the channel suspend bit + * 0x1 for enable write to CH5_SUSP bit + * 0x0 for disable write to CH5_SUSP bit + */ + uint64_t ch5_susp_we : 1; + /** + * Bit 29 is write enable to the channel suspend bit + * 0x1 for enable write to CH6_SUSP bit + * 0x0 for disable write to CH6_SUSP bit + */ + uint64_t ch6_susp_we : 1; + /* Bits [31:30] is reserved */ + uint64_t rsvd4 : 2; + /** + * Bit 32 is channel-1 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch1_abort : 1; + /** + * Bit 33 is channel-2 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch2_abort : 1; + /** + * Bit 34 is channel-3 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch3_abort : 1; + /** + * Bit 35 is channel-4 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch4_abort : 1; + /** + * Bit 36 is channel-5 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch5_abort : 1; + /** + * Bit 37 is channel-6 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch6_abort : 1; + /* Bits [39:38] is reserved */ + uint64_t rsvd5 : 2; + /** + * Bit 40 is ued to write enable channel-1 abort bit + * 0x1 for enable write to CH1_ABORT bit + * 0x0 for disable write to CH1_ABORT bit + */ + uint64_t ch1_abort_we : 1; + /** + * Bit 41 is ued to write enable channel-2 abort bit + * 0x1 for enable write to CH2_ABORT bit + * 0x0 for disable write to CH2_ABORT bit + */ + uint64_t ch2_abort_we : 1; + /** + * Bit 42 is ued to write enable channel-3 abort bit + * 0x1 for enable write to CH3_ABORT bit + * 0x0 for disable write to CH3_ABORT bit + */ + uint64_t ch3_abort_we : 1; + /** + * Bit 43 is ued to write enable channel-4 abort bit + * 0x1 for enable write to CH4_ABORT bit + * 0x0 for disable write to CH4_ABORT bit + */ + uint64_t ch4_abort_we : 1; + /** + * Bit 44 is ued to write enable channel-5 abort bit + * 0x1 for enable write to CH5_ABORT bit + * 0x0 for disable write to CH5_ABORT bit + */ + uint64_t ch5_abort_we : 1; + /** + * Bit 45 is ued to write enable channel-6 abort bit + * 0x1 for enable write to CH6_ABORT bit + * 0x0 for disable write to CH6_ABORT bit + */ + uint64_t ch6_abort_we : 1; + /* Bits [47:46] is reserved */ + uint64_t rsvd6 : 2; + /* Bits [63:48] is reserved */ + uint64_t rsvd7 : 16; +} __attribute__((packed, aligned(8))) damc_chen_t; + +typedef union _dmac_chen_u +{ + damc_chen_t dmac_chen; + uint64_t data; +} dmac_chen_u_t; + +typedef struct _dmac_intstatus +{ + /** + * Bit 0 is channel 1 interrupt bit + * 0x1 for channel 1 interrupt active + * 0x0 for channel 1 interrupt inactive + */ + uint64_t ch1_intstat : 1; + /** + * Bit 1 is channel 1 interrupt bit + * 0x1 for channel 2 interrupt active + * 0x0 for channel 2 interrupt inactive + */ + uint64_t ch2_intstat : 1; + /** + * Bit 2 is channel 3 interrupt bit + * 0x1 for channel 3 interrupt active + * 0x0 for channel 3 interrupt inactive + */ + uint64_t ch3_intstat : 1; + /** + * Bit 3 is channel 4 interrupt bit + * 0x1 for channel 4 interrupt active + * 0x0 for channel 4 interrupt inactive + */ + uint64_t ch4_intstat : 1; + /** + * Bit 4 is channel 5 interrupt bit + * 0x1 for channel 5 interrupt active + * 0x0 for channel 5 interrupt inactive + */ + uint64_t ch5_intstat : 1; + /** + * Bit 5 is channel 6 interrupt bit + * 0x1 for channel 6 interrupt active + * 0x0 for channel 6 interrupt inactive + */ + uint64_t ch6_intstat : 1; + /* Bits [15:6] is reserved */ + uint64_t rsvd1 : 10; + /** + * Bit 16 is commom register status bit + * 0x1 for common register interrupt is active + * 0x0 for common register interrupt inactive + */ + uint64_t commonreg_intstat : 1; + /* Bits [63:17] is reserved */ + uint64_t rsvd2 : 47; +} __attribute__((packed, aligned(8))) dmac_intstatus_t; + +typedef union _dmac_intstatus_u +{ + dmac_intstatus_t intstatus; + uint64_t data; +} dmac_intstatus_u_t; + +typedef struct _dmac_commonreg_intclear +{ + /** + * Bit 0 is slave nterface Common Register + * Decode Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_DEC_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t cear_slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write + * to Read only Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_WR2RO_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_wr2ro_err_intstat : 1; + /** + * Bit 2 is Slave Interface Common Register Read to + * Write only Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_RD2WO_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write + * On Hold Error Interrupt clear Bit + * x01 for clear SSLVIF_CommonReg_WrOnHold_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_wronhold_err_intstat : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register + * Decode Error Interrupt clear Bit + * x01 for clear SLVIF_UndefinedReg_DEC_ERRinterrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))) dmac_commonreg_intclear_t; + +typedef union _dmac_commonreg_intclear_u +{ + dmac_commonreg_intclear_t com_intclear; + uint64_t data; +} dmac_commonreg_intclear_u_t; + +typedef struct _dmac_commonreg_intstatus_enable +{ + /** + * Bit 0 is Slave Interface Common Register Decode Error + * Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_DEC_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_DEC_ERR_IntStat bit disable + */ + uint64_t enable_slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read + * only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_WR2RO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_WR2RO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_wr2ro_err_intstat : 1; + /*!< + * Bit 2 is Slave Interface Common Register Read to Write + * only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write On Hold + * Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_WrOnHold_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_WrOnHold_ERR_IntStat bit disable + */ + uint64_t enable_slvif_wronhold_err_intstat : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode + * Error Interrupt Status enable Bit + * 0x1 for SLVIF_UndefinedReg_DEC_ERR_IntStat bit enable + * 0x0 for SLVIF_UndefinedReg_DEC_ERR_IntStat disable + */ + uint64_t enable_slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))) dmac_commonreg_intstatus_enable_t; + +typedef union _dmac_commonreg_intstatus_enable_u +{ + dmac_commonreg_intstatus_enable_t intstatus_enable; + uint64_t data; +} dmac_commonreg_intstatus_enable_u_t; + +typedef struct _dmac_commonreg_intsignal_enable +{ + /** + * Bit 0 is Slave Interface Common Register Decode Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_DEC_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_DEC_ERR_IntStat signal disable + */ + uint64_t enable_slvif_dec_err_intsignal : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read only + * Error Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_WR2RO_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_WR2RO_ERR_IntStat signal disable + */ + uint64_t enable_slvif_wr2ro_err_intsignal : 1; + /** + * Bit 2 is Slave Interface Common Register Read to + * Write only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_rd2wo_err_intsignal : 1; + /** + * Bit 3 is Slave Interface Common Register Write On Hold Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_WrOnHold_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_WrOnHold_ERR_IntStat signal disable + */ + uint64_t enable_slvif_wronhold_err_intsignal : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_UndefinedReg_DEC_ERR_IntStat signal enable + * 0x0 for SLVIF_UndefinedReg_DEC_ERR_IntStat signal disable + */ + uint64_t enable_slvif_undefinedreg_dec_err_intsignal : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))) dmac_commonreg_intsignal_enable_t; + +typedef union _dmac_commonreg_intsignal_enable_u +{ + dmac_commonreg_intsignal_enable_t intsignal_enable; + uint64_t data; +} dmac_commonreg_intsignal_enable_u_t; + +typedef struct _dmac_commonreg_intstatus +{ + /** + * Bit 0 is Slave Interface Common Register Decode + * Error Interrupt Status Bit + * 0x1 for Slave Interface Decode Error detected + * 0x0 for No Slave Interface Decode Errors + */ + uint64_t slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read Only + * Error Interrupt Status bit + * 0x1 for Slave Interface Write to Read Only Error detected + * 0x0 No Slave Interface Write to Read Only Errors + */ + uint64_t slvif_wr2ro_err_intstat : 1; + /** + * Bit 2 is Slave Interface Common Register Read to Write + * only Error Interrupt Status bit + * 0x1 for Slave Interface Read to Write Only Error detected + * 0x0 for No Slave Interface Read to Write Only Errors + */ + uint64_t slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write On + * Hold Error Interrupt Status Bit + * 0x1 for Slave Interface Common Register Write On Hold Error detected + * 0x0 for No Slave Interface Common Register Write On Hold Errors + */ + uint64_t slvif_wronhold_err_intstat : 1; + /*!< Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode + * Error Interrupt Signal Enable Bit + * 0x1 for Slave Interface Decode Error detected + * 0x0 for No Slave Interface Decode Errors + */ + uint64_t slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))) dmac_commonreg_intstatus_t; + +typedef union _dmac_commonreg_intstatus_u +{ + dmac_commonreg_intstatus_t commonreg_intstatus; + uint64_t data; +} dmac_commonreg_intstatus_u_t; + +typedef struct _dmac_reset +{ + /* Bit 0 is DMAC reset request bit */ + uint64_t rst : 1; + /* Bits [63:1] is reserved */ + uint64_t rsvd : 63; +} __attribute__((packed, aligned(8))) dmac_reset_t; + +typedef union _dmac_reset_u +{ + dmac_reset_t reset; + uint64_t data; +} dmac_reset_u_t; + +typedef struct _dmac_ch_block_ts +{ + uint64_t block_ts : 22; + /*!< Bit [21:0] is block transfer size*/ + uint64_t rsvd : 42; + /*!< Bits [63:22] is reserved */ +} __attribute__((packed, aligned(8))) dmac_ch_block_ts_t; + +typedef union _dmac_ch_block_ts_u +{ + dmac_ch_block_ts_t block_ts; + uint64_t data; +} dmac_ch_block_ts_u_t; + +typedef struct _dmac_ch_ctl +{ + /** + * Bit 0 is source master select + * 1 for AXI master 2, 0 for AXI master 1 + */ + uint64_t sms : 1; + /* Bit 1 is reserved */ + uint64_t rsvd1 : 1; + /** + * Bit 2 is destination master select + * 0x1 for AXI master 2,0x0 for AXI master 1 + */ + uint64_t dms : 1; + /* Bit 3 is reserved */ + uint64_t rsvd2 : 1; + /** + * Bit 4 is source address increment + * 0x1 for no change, 0x0 for incremnet + */ + uint64_t sinc : 1; + /** + * Bit 5 is reserved + */ + uint64_t rsvd3 : 1; + /** + * Bit 6 is destination address incremnet + * 0x1 for no change, 0x0 for increment + */ + uint64_t dinc : 1; + /* Bit 7 is reserved*/ + uint64_t rsvd4 : 1; + /** + * Bits [10:8] is source transfer width + * 0x0 for source transfer width is 8 bits + * 0x1 for source transfer width is 16 bits + * 0x2 for source transfer width is 32 bits + * 0x3 for source transfer width is 64 bits + * 0x4 for source transfer width is 128 bits + * 0x5 for source transfer width is 256 bits + * 0x6 for source transfer width is 512 bits + */ + uint64_t src_tr_width : 3; + /** + * Bits [13:11] is detination transfer width + * 0x0 for detination transfer width is 8 bits + * 0x1 for detination transfer width is 16 bits + * 0x2 for detination transfer width is 32 bits + * 0x3 for detination transfer width is 64 bits + * 0x4 for detination transfer width is 128 bits + * 0x5 for detination transfer width is 256 bits + * 0x6 for detination transfer width is 512 bits + */ + uint64_t dst_tr_width : 3; + /** + * Bits [17:14] is source burst transaction length + * 0x0 for 1 data item read from rource in the burst transaction + * 0x1 for 4 data item read from rource in the burst transaction + * 0x2 for 8 data item read from rource in the burst transaction + * 0x3 for 16 data item read from rource in the burst transaction + * 0x4 for 32 data item read from rource in the burst transaction + * 0x5 for 64 data item read from rource in the burst transaction + * 0x6 for 128 data item read from rource in the burst transaction + * 0x7 for 256 data item read from rource in the burst transaction + * 0x8 for 512 data item read from rource in the burst transaction + * 0x9 for 1024 data item read from rource in the burst transaction + */ + uint64_t src_msize : 4; + /** + * Bits [17:14] is sdestination burst transaction length + * 0x0 for 1 data item read from rource in the burst transaction + * 0x1 for 4 data item read from rource in the burst transaction + * 0x2 for 8 data item read from rource in the burst transaction + * 0x3 for 16 data item read from rource in the burst transaction + * 0x4 for 32 data item read from rource in the burst transaction + * 0x5 for 64 data item read from rource in the burst transaction + * 0x6 for 128 data item read from rource in the burst transaction + * 0x7 for 256 data item read from rource in the burst transaction + * 0x8 for 512 data item read from rource in the burst transaction + * 0x9 for 1024 data item read from rource in the burst transaction + */ + uint64_t dst_msize : 4; + /** + * Bits [25:22] is reserved + */ + uint64_t rsvd5 : 4; + /*!< Bits [29:26] is reserved */ + uint64_t rsvd6 : 4; + /** + * Bit 30 is Non Posted Last Write Enable + * 0x1 for posted writes may be used till the end of the block + * 0x 0 for posted writes may be used throughout the block transfer + */ + uint64_t nonposted_lastwrite_en : 1; + /* Bit 31 is resrved */ + uint64_t rsvd7 : 1; + /* Bits [34:32] is reserved*/ + uint64_t rsvd8 : 3; + /* Bits [37:35] is reserved*/ + uint64_t rsvd9 : 3; + /** + * Bit 38 is source burst length enable + * 1 for enable, 0 for disable + */ + uint64_t arlen_en : 1; + /* Bits [46:39] is source burst length*/ + uint64_t arlen : 8; + /** + * Bit 47 is destination burst length enable + * 1 for enable, 0 for disable + */ + uint64_t awlen_en : 1; + /* Bits [55:48] is destination burst length */ + uint64_t awlen : 8; + /** + * Bit 56 is source status enable + * 0x1 for enable, 0x0 for disable + */ + uint64_t src_stat_en : 1; + /** + * Bit 57 is destination status enable + * 0x1 for enable, 0x0 for disable + */ + uint64_t dst_stat_en : 1; + /** + * Bit 58 is interrupt completion of block transfer + * 0x1 for enable CHx_IntStatusReg.BLOCK_TFR_DONE_IntStat field + * 0x0 for dsiable CHx_IntStatusReg.BLOCK_TFR_DONE_IntStat field + */ + uint64_t ioc_blktfr : 1; + /** + * Bits [61:59] is reserved + */ + uint64_t rsvd10 : 3; + /** + * Bit 62 is last shadow linked list item + * 0x1 for indicate shadowreg/LLI content is the last one + * 0x0 for indicate shadowreg/LLI content not the last one + */ + uint64_t shadowreg_or_lli_last : 1; + /** + * Bit 63 is last shadow linked list item valid + * 0x1 for indicate shadowreg/LLI content is valid + * 0x0 for indicate shadowreg/LLI content is invalid + */ + uint64_t shadowreg_or_lli_valid : 1; +} __attribute__((packed, aligned(8))) dmac_ch_ctl_t; + +typedef union _dmac_ch_ctl_u +{ + dmac_ch_ctl_t ch_ctl; + uint64_t data; +} dmac_ch_ctl_u_t; + +typedef struct _dmac_ch_cfg +{ + /** + * Bit[1:0] is source multi block transfer type + * 0x0 for continuous multiblock type + * 0x1 for reload multiblock type + * 0x2 for shadow register based multiblock type + * 0x3 for linked lisr bases multiblock type + */ + uint64_t src_multblk_type : 2; + /** + * Bit[3:2] is source multi block transfer type + * 0x0 for continuous multiblock type + * 0x1 for reload multiblock type + * 0x2 for shadow register based multiblock type + * 0x3 for linked lisr bases multiblock type + */ + uint64_t dst_multblk_type : 2; + /* Bits [31:4] is reserved*/ + uint64_t rsvd1 : 28; + /** + * Bits [34:32] is transfer type and flow control + * 0x0 transfer memory to memory and flow controler is dmac + * 0x1 transfer memory to peripheral and flow controler is dmac + * 0x2 transfer peripheral to memory and flow controler is dmac + * 0x3 transfer peripheral to peripheral and flow controler is dmac + * 0x4 transfer peripheral to memory and flow controler is + * source peripheral + * 0x5 transfer peripheral to peripheral and flow controler + * is source peripheral + * 0x6 transfer memory to peripheral and flow controler is + * destination peripheral + * 0x7 transfer peripheral to peripheral and flow controler + * is destination peripheral + */ + uint64_t tt_fc : 3; + /** + * Bit 35 is source software or hardware handshaking select + * 0x1 for software handshaking is used + * 0x0 for hardware handshaking is used + */ + uint64_t hs_sel_src : 1; + /** + * Bit 36 is destination software or hardware handshaking select + *0x1 for software handshaking is used + *0x0 for hardware handshaking is used + */ + uint64_t hs_sel_dst : 1; + /** + * Bit 37 is sorce hardware handshaking interface polarity + * 0x1 active low, 0x0 active high + */ + uint64_t src_hwhs_pol : 1; + /** + * Bit 38 is destination hardware handshaking interface polarity + * 0x1 active low, 0x0 active high + */ + uint64_t dst_hwhs_pol : 1; + /** + * Bits [41:39] is assign a hardware handshaking interface + * to source of channel x + */ + uint64_t src_per : 4; + /* Bit 43 is reserved*/ + uint64_t rsvd3 : 1; + /** + * Bits [46:44] is assign a hardware handshaking interface + * to destination of channel x + */ + uint64_t dst_per : 4; + /* Bit 48 is reserved*/ + uint64_t rsvd5 : 1; + /* Bits [51:49] is channel priority,7 is highest, 0 is lowest*/ + uint64_t ch_prior : 3; + /** + * Bit 52 is channel lock bit + * 0x0 for channel is not locked, 0x1 for channel is locked + */ + uint64_t lock_ch : 1; + /** + * Bits [54:53] is chnannel lock level + * 0x0 for duration of channel is locked for entire DMA transfer + * 0x1 for duration of channel is locked for current block transfer + */ + uint64_t lock_ch_l : 2; + uint64_t src_osr_lmt : 4; + /* Bits [58:55] is source outstanding request limit */ + uint64_t dst_osr_lmt : 4; + /* Bits [62:59] is destination outstanding request limit */ +} __attribute__((packed, aligned(8))) dmac_ch_cfg_t; + +typedef union _dmac_ch_cfg_u +{ + dmac_ch_cfg_t ch_cfg; + uint64_t data; +} dmac_ch_cfg_u_t; + +typedef struct _dmac_ch_llp +{ + /** + * Bit 0 is LLI master select + * 0x0 for next linked list item resides on AXI madster1 interface + * 0x1 for next linked list item resides on AXI madster2 interface + */ + uint64_t lms : 1; + /* Bits [5:1] is reserved */ + uint64_t rsvd1 : 5; + /* Bits [63:6] is starting address memeory of LLI block */ + uint64_t loc : 58; +} __attribute__((packed, aligned(8))) dmac_ch_llp_t; + +typedef union _dmac_ch_llp_u +{ + dmac_ch_llp_t llp; + uint64_t data; +} dmac_ch_llp_u_t; + +typedef struct _dmac_ch_status +{ + /* Bits [21:0] is completed block transfer size */ + uint64_t cmpltd_blk_size : 22; + /* Bits [46:32] is reserved */ + uint64_t rsvd1 : 15; + /* Bits [63:47] is reserved */ + uint64_t rsvd2 : 17; +} __attribute__((packed, aligned(8))) dmac_ch_status_t; + +typedef union _dmac_ch_status_u +{ + dmac_ch_status_t status; + uint64_t data; +} dmac_ch_status_u_t; + +typedef struct _dmac_ch_swhssrc +{ + /** + * Bit 0 is software handshake request for channel source + * 0x1 source periphraral request for a dma transfer + * 0x0 source peripheral is not request for a burst transfer + */ + uint64_t swhs_req_src : 1; + /** + * Bit 1 is write enable bit for software handshake request + *0x1 for enable, 0x0 for disable + */ + uint64_t swhs_req_src_we : 1; + /** + * Bit 2 is software handshake single request for channel source + * 0x1 for source peripheral requesr for a single dma transfer + * 0x0 for source peripheral is not requesting for a single transfer + */ + uint64_t swhs_sglreq_src : 1; + /** + * Bit 3 is write enable bit for software handshake + * single request for channle source + * 0x1 for enable write, 0x0 for disable write + */ + uint64_t swhs_sglreq_src_we : 1; + /** + * Bit 4 software handshake last request for channel source + * 0x1 for current transfer is last transfer + * 0x0 for current transfer is not the last transfer + */ + uint64_t swhs_lst_src : 1; + /** + * Bit 5 is write enable bit for software + * handshake last request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_lst_src_we : 1; + /* Bits [63:6] is reserved */ + uint64_t rsvd : 58; +} __attribute__((packed, aligned(8))) dmac_ch_swhssrc_t; + +typedef union _dmac_ch_swhssrc_u +{ + dmac_ch_swhssrc_t swhssrc; + uint64_t data; +} dmac_ch_swhssrc_u_t; + +typedef struct _dmac_ch_swhsdst +{ + /** + * Bit 0 is software handshake request for channel destination + * 0x1 destination periphraral request for a dma transfer + * 0x0 destination peripheral is not request for a burst transfer + */ + uint64_t swhs_req_dst : 1; + /** + * Bit 1 is write enable bit for software handshake request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_req_dst_we : 1; + /** + * Bit 2 is software handshake single request for channel destination + * 0x1 for destination peripheral requesr for a single dma transfer + * 0x0 for destination peripheral is not requesting + * for a single transfer + */ + uint64_t swhs_sglreq_dst : 1; + /** + * Bit 3 is write enable bit for software handshake + * single request for channle destination + * 0x1 for enable write, 0x0 for disable write + */ + uint64_t swhs_sglreq_dst_we : 1; + /** + * Bit 4 software handshake last request for channel dstination + * 0x1 for current transfer is last transfer + * 0x0 for current transfer is not the last transfer + */ + uint64_t swhs_lst_dst : 1; + /** + * Bit 5 is write enable bit for software handshake last request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_lst_dst_we : 1; + /* Bits [63:6] is reserved */ + uint64_t rsvd : 58; +} __attribute__((packed, aligned(8))) dmac_ch_swhsdst_t; + +typedef union _dmac_ch_swhsdst_u +{ + dmac_ch_swhsdst_t swhsdst; + uint64_t data; +} dmac_ch_swhsdst_u_t; + +typedef struct _dmac_ch_blk_tfr_resumereq +{ + /** + * Bit 0 is block transfer resume request bit + * 0x1 for request for resuming + * 0x0 for no request to resume + */ + uint64_t blk_tfr_resumereq : 1; + /* Bits [63:1] is reserved */ + uint64_t rsvd : 63; +} __attribute__((packed, aligned(8))) dmac_ch_blk_tfr_resumereq_t; + +typedef union _dmac_ch_blk_tfr_resumereq_u +{ + dmac_ch_blk_tfr_resumereq_t blk_tfr_resumereq; + uint64_t data; +} dmac_ch_blk_tfr_resumereq_u_t; + +typedef struct _dmac_ch_intstatus_enable +{ + /* Bit 0 is block transfer done interrupt status enable */ + uint64_t enable_block_tfr_done_intstatus : 1; + /* DMA transfer done interrupt status enable */ + uint64_t enable_dma_tfr_done_intstat : 1; + /* Bit 2 reserved */ + uint64_t rsvd1 : 1; + /* Bit 3 source transaction complete status enable */ + uint64_t enable_src_transcomp_intstat : 1; + /* Bit 4 destination transaction complete */ + uint64_t enable_dst_transcomp_intstat : 1; + /* Bit 5 Source Decode Error Status Enable */ + uint64_t enable_src_dec_err_intstat : 1; + /* Bit 6 Destination Decode Error Status Enable */ + uint64_t enable_dst_dec_err_intstat : 1; + /* Bit 7 Source Slave Error Status Enable */ + uint64_t enable_src_slv_err_intstat : 1; + /* Bit 8 Destination Slave Error Status Enable */ + uint64_t enable_dst_slv_err_intstat : 1; + /* Bit 9 LLI Read Decode Error Status Enable */ + uint64_t enable_lli_rd_dec_err_intstat : 1; + /* Bit 10 LLI WRITE Decode Error Status Enable */ + uint64_t enable_lli_wr_dec_err_intstat : 1; + /* Bit 11 LLI Read Slave Error Status Enable */ + uint64_t enable_lli_rd_slv_err_intstat : 1; + /* Bit 12 LLI WRITE Slave Error Status Enable */ + uint64_t enable_lli_wr_slv_err_intstat : 1; + uint64_t rsvd2 : 51; +} dmac_ch_intstatus_enable_t; + +typedef union _dmac_ch_intstatus_enable_u +{ + dmac_ch_intstatus_enable_t ch_intstatus_enable; + uint64_t data; +} dmac_ch_intstatus_enable_u_t; + +typedef struct _dmac_ch_intclear +{ + /* Bit 0 block transfer done interrupt clear bit.*/ + uint64_t blk_tfr_done_intstat : 1; + /* Bit 1 DMA transfer done interrupt clear bit */ + uint64_t dma_tfr_done_intstat : 1; + /* Bit 2 is reserved */ + uint64_t resv1 : 1; + uint64_t resv2 : 61; +} __attribute__((packed, aligned(8))) dmac_ch_intclear_t; + +typedef union _dmac_ch_intclear_u +{ + uint64_t data; + dmac_ch_intclear_t intclear; +} dmac_ch_intclear_u_t; + +typedef struct _dmac_channel +{ + /* (0x100) SAR Address Register */ + uint64_t sar; + /* (0x108) DAR Address Register */ + uint64_t dar; + /* (0x110) Block Transfer Size Register */ + uint64_t block_ts; + /* (0x118) Control Register */ + uint64_t ctl; + /* (0x120) Configure Register */ + uint64_t cfg; + /* (0x128) Linked List Pointer register */ + uint64_t llp; + /* (0x130) Channelx Status Register */ + uint64_t status; + /* (0x138) Channelx Software handshake Source Register */ + uint64_t swhssrc; + /* (0x140) Channelx Software handshake Destination Register */ + uint64_t swhsdst; + /* (0x148) Channelx Block Transfer Resume Request Register */ + uint64_t blk_tfr; + /* (0x150) Channelx AXI ID Register */ + uint64_t axi_id; + /* (0x158) Channelx AXI QOS Register */ + uint64_t axi_qos; + /* Reserved address */ + uint64_t reserved1[4]; + /* (0x180) Interrupt Status Enable Register */ + uint64_t intstatus_en; + /* (0x188) Channelx Interrupt Status Register */ + uint64_t intstatus; + /* (0x190) Interrupt Siganl Enable Register */ + uint64_t intsignal_en; + /* (0x198) Interrupt Clear Register */ + uint64_t intclear; + uint64_t reserved2[12]; +} __attribute__((packed, aligned(8))) dmac_channel_t; + +typedef struct _dmac +{ + /* (0x00) DMAC ID Rgister */ + uint64_t id; + /* (0x08) DMAC COMPVER Register */ + uint64_t compver; + /* (0x10) DMAC Configure Register */ + uint64_t cfg; + /* (0x18) Channel Enable Register */ + uint64_t chen; + uint64_t reserved1[2]; + /* (0x30) DMAC Interrupt Status Register */ + uint64_t intstatus; + /* (0x38) DMAC Common register Interrupt Status Register */ + uint64_t com_intclear; + /* (0x40) DMAC Common Interrupt Enable Register */ + uint64_t com_intstatus_en; + /* (0x48) DMAC Common Interrupt Signal Enable Register */ + uint64_t com_intsignal_en; + /* (0x50) DMAC Common Interrupt Status */ + uint64_t com_intstatus; + /* (0x58) DMAC Reset register */ + uint64_t reset; + uint64_t reserved2[20]; + dmac_channel_t channel[DMAC_CHANNEL_COUNT]; +} __attribute__((packed, aligned(8))) dmac_t; + +typedef struct _dmac_channel_config +{ + uint64_t sar; + uint64_t dar; + uint8_t ctl_sms; + uint8_t ctl_dms; + uint8_t ctl_src_msize; + uint8_t ctl_drc_msize; + uint8_t ctl_sinc; + uint8_t ctl_dinc; + uint8_t ctl_src_tr_width; + uint8_t ctl_dst_tr_width; + uint8_t ctl_ioc_blktfr; + uint8_t ctl_src_stat_en; + uint8_t ctl_dst_stat_en; + uint8_t cfg_dst_per; + uint8_t cfg_src_per; + uint8_t cfg_src_hs_pol; + uint8_t cfg_dst_hs_pol; + uint8_t cfg_hs_sel_src; + uint8_t cfg_hs_sel_dst; + uint64_t cfg_src_multblk_type; + uint64_t cfg_dst_multblk_type; + uint64_t llp_loc; + uint8_t llp_lms; + uint64_t ctl_block_ts; + uint8_t ctl_tt_fc; + uint8_t cfg_protctl; + uint8_t cfg_fifo_mode; + uint8_t cfg_fcmode; + uint8_t cfg_lock_ch_l; + uint8_t cfg_ch_prior; +} dmac_channel_config_t; + +#define LIST_ENTRY(ptr, type, member) \ + ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) + +struct list_head_t +{ + struct list_head_t *next, *prev; +}; + +/** + * @brief Dmac.data/dw_dmac_lli_item + * + * @desc This structure is used when creating Linked List Items. + * + * @see dw_dmac_addLliItem() + */ +typedef struct _dmac_lli_item +{ + uint64_t sar; + uint64_t dar; + uint64_t ch_block_ts; + uint64_t llp; + uint64_t ctl; + uint64_t sstat; + uint64_t dstat; + uint64_t resv; +} __attribute__((packed, aligned(64))) dmac_lli_item_t; + +extern volatile dmac_t *const dmac; + +/** + * @brief Dmac initialize + */ +void DmacInit(void); + +/** + * @brief Set dmac param + * + * @param[in] channel_num Dmac channel + * @param[in] src Dmac source + * @param[in] dest Dmac dest + * @param[in] src_inc Source address increase or not + * @param[in] dest_inc Dest address increase or not + * @param[in] dmac_burst_size Dmac burst length + * @param[in] dmac_trans_width Dmac transfer data width + * @param[in] BlockSize Dmac transfer length + * + */ +void dmac_set_single_mode(dmac_channel_number_t channel_num, + const void *src, void *dest, dmac_address_increment_t src_inc, + dmac_address_increment_t dest_inc, + dmac_burst_trans_length_t dmac_burst_size, + dmac_transfer_width_t dmac_trans_width, + size_t BlockSize); + +/** + * @brief Determine the transfer is complete or not + * + * @param[in] channel_num Dmac channel + * + * @return result + * - 0 uncompleted + * - 1 completed +*/ +int dmac_is_done(dmac_channel_number_t channel_num); + +/** + * @brief Wait for dmac work done + * + * @param[in] channel_num Dmac channel + * + */ +void dmac_wait_done(dmac_channel_number_t channel_num); + +/** + * @brief Determine the dma is idle or not + * + * @param[in] channel_num Dmac channel + * + * @return result + * - 0 busy + * - 1 idel +*/ +int dmac_is_idle(dmac_channel_number_t channel_num); + +/** + * @brief Wait for dmac idle + * + * @param[in] channel_num Dmac channel + * + */ +void dmac_wait_idle(dmac_channel_number_t channel_num); + +/** + * @brief Set interrupt param + * + * @param[in] channel_num Dmac channel + * @param[in] dmac_callback Dmac interrupt callback + * @param[in] ctx The param of callback + * @param[in] priority Interrupt priority + */ +void dmac_set_irq(dmac_channel_number_t channel_num , plic_irq_callback_t dmac_callback, void *ctx, uint32_t priority); + +/** + * @brief Set interrupt param + * + * @param[in] channel_num Dmac channel + * @param[in] dmac_callback Dmac interrupt callback + * @param[in] ctx The param of callback + * @param[in] priority Interrupt priority + */ +void dmac_irq_register(dmac_channel_number_t channel_num , plic_irq_callback_t dmac_callback, void *ctx, uint32_t priority); + + +/** + * @brief Unregister dmac interrupt + * + * @param[in] channel_num Dmac channel + * + */ +void dmac_irq_unregister(dmac_channel_number_t channel_num); + +/** + * @brief Disable dmac interrupt + * + * @param[in] channel_num Dmac channel + * + */ +void dmac_free_irq(dmac_channel_number_t channel_num); + +/** + * @brief Set source dest and length + * + * @param[in] channel_num Dmac channel + * @param[in] src Source + * @param[in] dest Dest + * @param[in] len The length of dmac transfer + */ +void dmac_set_src_dest_length(dmac_channel_number_t channel_num, const void *src, void *dest, size_t len); + +/** + * @brief Disable dmac channel interrupt + * + * @param[in] channel_num Dmac channel + * +*/ +void dmac_disable_channel_interrupt(dmac_channel_number_t channel_num); + +/** + * @brief Disable dmac channel + * + * @param[in] channel_num Dmac channel + * +*/ +void dmac_channel_disable(dmac_channel_number_t channel_num); + +/** + * @brief Enable dmac channel + * + * @param[in] channel_num Dmac channel + * +*/ +void dmac_channel_enable(dmac_channel_number_t channel_num); + +#ifdef __cplusplus +} +#endif + +#endif /* __DMAC_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/drv_io_config.h b/board/k210-emulator/third_party_driver/include/drv_io_config.h new file mode 100644 index 00000000..f11c1f19 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/drv_io_config.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-03-19 ZYH first version + */ + +/** +* @file drv_io_config.h +* @brief define kd233-board io configure +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: drv_io_config.h +Description: define kd233-board io configure +Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_io_config.h for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: add kd233-board io configure define +*************************************************/ + +#ifndef __DRV_IO_CONFIG_H__ +#define __DRV_IO_CONFIG_H__ + +enum HS_GPIO_CONFIG +{ +#ifdef BSP_USING_LCD + LCD_DC_PIN = 0, /* LCD DC PIN */ +#endif +#ifdef BSP_SPI1_USING_SS0 + SPI1_CS0_PIN, +#endif +#ifdef BSP_SPI1_USING_SS1 + SPI1_CS1_PIN, +#endif +#ifdef BSP_SPI1_USING_SS2 + SPI1_CS2_PIN, +#endif +#ifdef BSP_SPI1_USING_SS3 + SPI1_CS3_PIN, +#endif + GPIO_ALLOC_START /* index of gpio driver start */ +}; + +extern int IoConfigInit(void); + +#endif diff --git a/board/k210-emulator/third_party_driver/include/dvp.h b/board/k210-emulator/third_party_driver/include/dvp.h new file mode 100644 index 00000000..18870325 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/dvp.h @@ -0,0 +1,279 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 dvp.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __DVP_H__ +#define __DVP_H__ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/** + * @brief DVP object + */ +typedef struct _dvp +{ + uint32_t dvp_cfg; + uint32_t r_addr; + uint32_t g_addr; + uint32_t b_addr; + uint32_t cmos_cfg; + uint32_t sccb_cfg; + uint32_t sccb_ctl; + uint32_t axi; + uint32_t sts; + uint32_t reverse; + uint32_t rgb_addr; +} __attribute__((packed, aligned(4))) dvp_t; + +/* DVP Config Register */ +#define DVP_CFG_START_INT_ENABLE 0x00000001U +#define DVP_CFG_FINISH_INT_ENABLE 0x00000002U +#define DVP_CFG_AI_OUTPUT_ENABLE 0x00000004U +#define DVP_CFG_DISPLAY_OUTPUT_ENABLE 0x00000008U +#define DVP_CFG_AUTO_ENABLE 0x00000010U +#define DVP_CFG_BURST_SIZE_4BEATS 0x00000100U +#define DVP_CFG_FORMAT_MASK 0x00000600U +#define DVP_CFG_RGB_FORMAT 0x00000000U +#define DVP_CFG_YUV_FORMAT 0x00000200U +#define DVP_CFG_Y_FORMAT 0x00000600U +#define DVP_CFG_HREF_BURST_NUM_MASK 0x000FF000U +#define DVP_CFG_HREF_BURST_NUM(x) ((x) << 12) +#define DVP_CFG_LINE_NUM_MASK 0x3FF00000U +#define DVP_CFG_LINE_NUM(x) ((x) << 20) + +/* DVP CMOS Config Register */ +#define DVP_CMOS_CLK_DIV_MASK 0x000000FFU +#define DVP_CMOS_CLK_DIV(x) ((x) << 0) +#define DVP_CMOS_CLK_ENABLE 0x00000100U +#define DVP_CMOS_RESET 0x00010000U +#define DVP_CMOS_POWER_DOWN 0x01000000U + +/* DVP SCCB Config Register */ +#define DVP_SCCB_BYTE_NUM_MASK 0x00000003U +#define DVP_SCCB_BYTE_NUM_2 0x00000001U +#define DVP_SCCB_BYTE_NUM_3 0x00000002U +#define DVP_SCCB_BYTE_NUM_4 0x00000003U +#define DVP_SCCB_SCL_LCNT_MASK 0x0000FF00U +#define DVP_SCCB_SCL_LCNT(x) ((x) << 8) +#define DVP_SCCB_SCL_HCNT_MASK 0x00FF0000U +#define DVP_SCCB_SCL_HCNT(x) ((x) << 16) +#define DVP_SCCB_RDATA_BYTE(x) ((x) >> 24) + +/* DVP SCCB Control Register */ +#define DVP_SCCB_WRITE_DATA_ENABLE 0x00000001U +#define DVP_SCCB_DEVICE_ADDRESS(x) ((x) << 0) +#define DVP_SCCB_REG_ADDRESS(x) ((x) << 8) +#define DVP_SCCB_WDATA_BYTE0(x) ((x) << 16) +#define DVP_SCCB_WDATA_BYTE1(x) ((x) << 24) + +/* DVP AXI Register */ +#define DVP_AXI_GM_MLEN_MASK 0x000000FFU +#define DVP_AXI_GM_MLEN_1BYTE 0x00000000U +#define DVP_AXI_GM_MLEN_4BYTE 0x00000003U + +/* DVP STS Register */ +#define DVP_STS_FRAME_START 0x00000001U +#define DVP_STS_FRAME_START_WE 0x00000002U +#define DVP_STS_FRAME_FINISH 0x00000100U +#define DVP_STS_FRAME_FINISH_WE 0x00000200U +#define DVP_STS_DVP_EN 0x00010000U +#define DVP_STS_DVP_EN_WE 0x00020000U +#define DVP_STS_SCCB_EN 0x01000000U +#define DVP_STS_SCCB_EN_WE 0x02000000U +/* clang-format on */ + +typedef enum _dvp_output_mode +{ + DVP_OUTPUT_AI, + DVP_OUTPUT_DISPLAY, +} dvp_output_mode_t; + +/** + * @brief DVP object instance + */ +extern volatile dvp_t* const dvp; + +/** + * @brief Initialize DVP + */ +void dvp_init(uint8_t reg_len); + +/** + * @brief Set image format + * + * @param[in] format The image format + */ +void dvp_set_image_format(uint32_t format); + +/** + * @brief Set image size + * + * @param[in] width The width of image + * @param[in] height The height of image + */ +void dvp_set_image_size(uint32_t width, uint32_t height); + +/** + * @brief Set the address of RGB for AI + * + * @param[in] r_addr The R address of RGB + * @param[in] g_addr The G address of RGB + * @param[in] b_addr The B address of RGB + */ +void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr); + +/** + * @brief Set the address of RGB for display + * + * @param[in] r_addr The R address of RGB + * @param[in] g_addr The G address of RGB + * @param[in] b_addr The B address of RGB + */ +void dvp_set_display_addr(uint32_t addr); + +/** + * @brief The frame start transfer + */ +void dvp_start_frame(void); + +/** + * @brief The DVP convert start + */ +void dvp_start_convert(void); + +/** + * @brief The DVP convert finish + */ +void dvp_finish_convert(void); + +/** + * @brief Get the image data + * + * @note The image data stored in the address of RGB + */ +void dvp_get_image(void); + +/** + * @brief Use SCCB write register + * + * @param[in] DevAddr The device address + * @param[in] reg_addr The register address + * @param[in] reg_data The register data + */ +void dvp_sccb_send_data(uint8_t DevAddr, uint16_t reg_addr, uint8_t reg_data); + +/** + * @brief Use SCCB read register + * + * @param[in] DevAddr The device address + * @param[in] reg_addr The register address + * + * @return The register value + */ +uint8_t dvp_sccb_receive_data(uint8_t DevAddr, uint16_t reg_addr); + +/** + * @brief Enable dvp burst + */ +void dvp_enable_burst(void); + +/** + * @brief Disable dvp burst + */ +void dvp_disable_burst(void); + +/** + * @brief Enable or disable dvp interrupt + * + * @param[in] interrupt Dvp interrupt + * @param[in] status 0:disable 1:enable + * + */ +void dvp_config_interrupt(uint32_t interrupt, uint8_t enable); + +/** + * @brief Get dvp interrupt status + * + * @param[in] interrupt Dvp interrupt + * + * + * @return Interrupt status + * - 0 false + * - 1 true + */ +int dvp_get_interrupt(uint32_t interrupt); + +/** + * @brief Clear dvp interrupt status + * + * @param[in] interrupt Dvp interrupt + * + */ +void dvp_clear_interrupt(uint32_t interrupt); + +/** + * @brief Enable dvp auto mode + */ +void dvp_enable_auto(void); + +/** + * @brief Disable dvp auto mode + */ +void dvp_disable_auto(void); + +/** + * @brief Dvp ouput data enable or not + * + * @param[in] index 0:AI, 1:display + * @param[in] enable 0:disable, 1:enable + * + */ +void dvp_set_output_enable(dvp_output_mode_t index, int enable); + +/** + * @brief Set sccb clock rate + * + * @param[in] clk_rate Sccb clock rate + * + * @return The real sccb clock rate + */ +uint32_t dvp_sccb_set_clk_rate(uint32_t clk_rate); + +/** + * @brief Set xclk rate + * + * @param[in] clk_rate xclk rate + * + * @return The real xclk rate + */ +uint32_t dvp_set_xclk_rate(uint32_t xclk_rate); + +#ifdef __cplusplus +} +#endif + +#endif /* __DVP_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/font.h b/board/k210-emulator/third_party_driver/include/font.h new file mode 100644 index 00000000..49f56027 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/font.h @@ -0,0 +1,425 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 font.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __FONT_H__ +#define __FONT_H__ +//ASCII char table +//offset 32 +//ASCII char : !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +//bytes of a single char : (size/8+((size%8)?1:0))*(size/2), size : (12/16/24/32...) code table size + +//12*12 ASCII code +const unsigned char asc2_1206[95][12]={ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ +{0x00,0x00,0x00,0x00,0x3F,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ +{0x00,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x40,0x00,0x00,0x00},/*""",2*/ +{0x09,0x00,0x0B,0xC0,0x3D,0x00,0x0B,0xC0,0x3D,0x00,0x09,0x00},/*"#",3*/ +{0x18,0xC0,0x24,0x40,0x7F,0xE0,0x22,0x40,0x31,0x80,0x00,0x00},/*"$",4*/ +{0x18,0x00,0x24,0xC0,0x1B,0x00,0x0D,0x80,0x32,0x40,0x01,0x80},/*"%",5*/ +{0x03,0x80,0x1C,0x40,0x27,0x40,0x1C,0x80,0x07,0x40,0x00,0x40},/*"&",6*/ +{0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x20,0x40,0x40,0x20},/*"(",8*/ +{0x00,0x00,0x40,0x20,0x20,0x40,0x1F,0x80,0x00,0x00,0x00,0x00},/*")",9*/ +{0x09,0x00,0x06,0x00,0x1F,0x80,0x06,0x00,0x09,0x00,0x00,0x00},/*"*",10*/ +{0x04,0x00,0x04,0x00,0x3F,0x80,0x04,0x00,0x04,0x00,0x00,0x00},/*"+",11*/ +{0x00,0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/ +{0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x00,0x00},/*"-",13*/ +{0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ +{0x00,0x20,0x01,0xC0,0x06,0x00,0x38,0x00,0x40,0x00,0x00,0x00},/*"/",15*/ +{0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"0",16*/ +{0x00,0x00,0x10,0x40,0x3F,0xC0,0x00,0x40,0x00,0x00,0x00,0x00},/*"1",17*/ +{0x18,0xC0,0x21,0x40,0x22,0x40,0x24,0x40,0x18,0x40,0x00,0x00},/*"2",18*/ +{0x10,0x80,0x20,0x40,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"3",19*/ +{0x02,0x00,0x0D,0x00,0x11,0x00,0x3F,0xC0,0x01,0x40,0x00,0x00},/*"4",20*/ +{0x3C,0x80,0x24,0x40,0x24,0x40,0x24,0x40,0x23,0x80,0x00,0x00},/*"5",21*/ +{0x1F,0x80,0x24,0x40,0x24,0x40,0x34,0x40,0x03,0x80,0x00,0x00},/*"6",22*/ +{0x30,0x00,0x20,0x00,0x27,0xC0,0x38,0x00,0x20,0x00,0x00,0x00},/*"7",23*/ +{0x1B,0x80,0x24,0x40,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"8",24*/ +{0x1C,0x00,0x22,0xC0,0x22,0x40,0x22,0x40,0x1F,0x80,0x00,0x00},/*"9",25*/ +{0x00,0x00,0x00,0x00,0x08,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/ +{0x00,0x00,0x00,0x00,0x04,0x60,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/ +{0x00,0x00,0x04,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0x40,0x40},/*"<",28*/ +{0x09,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x00,0x00},/*"=",29*/ +{0x00,0x00,0x40,0x40,0x20,0x80,0x11,0x00,0x0A,0x00,0x04,0x00},/*">",30*/ +{0x18,0x00,0x20,0x00,0x23,0x40,0x24,0x00,0x18,0x00,0x00,0x00},/*"?",31*/ +{0x1F,0x80,0x20,0x40,0x27,0x40,0x29,0x40,0x1F,0x40,0x00,0x00},/*"@",32*/ +{0x00,0x40,0x07,0xC0,0x39,0x00,0x0F,0x00,0x01,0xC0,0x00,0x40},/*"A",33*/ +{0x20,0x40,0x3F,0xC0,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"B",34*/ +{0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x30,0x80,0x00,0x00},/*"C",35*/ +{0x20,0x40,0x3F,0xC0,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"D",36*/ +{0x20,0x40,0x3F,0xC0,0x24,0x40,0x2E,0x40,0x30,0xC0,0x00,0x00},/*"E",37*/ +{0x20,0x40,0x3F,0xC0,0x24,0x40,0x2E,0x00,0x30,0x00,0x00,0x00},/*"F",38*/ +{0x0F,0x00,0x10,0x80,0x20,0x40,0x22,0x40,0x33,0x80,0x02,0x00},/*"G",39*/ +{0x20,0x40,0x3F,0xC0,0x04,0x00,0x04,0x00,0x3F,0xC0,0x20,0x40},/*"H",40*/ +{0x20,0x40,0x20,0x40,0x3F,0xC0,0x20,0x40,0x20,0x40,0x00,0x00},/*"I",41*/ +{0x00,0x60,0x20,0x20,0x20,0x20,0x3F,0xC0,0x20,0x00,0x20,0x00},/*"J",42*/ +{0x20,0x40,0x3F,0xC0,0x24,0x40,0x0B,0x00,0x30,0xC0,0x20,0x40},/*"K",43*/ +{0x20,0x40,0x3F,0xC0,0x20,0x40,0x00,0x40,0x00,0x40,0x00,0xC0},/*"L",44*/ +{0x3F,0xC0,0x3C,0x00,0x03,0xC0,0x3C,0x00,0x3F,0xC0,0x00,0x00},/*"M",45*/ +{0x20,0x40,0x3F,0xC0,0x0C,0x40,0x23,0x00,0x3F,0xC0,0x20,0x00},/*"N",46*/ +{0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"O",47*/ +{0x20,0x40,0x3F,0xC0,0x24,0x40,0x24,0x00,0x18,0x00,0x00,0x00},/*"P",48*/ +{0x1F,0x80,0x21,0x40,0x21,0x40,0x20,0xE0,0x1F,0xA0,0x00,0x00},/*"Q",49*/ +{0x20,0x40,0x3F,0xC0,0x24,0x40,0x26,0x00,0x19,0xC0,0x00,0x40},/*"R",50*/ +{0x18,0xC0,0x24,0x40,0x24,0x40,0x22,0x40,0x31,0x80,0x00,0x00},/*"S",51*/ +{0x30,0x00,0x20,0x40,0x3F,0xC0,0x20,0x40,0x30,0x00,0x00,0x00},/*"T",52*/ +{0x20,0x00,0x3F,0x80,0x00,0x40,0x00,0x40,0x3F,0x80,0x20,0x00},/*"U",53*/ +{0x20,0x00,0x3E,0x00,0x01,0xC0,0x07,0x00,0x38,0x00,0x20,0x00},/*"V",54*/ +{0x38,0x00,0x07,0xC0,0x3C,0x00,0x07,0xC0,0x38,0x00,0x00,0x00},/*"W",55*/ +{0x20,0x40,0x39,0xC0,0x06,0x00,0x39,0xC0,0x20,0x40,0x00,0x00},/*"X",56*/ +{0x20,0x00,0x38,0x40,0x07,0xC0,0x38,0x40,0x20,0x00,0x00,0x00},/*"Y",57*/ +{0x30,0x40,0x21,0xC0,0x26,0x40,0x38,0x40,0x20,0xC0,0x00,0x00},/*"Z",58*/ +{0x00,0x00,0x00,0x00,0x7F,0xE0,0x40,0x20,0x40,0x20,0x00,0x00},/*"[",59*/ +{0x00,0x00,0x70,0x00,0x0C,0x00,0x03,0x80,0x00,0x40,0x00,0x00},/*"\",60*/ +{0x00,0x00,0x40,0x20,0x40,0x20,0x7F,0xE0,0x00,0x00,0x00,0x00},/*"]",61*/ +{0x00,0x00,0x20,0x00,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x00},/*"^",62*/ +{0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10},/*"_",63*/ +{0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ +{0x00,0x00,0x02,0x80,0x05,0x40,0x05,0x40,0x03,0xC0,0x00,0x40},/*"a",65*/ +{0x20,0x00,0x3F,0xC0,0x04,0x40,0x04,0x40,0x03,0x80,0x00,0x00},/*"b",66*/ +{0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x40,0x06,0x40,0x00,0x00},/*"c",67*/ +{0x00,0x00,0x03,0x80,0x04,0x40,0x24,0x40,0x3F,0xC0,0x00,0x40},/*"d",68*/ +{0x00,0x00,0x03,0x80,0x05,0x40,0x05,0x40,0x03,0x40,0x00,0x00},/*"e",69*/ +{0x00,0x00,0x04,0x40,0x1F,0xC0,0x24,0x40,0x24,0x40,0x20,0x00},/*"f",70*/ +{0x00,0x00,0x02,0xE0,0x05,0x50,0x05,0x50,0x06,0x50,0x04,0x20},/*"g",71*/ +{0x20,0x40,0x3F,0xC0,0x04,0x40,0x04,0x00,0x03,0xC0,0x00,0x40},/*"h",72*/ +{0x00,0x00,0x04,0x40,0x27,0xC0,0x00,0x40,0x00,0x00,0x00,0x00},/*"i",73*/ +{0x00,0x10,0x00,0x10,0x04,0x10,0x27,0xE0,0x00,0x00,0x00,0x00},/*"j",74*/ +{0x20,0x40,0x3F,0xC0,0x01,0x40,0x07,0x00,0x04,0xC0,0x04,0x40},/*"k",75*/ +{0x20,0x40,0x20,0x40,0x3F,0xC0,0x00,0x40,0x00,0x40,0x00,0x00},/*"l",76*/ +{0x07,0xC0,0x04,0x00,0x07,0xC0,0x04,0x00,0x03,0xC0,0x00,0x00},/*"m",77*/ +{0x04,0x40,0x07,0xC0,0x04,0x40,0x04,0x00,0x03,0xC0,0x00,0x40},/*"n",78*/ +{0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x40,0x03,0x80,0x00,0x00},/*"o",79*/ +{0x04,0x10,0x07,0xF0,0x04,0x50,0x04,0x40,0x03,0x80,0x00,0x00},/*"p",80*/ +{0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x50,0x07,0xF0,0x00,0x10},/*"q",81*/ +{0x04,0x40,0x07,0xC0,0x02,0x40,0x04,0x00,0x04,0x00,0x00,0x00},/*"r",82*/ +{0x00,0x00,0x06,0x40,0x05,0x40,0x05,0x40,0x04,0xC0,0x00,0x00},/*"s",83*/ +{0x00,0x00,0x04,0x00,0x1F,0x80,0x04,0x40,0x00,0x40,0x00,0x00},/*"t",84*/ +{0x04,0x00,0x07,0x80,0x00,0x40,0x04,0x40,0x07,0xC0,0x00,0x40},/*"u",85*/ +{0x04,0x00,0x07,0x00,0x04,0xC0,0x01,0x80,0x06,0x00,0x04,0x00},/*"v",86*/ +{0x06,0x00,0x01,0xC0,0x07,0x00,0x01,0xC0,0x06,0x00,0x00,0x00},/*"w",87*/ +{0x04,0x40,0x06,0xC0,0x01,0x00,0x06,0xC0,0x04,0x40,0x00,0x00},/*"x",88*/ +{0x04,0x10,0x07,0x10,0x04,0xE0,0x01,0x80,0x06,0x00,0x04,0x00},/*"y",89*/ +{0x00,0x00,0x04,0x40,0x05,0xC0,0x06,0x40,0x04,0x40,0x00,0x00},/*"z",90*/ +{0x00,0x00,0x00,0x00,0x04,0x00,0x7B,0xE0,0x40,0x20,0x00,0x00},/*"{",91*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00},/*"|",92*/ +{0x00,0x00,0x40,0x20,0x7B,0xE0,0x04,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ +{0x40,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x40,0x00},/*"~",94*/ +}; +//16*16 ASCII鐎涙顑侀梿鍡欏仯闂冿拷 +const unsigned char asc2_1608[95][16]={ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xCC,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ +{0x00,0x00,0x08,0x00,0x30,0x00,0x60,0x00,0x08,0x00,0x30,0x00,0x60,0x00,0x00,0x00},/*""",2*/ +{0x02,0x20,0x03,0xFC,0x1E,0x20,0x02,0x20,0x03,0xFC,0x1E,0x20,0x02,0x20,0x00,0x00},/*"#",3*/ +{0x00,0x00,0x0E,0x18,0x11,0x04,0x3F,0xFF,0x10,0x84,0x0C,0x78,0x00,0x00,0x00,0x00},/*"$",4*/ +{0x0F,0x00,0x10,0x84,0x0F,0x38,0x00,0xC0,0x07,0x78,0x18,0x84,0x00,0x78,0x00,0x00},/*"%",5*/ +{0x00,0x78,0x0F,0x84,0x10,0xC4,0x11,0x24,0x0E,0x98,0x00,0xE4,0x00,0x84,0x00,0x08},/*"&",6*/ +{0x08,0x00,0x68,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x18,0x18,0x20,0x04,0x40,0x02,0x00,0x00},/*"(",8*/ +{0x00,0x00,0x40,0x02,0x20,0x04,0x18,0x18,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*")",9*/ +{0x02,0x40,0x02,0x40,0x01,0x80,0x0F,0xF0,0x01,0x80,0x02,0x40,0x02,0x40,0x00,0x00},/*"*",10*/ +{0x00,0x80,0x00,0x80,0x00,0x80,0x0F,0xF8,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00},/*"+",11*/ +{0x00,0x01,0x00,0x0D,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/ +{0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80},/*"-",13*/ +{0x00,0x00,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ +{0x00,0x00,0x00,0x06,0x00,0x18,0x00,0x60,0x01,0x80,0x06,0x00,0x18,0x00,0x20,0x00},/*"/",15*/ +{0x00,0x00,0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"0",16*/ +{0x00,0x00,0x08,0x04,0x08,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"1",17*/ +{0x00,0x00,0x0E,0x0C,0x10,0x14,0x10,0x24,0x10,0x44,0x11,0x84,0x0E,0x0C,0x00,0x00},/*"2",18*/ +{0x00,0x00,0x0C,0x18,0x10,0x04,0x11,0x04,0x11,0x04,0x12,0x88,0x0C,0x70,0x00,0x00},/*"3",19*/ +{0x00,0x00,0x00,0xE0,0x03,0x20,0x04,0x24,0x08,0x24,0x1F,0xFC,0x00,0x24,0x00,0x00},/*"4",20*/ +{0x00,0x00,0x1F,0x98,0x10,0x84,0x11,0x04,0x11,0x04,0x10,0x88,0x10,0x70,0x00,0x00},/*"5",21*/ +{0x00,0x00,0x07,0xF0,0x08,0x88,0x11,0x04,0x11,0x04,0x18,0x88,0x00,0x70,0x00,0x00},/*"6",22*/ +{0x00,0x00,0x1C,0x00,0x10,0x00,0x10,0xFC,0x13,0x00,0x1C,0x00,0x10,0x00,0x00,0x00},/*"7",23*/ +{0x00,0x00,0x0E,0x38,0x11,0x44,0x10,0x84,0x10,0x84,0x11,0x44,0x0E,0x38,0x00,0x00},/*"8",24*/ +{0x00,0x00,0x07,0x00,0x08,0x8C,0x10,0x44,0x10,0x44,0x08,0x88,0x07,0xF0,0x00,0x00},/*"9",25*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x03,0x0C,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/ +{0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/ +{0x00,0x00,0x00,0x80,0x01,0x40,0x02,0x20,0x04,0x10,0x08,0x08,0x10,0x04,0x00,0x00},/*"<",28*/ +{0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x00,0x00},/*"=",29*/ +{0x00,0x00,0x10,0x04,0x08,0x08,0x04,0x10,0x02,0x20,0x01,0x40,0x00,0x80,0x00,0x00},/*">",30*/ +{0x00,0x00,0x0E,0x00,0x12,0x00,0x10,0x0C,0x10,0x6C,0x10,0x80,0x0F,0x00,0x00,0x00},/*"?",31*/ +{0x03,0xE0,0x0C,0x18,0x13,0xE4,0x14,0x24,0x17,0xC4,0x08,0x28,0x07,0xD0,0x00,0x00},/*"@",32*/ +{0x00,0x04,0x00,0x3C,0x03,0xC4,0x1C,0x40,0x07,0x40,0x00,0xE4,0x00,0x1C,0x00,0x04},/*"A",33*/ +{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x11,0x04,0x0E,0x88,0x00,0x70,0x00,0x00},/*"B",34*/ +{0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x08,0x1C,0x10,0x00,0x00},/*"C",35*/ +{0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"D",36*/ +{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x17,0xC4,0x10,0x04,0x08,0x18,0x00,0x00},/*"E",37*/ +{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x17,0xC0,0x10,0x00,0x08,0x00,0x00,0x00},/*"F",38*/ +{0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x44,0x1C,0x78,0x00,0x40,0x00,0x00},/*"G",39*/ +{0x10,0x04,0x1F,0xFC,0x10,0x84,0x00,0x80,0x00,0x80,0x10,0x84,0x1F,0xFC,0x10,0x04},/*"H",40*/ +{0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x00,0x00,0x00,0x00},/*"I",41*/ +{0x00,0x03,0x00,0x01,0x10,0x01,0x10,0x01,0x1F,0xFE,0x10,0x00,0x10,0x00,0x00,0x00},/*"J",42*/ +{0x10,0x04,0x1F,0xFC,0x11,0x04,0x03,0x80,0x14,0x64,0x18,0x1C,0x10,0x04,0x00,0x00},/*"K",43*/ +{0x10,0x04,0x1F,0xFC,0x10,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x0C,0x00,0x00},/*"L",44*/ +{0x10,0x04,0x1F,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x1F,0xFC,0x10,0x04,0x00,0x00},/*"M",45*/ +{0x10,0x04,0x1F,0xFC,0x0C,0x04,0x03,0x00,0x00,0xE0,0x10,0x18,0x1F,0xFC,0x10,0x00},/*"N",46*/ +{0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"O",47*/ +{0x10,0x04,0x1F,0xFC,0x10,0x84,0x10,0x80,0x10,0x80,0x10,0x80,0x0F,0x00,0x00,0x00},/*"P",48*/ +{0x07,0xF0,0x08,0x18,0x10,0x24,0x10,0x24,0x10,0x1C,0x08,0x0A,0x07,0xF2,0x00,0x00},/*"Q",49*/ +{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x11,0xC0,0x11,0x30,0x0E,0x0C,0x00,0x04},/*"R",50*/ +{0x00,0x00,0x0E,0x1C,0x11,0x04,0x10,0x84,0x10,0x84,0x10,0x44,0x1C,0x38,0x00,0x00},/*"S",51*/ +{0x18,0x00,0x10,0x00,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x00,0x18,0x00,0x00,0x00},/*"T",52*/ +{0x10,0x00,0x1F,0xF8,0x10,0x04,0x00,0x04,0x00,0x04,0x10,0x04,0x1F,0xF8,0x10,0x00},/*"U",53*/ +{0x10,0x00,0x1E,0x00,0x11,0xE0,0x00,0x1C,0x00,0x70,0x13,0x80,0x1C,0x00,0x10,0x00},/*"V",54*/ +{0x1F,0xC0,0x10,0x3C,0x00,0xE0,0x1F,0x00,0x00,0xE0,0x10,0x3C,0x1F,0xC0,0x00,0x00},/*"W",55*/ +{0x10,0x04,0x18,0x0C,0x16,0x34,0x01,0xC0,0x01,0xC0,0x16,0x34,0x18,0x0C,0x10,0x04},/*"X",56*/ +{0x10,0x00,0x1C,0x00,0x13,0x04,0x00,0xFC,0x13,0x04,0x1C,0x00,0x10,0x00,0x00,0x00},/*"Y",57*/ +{0x08,0x04,0x10,0x1C,0x10,0x64,0x10,0x84,0x13,0x04,0x1C,0x04,0x10,0x18,0x00,0x00},/*"Z",58*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x40,0x02,0x40,0x02,0x40,0x02,0x00,0x00},/*"[",59*/ +{0x00,0x00,0x30,0x00,0x0C,0x00,0x03,0x80,0x00,0x60,0x00,0x1C,0x00,0x03,0x00,0x00},/*"\",60*/ +{0x00,0x00,0x40,0x02,0x40,0x02,0x40,0x02,0x7F,0xFE,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/ +{0x00,0x00,0x00,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00},/*"^",62*/ +{0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01},/*"_",63*/ +{0x00,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ +{0x00,0x00,0x00,0x98,0x01,0x24,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xFC,0x00,0x04},/*"a",65*/ +{0x10,0x00,0x1F,0xFC,0x00,0x88,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"b",66*/ +{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x00},/*"c",67*/ +{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x11,0x08,0x1F,0xFC,0x00,0x04},/*"d",68*/ +{0x00,0x00,0x00,0xF8,0x01,0x44,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xC8,0x00,0x00},/*"e",69*/ +{0x00,0x00,0x01,0x04,0x01,0x04,0x0F,0xFC,0x11,0x04,0x11,0x04,0x11,0x00,0x18,0x00},/*"f",70*/ +{0x00,0x00,0x00,0xD6,0x01,0x29,0x01,0x29,0x01,0x29,0x01,0xC9,0x01,0x06,0x00,0x00},/*"g",71*/ +{0x10,0x04,0x1F,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"h",72*/ +{0x00,0x00,0x01,0x04,0x19,0x04,0x19,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"i",73*/ +{0x00,0x00,0x00,0x03,0x00,0x01,0x01,0x01,0x19,0x01,0x19,0xFE,0x00,0x00,0x00,0x00},/*"j",74*/ +{0x10,0x04,0x1F,0xFC,0x00,0x24,0x00,0x40,0x01,0xB4,0x01,0x0C,0x01,0x04,0x00,0x00},/*"k",75*/ +{0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"l",76*/ +{0x01,0x04,0x01,0xFC,0x01,0x04,0x01,0x00,0x01,0xFC,0x01,0x04,0x01,0x00,0x00,0xFC},/*"m",77*/ +{0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"n",78*/ +{0x00,0x00,0x00,0xF8,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0xF8,0x00,0x00},/*"o",79*/ +{0x01,0x01,0x01,0xFF,0x00,0x85,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"p",80*/ +{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0xFF,0x00,0x01},/*"q",81*/ +{0x01,0x04,0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x04,0x01,0x00,0x01,0x80,0x00,0x00},/*"r",82*/ +{0x00,0x00,0x00,0xCC,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x98,0x00,0x00},/*"s",83*/ +{0x00,0x00,0x01,0x00,0x01,0x00,0x07,0xF8,0x01,0x04,0x01,0x04,0x00,0x00,0x00,0x00},/*"t",84*/ +{0x01,0x00,0x01,0xF8,0x00,0x04,0x00,0x04,0x00,0x04,0x01,0x08,0x01,0xFC,0x00,0x04},/*"u",85*/ +{0x01,0x00,0x01,0x80,0x01,0x70,0x00,0x0C,0x00,0x10,0x01,0x60,0x01,0x80,0x01,0x00},/*"v",86*/ +{0x01,0xF0,0x01,0x0C,0x00,0x30,0x01,0xC0,0x00,0x30,0x01,0x0C,0x01,0xF0,0x01,0x00},/*"w",87*/ +{0x00,0x00,0x01,0x04,0x01,0x8C,0x00,0x74,0x01,0x70,0x01,0x8C,0x01,0x04,0x00,0x00},/*"x",88*/ +{0x01,0x01,0x01,0x81,0x01,0x71,0x00,0x0E,0x00,0x18,0x01,0x60,0x01,0x80,0x01,0x00},/*"y",89*/ +{0x00,0x00,0x01,0x84,0x01,0x0C,0x01,0x34,0x01,0x44,0x01,0x84,0x01,0x0C,0x00,0x00},/*"z",90*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x3E,0xFC,0x40,0x02,0x40,0x02},/*"{",91*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/ +{0x00,0x00,0x40,0x02,0x40,0x02,0x3E,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ +{0x00,0x00,0x60,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00},/*"~",94*/ +}; +//24*24 ASCII code +const unsigned char asc2_2412[95][36]={ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x38,0x0F,0xFE,0x38,0x0F,0x80,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0x00,0x38,0x00,0x00,0x31,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0x00,0x38,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*""",2*/ +{0x00,0x00,0x00,0x00,0x61,0x80,0x00,0x67,0xF8,0x07,0xF9,0x80,0x00,0x61,0x80,0x00,0x61,0x80,0x00,0x61,0x80,0x00,0x61,0x80,0x00,0x67,0xF8,0x07,0xF9,0x80,0x00,0x61,0x80,0x00,0x00,0x00},/*"#",3*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xC0,0xE0,0x03,0xE0,0xF0,0x06,0x30,0x08,0x04,0x18,0x08,0x1F,0xFF,0xFE,0x04,0x0E,0x08,0x07,0x87,0xF0,0x03,0x81,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*"$",4*/ +{0x01,0xF0,0x00,0x06,0x0C,0x00,0x04,0x04,0x08,0x06,0x0C,0x70,0x01,0xF9,0xC0,0x00,0x0E,0x00,0x00,0x3B,0xE0,0x00,0xEC,0x18,0x07,0x08,0x08,0x04,0x0C,0x18,0x00,0x03,0xE0,0x00,0x00,0x00},/*"%",5*/ +{0x00,0x01,0xE0,0x00,0x07,0xF0,0x03,0xF8,0x18,0x04,0x1C,0x08,0x04,0x17,0x08,0x07,0xE1,0xD0,0x03,0xC0,0xE0,0x00,0x23,0xB0,0x00,0x3C,0x08,0x00,0x20,0x08,0x00,0x00,0x10,0x00,0x00,0x00},/*"&",6*/ +{0x00,0x00,0x00,0x01,0x00,0x00,0x31,0x00,0x00,0x32,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x01,0xFF,0xC0,0x07,0x80,0xF0,0x0C,0x00,0x18,0x10,0x00,0x04,0x20,0x00,0x02,0x00,0x00,0x00},/*"(",8*/ +{0x00,0x00,0x00,0x20,0x00,0x02,0x10,0x00,0x04,0x0C,0x00,0x18,0x07,0x80,0xF0,0x01,0xFF,0xC0,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*")",9*/ +{0x00,0x00,0x00,0x00,0x42,0x00,0x00,0x66,0x00,0x00,0x66,0x00,0x00,0x3C,0x00,0x00,0x18,0x00,0x03,0xFF,0xC0,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x66,0x00,0x00,0x66,0x00,0x00,0x42,0x00},/*"*",10*/ +{0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x01,0xFF,0xC0,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00},/*"+",11*/ +{0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x31,0x00,0x00,0x32,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/ +{0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x00},/*"-",13*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ +{0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x1C,0x00,0x00,0x70,0x00,0x01,0x80,0x00,0x0E,0x00,0x00,0x38,0x00,0x00,0xC0,0x00,0x07,0x00,0x00,0x1C,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*"/",15*/ +{0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x06,0x00,0x18,0x04,0x00,0x08,0x04,0x00,0x08,0x06,0x00,0x18,0x03,0x80,0x70,0x01,0xFF,0xE0,0x00,0x7F,0x80,0x00,0x00,0x00},/*"0",16*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x08,0x01,0x00,0x08,0x01,0x00,0x08,0x03,0xFF,0xF8,0x07,0xFF,0xF8,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",17*/ +{0x00,0x00,0x00,0x01,0xC0,0x38,0x02,0xC0,0x58,0x04,0x00,0x98,0x04,0x01,0x18,0x04,0x02,0x18,0x04,0x04,0x18,0x06,0x1C,0x18,0x03,0xF8,0x18,0x01,0xE0,0xF8,0x00,0x00,0x00,0x00,0x00,0x00},/*"2",18*/ +{0x00,0x00,0x00,0x01,0xC0,0xE0,0x03,0xC0,0xF0,0x04,0x00,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x06,0x18,0x08,0x03,0xF4,0x18,0x01,0xE7,0xF0,0x00,0x01,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*"3",19*/ +{0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x0D,0x00,0x00,0x11,0x00,0x00,0x61,0x00,0x00,0x81,0x08,0x03,0x01,0x08,0x07,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0x01,0x08,0x00,0x01,0x08,0x00,0x00,0x00},/*"4",20*/ +{0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0xFC,0xD0,0x06,0x08,0x08,0x06,0x10,0x08,0x06,0x10,0x08,0x06,0x10,0x08,0x06,0x18,0x38,0x06,0x0F,0xF0,0x06,0x07,0xC0,0x00,0x00,0x00,0x00,0x00,0x00},/*"5",21*/ +{0x00,0x00,0x00,0x00,0x3F,0x80,0x01,0xFF,0xE0,0x03,0x84,0x30,0x02,0x08,0x18,0x04,0x10,0x08,0x04,0x10,0x08,0x04,0x10,0x08,0x07,0x18,0x10,0x03,0x0F,0xF0,0x00,0x07,0xC0,0x00,0x00,0x00},/*"6",22*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x07,0x00,0x00,0x06,0x00,0x00,0x06,0x00,0xF8,0x06,0x07,0xF8,0x06,0x18,0x00,0x06,0xE0,0x00,0x07,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00},/*"7",23*/ +{0x00,0x00,0x00,0x01,0xE1,0xE0,0x03,0xF7,0xF0,0x06,0x34,0x10,0x04,0x18,0x08,0x04,0x18,0x08,0x04,0x0C,0x08,0x04,0x0C,0x08,0x06,0x16,0x18,0x03,0xF3,0xF0,0x01,0xC1,0xE0,0x00,0x00,0x00},/*"8",24*/ +{0x00,0x00,0x00,0x00,0xF8,0x00,0x03,0xFC,0x30,0x03,0x06,0x38,0x04,0x02,0x08,0x04,0x02,0x08,0x04,0x02,0x08,0x04,0x04,0x10,0x03,0x08,0xF0,0x01,0xFF,0xC0,0x00,0x7F,0x00,0x00,0x00,0x00},/*"9",25*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x00,0x70,0x38,0x00,0x70,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x1A,0x00,0x30,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x14,0x00,0x00,0x22,0x00,0x00,0x41,0x00,0x00,0x80,0x80,0x01,0x00,0x40,0x02,0x00,0x20,0x04,0x00,0x10,0x08,0x00,0x08,0x00,0x00,0x00},/*"<",28*/ +{0x00,0x00,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x00,0x00},/*"=",29*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x04,0x00,0x10,0x02,0x00,0x20,0x01,0x00,0x40,0x00,0x80,0x80,0x00,0x41,0x00,0x00,0x22,0x00,0x00,0x14,0x00,0x00,0x08,0x00,0x00,0x00,0x00},/*">",30*/ +{0x00,0x00,0x00,0x03,0xC0,0x00,0x04,0xC0,0x00,0x04,0x00,0x00,0x08,0x00,0x38,0x08,0x0F,0x38,0x08,0x08,0x38,0x08,0x10,0x00,0x0C,0x30,0x00,0x07,0xE0,0x00,0x03,0xC0,0x00,0x00,0x00,0x00},/*"?",31*/ +{0x00,0x00,0x00,0x00,0x3F,0x80,0x00,0xFF,0xE0,0x03,0x80,0x70,0x02,0x0F,0x10,0x06,0x70,0x88,0x04,0xC0,0x88,0x04,0x83,0x08,0x04,0x7F,0x88,0x02,0xC0,0x90,0x03,0x01,0x20,0x00,0xFE,0x40},/*"@",32*/ +{0x00,0x00,0x08,0x00,0x00,0x18,0x00,0x01,0xF8,0x00,0x3E,0x08,0x01,0xC2,0x00,0x07,0x02,0x00,0x07,0xE2,0x00,0x00,0xFE,0x00,0x00,0x1F,0xC8,0x00,0x01,0xF8,0x00,0x00,0x38,0x00,0x00,0x08},/*"A",33*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x06,0x18,0x08,0x03,0xF4,0x18,0x01,0xE7,0xF0,0x00,0x01,0xE0,0x00,0x00,0x00},/*"B",34*/ +{0x00,0x00,0x00,0x00,0x3F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x02,0x00,0x18,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x10,0x06,0x00,0x20,0x07,0x80,0xC0,0x00,0x00,0x00},/*"C",35*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x18,0x02,0x00,0x10,0x03,0x80,0x70,0x01,0xFF,0xE0,0x00,0x7F,0x80,0x00,0x00,0x00},/*"D",36*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x3E,0x08,0x04,0x00,0x08,0x06,0x00,0x18,0x01,0x00,0x60,0x00,0x00,0x00},/*"E",37*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x04,0x08,0x00,0x04,0x08,0x00,0x04,0x08,0x00,0x04,0x3E,0x00,0x06,0x00,0x00,0x06,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00},/*"F",38*/ +{0x00,0x00,0x00,0x00,0x3F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x06,0x00,0x18,0x04,0x00,0x08,0x04,0x02,0x08,0x04,0x02,0x08,0x02,0x03,0xF0,0x07,0x83,0xF0,0x00,0x02,0x00,0x00,0x02,0x00},/*"G",39*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x04,0x08,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08},/*"H",40*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},/*"I",41*/ +{0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x07,0x00,0x00,0x01,0x04,0x00,0x01,0x04,0x00,0x01,0x04,0x00,0x03,0x07,0xFF,0xFE,0x07,0xFF,0xFC,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00},/*"J",42*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x0C,0x08,0x00,0x18,0x00,0x00,0x3E,0x00,0x04,0xC7,0x80,0x05,0x03,0xC8,0x06,0x00,0xF8,0x04,0x00,0x38,0x04,0x00,0x18,0x00,0x00,0x08},/*"K",43*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x18,0x00,0x00,0x60,0x00,0x00,0x00},/*"L",44*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0x80,0x08,0x07,0xFC,0x00,0x00,0x7F,0xC0,0x00,0x03,0xF8,0x00,0x07,0xC0,0x00,0x78,0x00,0x07,0x80,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08},/*"M",45*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0x00,0x08,0x03,0xC0,0x00,0x00,0xE0,0x00,0x00,0x38,0x00,0x00,0x1E,0x00,0x00,0x07,0x00,0x00,0x01,0xC0,0x04,0x00,0xF0,0x07,0xFF,0xF8,0x04,0x00,0x00},/*"N",46*/ +{0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x06,0x00,0x18,0x04,0x00,0x08,0x04,0x00,0x08,0x06,0x00,0x18,0x03,0x00,0x30,0x01,0xFF,0xE0,0x00,0x7F,0x80,0x00,0x00,0x00},/*"O",47*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x04,0x08,0x04,0x04,0x00,0x04,0x04,0x00,0x04,0x04,0x00,0x04,0x04,0x00,0x06,0x0C,0x00,0x03,0xF8,0x00,0x01,0xF0,0x00,0x00,0x00,0x00},/*"P",48*/ +{0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x06,0x00,0x88,0x04,0x00,0x88,0x04,0x00,0xC8,0x06,0x00,0x3C,0x03,0x00,0x3E,0x01,0xFF,0xE6,0x00,0x7F,0x84,0x00,0x00,0x00},/*"Q",49*/ +{0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x04,0x08,0x00,0x04,0x0C,0x00,0x04,0x0F,0x00,0x04,0x0B,0xC0,0x06,0x10,0xF0,0x03,0xF0,0x38,0x01,0xE0,0x08,0x00,0x00,0x08},/*"R",50*/ +{0x00,0x00,0x00,0x01,0xE0,0xF8,0x03,0xF0,0x30,0x06,0x30,0x10,0x04,0x18,0x08,0x04,0x18,0x08,0x04,0x0C,0x08,0x04,0x0C,0x08,0x02,0x06,0x18,0x02,0x07,0xF0,0x07,0x81,0xE0,0x00,0x00,0x00},/*"S",51*/ +{0x01,0x80,0x00,0x06,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08,0x04,0x00,0x00,0x04,0x00,0x00,0x06,0x00,0x00,0x01,0x80,0x00},/*"T",52*/ +{0x04,0x00,0x00,0x07,0xFF,0xE0,0x07,0xFF,0xF0,0x04,0x00,0x18,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x04,0x00,0x10,0x07,0xFF,0xE0,0x04,0x00,0x00},/*"U",53*/ +{0x04,0x00,0x00,0x06,0x00,0x00,0x07,0xE0,0x00,0x07,0xFE,0x00,0x04,0x1F,0xE0,0x00,0x01,0xF8,0x00,0x00,0x38,0x00,0x01,0xE0,0x04,0x3E,0x00,0x07,0xC0,0x00,0x06,0x00,0x00,0x04,0x00,0x00},/*"V",54*/ +{0x04,0x00,0x00,0x07,0xE0,0x00,0x07,0xFF,0xC0,0x04,0x1F,0xF8,0x00,0x07,0xC0,0x07,0xF8,0x00,0x07,0xFF,0x80,0x04,0x3F,0xF8,0x00,0x07,0xC0,0x04,0xF8,0x00,0x07,0x00,0x00,0x04,0x00,0x00},/*"W",55*/ +{0x00,0x00,0x00,0x04,0x00,0x08,0x06,0x00,0x18,0x07,0xC0,0x78,0x05,0xF1,0xC8,0x00,0x3E,0x00,0x00,0x1F,0x80,0x04,0x63,0xE8,0x07,0x80,0xF8,0x06,0x00,0x18,0x04,0x00,0x08,0x00,0x00,0x00},/*"X",56*/ +{0x04,0x00,0x00,0x06,0x00,0x00,0x07,0x80,0x00,0x07,0xE0,0x08,0x04,0x7C,0x08,0x00,0x1F,0xF8,0x00,0x07,0xF8,0x00,0x18,0x08,0x04,0xE0,0x08,0x07,0x00,0x00,0x06,0x00,0x00,0x04,0x00,0x00},/*"Y",57*/ +{0x00,0x00,0x00,0x01,0x00,0x08,0x06,0x00,0x38,0x04,0x00,0xF8,0x04,0x03,0xE8,0x04,0x0F,0x08,0x04,0x7C,0x08,0x05,0xF0,0x08,0x07,0xC0,0x08,0x07,0x00,0x18,0x04,0x00,0x60,0x00,0x00,0x00},/*"Z",58*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFE,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x00,0x00,0x00},/*"[",59*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x07,0x00,0x00,0x00,0xC0,0x00,0x00,0x38,0x00,0x00,0x06,0x00,0x00,0x01,0xC0,0x00,0x00,0x30,0x00,0x00,0x0E,0x00,0x00,0x01,0x00,0x00,0x00},/*"\",60*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x3F,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x10,0x00,0x00,0x30,0x00,0x00,0x20,0x00,0x00,0x30,0x00,0x00,0x10,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"^",62*/ +{0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01},/*"_",63*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ +{0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x19,0xF8,0x00,0x1B,0x18,0x00,0x22,0x08,0x00,0x26,0x08,0x00,0x24,0x08,0x00,0x24,0x10,0x00,0x3F,0xF8,0x00,0x1F,0xF8,0x00,0x00,0x08,0x00,0x00,0x18},/*"a",65*/ +{0x00,0x00,0x00,0x04,0x00,0x00,0x07,0xFF,0xF8,0x0F,0xFF,0xF0,0x00,0x18,0x18,0x00,0x10,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x30,0x18,0x00,0x1F,0xF0,0x00,0x0F,0xC0,0x00,0x00,0x00},/*"b",66*/ +{0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x1F,0xF0,0x00,0x18,0x30,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x3C,0x08,0x00,0x1C,0x10,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00},/*"c",67*/ +{0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x1F,0xF0,0x00,0x38,0x18,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x04,0x10,0x10,0x07,0xFF,0xF8,0x0F,0xFF,0xF0,0x00,0x00,0x10,0x00,0x00,0x00},/*"d",68*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x1F,0xF0,0x00,0x12,0x30,0x00,0x22,0x18,0x00,0x22,0x08,0x00,0x22,0x08,0x00,0x32,0x08,0x00,0x1E,0x10,0x00,0x0E,0x20,0x00,0x00,0x00},/*"e",69*/ +{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x08,0x00,0x20,0x08,0x01,0xFF,0xF8,0x03,0xFF,0xF8,0x06,0x20,0x08,0x04,0x20,0x08,0x04,0x20,0x08,0x07,0x20,0x00,0x03,0x00,0x00,0x00,0x00,0x00},/*"f",70*/ +{0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x0E,0x6E,0x00,0x1F,0xF3,0x00,0x31,0xB1,0x00,0x20,0xB1,0x00,0x20,0xB1,0x00,0x31,0x91,0x00,0x1F,0x13,0x00,0x2E,0x1E,0x00,0x20,0x0E,0x00,0x30,0x00},/*"g",71*/ +{0x00,0x00,0x00,0x04,0x00,0x08,0x07,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0x10,0x08,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x1F,0xF8,0x00,0x00,0x08,0x00,0x00,0x00},/*"h",72*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x06,0x3F,0xF8,0x06,0x3F,0xF8,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},/*"i",73*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x03,0x00,0x20,0x01,0x00,0x20,0x01,0x00,0x20,0x03,0x06,0x3F,0xFE,0x06,0x3F,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"j",74*/ +{0x00,0x00,0x00,0x04,0x00,0x08,0x07,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0x01,0x88,0x00,0x03,0x00,0x00,0x2F,0xC0,0x00,0x38,0xF8,0x00,0x20,0x38,0x00,0x20,0x08,0x00,0x00,0x08,0x00,0x00,0x00},/*"k",75*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x07,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},/*"l",76*/ +{0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x10,0x08,0x00,0x20,0x00,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x10,0x08,0x00,0x20,0x00,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x00,0x08},/*"m",77*/ +{0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x10,0x08,0x00,0x10,0x00,0x00,0x20,0x00,0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x1F,0xF8,0x00,0x00,0x08,0x00,0x00,0x00},/*"n",78*/ +{0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x0F,0xF0,0x00,0x18,0x30,0x00,0x30,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x30,0x08,0x00,0x18,0x30,0x00,0x0F,0xF0,0x00,0x07,0xC0,0x00,0x00,0x00},/*"o",79*/ +{0x00,0x00,0x00,0x00,0x20,0x01,0x00,0x3F,0xFF,0x00,0x3F,0xFF,0x00,0x10,0x11,0x00,0x20,0x09,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x30,0x38,0x00,0x1F,0xF0,0x00,0x0F,0xC0,0x00,0x00,0x00},/*"p",80*/ +{0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x1F,0xF0,0x00,0x38,0x18,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x09,0x00,0x10,0x11,0x00,0x1F,0xFF,0x00,0x3F,0xFF,0x00,0x00,0x01,0x00,0x00,0x00},/*"q",81*/ +{0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x08,0x08,0x00,0x10,0x08,0x00,0x20,0x08,0x00,0x20,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x00,0x00},/*"r",82*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x78,0x00,0x1E,0x18,0x00,0x33,0x08,0x00,0x23,0x08,0x00,0x21,0x08,0x00,0x21,0x88,0x00,0x21,0x98,0x00,0x30,0xF0,0x00,0x38,0x60,0x00,0x00,0x00},/*"s",83*/ +{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0xFF,0xF0,0x03,0xFF,0xF8,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00},/*"t",84*/ +{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x3F,0xF0,0x00,0x7F,0xF8,0x00,0x00,0x18,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x20,0x10,0x00,0x3F,0xF8,0x00,0x7F,0xF0,0x00,0x00,0x10,0x00,0x00,0x00},/*"u",85*/ +{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x30,0x00,0x00,0x3C,0x00,0x00,0x3F,0x80,0x00,0x23,0xF0,0x00,0x00,0x78,0x00,0x00,0x70,0x00,0x23,0x80,0x00,0x3C,0x00,0x00,0x30,0x00,0x00,0x20,0x00},/*"v",86*/ +{0x00,0x20,0x00,0x00,0x3C,0x00,0x00,0x3F,0xE0,0x00,0x23,0xF8,0x00,0x00,0xE0,0x00,0x27,0x00,0x00,0x3E,0x00,0x00,0x3F,0xE0,0x00,0x21,0xF8,0x00,0x01,0xE0,0x00,0x3E,0x00,0x00,0x20,0x00},/*"w",87*/ +{0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x38,0x38,0x00,0x3E,0x68,0x00,0x27,0x80,0x00,0x03,0xC8,0x00,0x2C,0xF8,0x00,0x38,0x38,0x00,0x20,0x18,0x00,0x20,0x08,0x00,0x00,0x00},/*"x",88*/ +{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x30,0x03,0x00,0x3C,0x01,0x00,0x3F,0x83,0x00,0x23,0xEC,0x00,0x00,0x70,0x00,0x23,0x80,0x00,0x3C,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"y",89*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x08,0x00,0x20,0x38,0x00,0x20,0xF8,0x00,0x23,0xE8,0x00,0x2F,0x88,0x00,0x3E,0x08,0x00,0x38,0x08,0x00,0x20,0x18,0x00,0x00,0x70,0x00,0x00,0x00},/*"z",90*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x14,0x00,0x1F,0xF7,0xFC,0x30,0x00,0x06,0x20,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00},/*"{",91*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x02,0x30,0x00,0x06,0x1F,0xF7,0xFC,0x00,0x14,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ +{0x00,0x00,0x00,0x18,0x00,0x00,0x60,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0x00,0x10,0x00,0x00,0x08,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x0C,0x00,0x00,0x10,0x00,0x00},/*"~",94*/ +}; + +//32*32 ASCII code +const unsigned char asc2_3216[95][128]={ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF0,0x00,0xC0,0x07,0xFF,0xE1,0xE0,0x07,0xF0,0x01,0xE0,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0xC0,0x00,0x00,0x07,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x1C,0x20,0x00,0x00,0x01,0xC0,0x00,0x00,0x07,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*""",2*/ +{0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0F,0xE0,0x00,0x1F,0xFC,0x00,0x03,0xF8,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0F,0xE0,0x00,0x1F,0xFC,0x00,0x03,0xF8,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x00,0x00,0x00},/*"#",3*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x00,0x78,0x07,0xC0,0x00,0xFC,0x06,0x40,0x01,0x0E,0x00,0x20,0x03,0x07,0x00,0x20,0x02,0x03,0x80,0x20,0x0F,0xFF,0xFF,0xFC,0x02,0x01,0xC0,0x20,0x02,0x00,0xE0,0x60,0x01,0x30,0x70,0x40,0x01,0xF0,0x3F,0x80,0x00,0xF0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"$",4*/ +{0x00,0xFE,0x00,0x00,0x01,0xFF,0x00,0x00,0x03,0x01,0x80,0x00,0x02,0x00,0x80,0x60,0x03,0x01,0x81,0xC0,0x01,0xFF,0x07,0x00,0x00,0xFE,0x18,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0xBF,0x00,0x00,0x0C,0xFF,0xC0,0x00,0x71,0x80,0x60,0x01,0xC1,0x00,0x20,0x03,0x01,0x80,0x60,0x00,0x00,0xFF,0xC0,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00},/*"%",5*/ +{0x00,0x00,0x1F,0x00,0x00,0x00,0x7F,0xC0,0x00,0xFC,0xC0,0xC0,0x01,0xFF,0x80,0x60,0x03,0x03,0xE0,0x20,0x02,0x02,0x78,0x20,0x02,0x06,0x1E,0x20,0x03,0xFC,0x07,0x40,0x01,0xF0,0x03,0x80,0x00,0x01,0x03,0xC0,0x00,0x01,0x1C,0x60,0x00,0x01,0xE0,0x20,0x00,0x01,0x00,0x20,0x00,0x01,0x00,0x40,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00},/*"&",6*/ +{0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x1C,0x60,0x00,0x00,0x1C,0x40,0x00,0x00,0x1F,0x80,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0x3F,0xFF,0x00,0x00,0x78,0x07,0xC0,0x01,0xC0,0x00,0xE0,0x03,0x00,0x00,0x30,0x04,0x00,0x00,0x08,0x08,0x00,0x00,0x04,0x10,0x00,0x00,0x02,0x00,0x00,0x00,0x00},/*"(",8*/ +{0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0x08,0x00,0x00,0x04,0x04,0x00,0x00,0x08,0x03,0x00,0x00,0x30,0x01,0xC0,0x00,0xE0,0x00,0x78,0x07,0xC0,0x00,0x3F,0xFF,0x00,0x00,0x07,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*")",9*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x18,0x00,0x00,0x0E,0x38,0x00,0x00,0x0E,0x38,0x00,0x00,0x06,0x30,0x00,0x00,0x03,0x60,0x00,0x00,0x61,0x43,0x80,0x00,0xFF,0xFF,0x80,0x00,0x61,0x43,0x00,0x00,0x03,0x60,0x00,0x00,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x0E,0x38,0x00,0x00,0x0C,0x18,0x00,0x00,0x00,0x00,0x00},/*"*",10*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x7F,0xFF,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},/*"+",11*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xE3,0x00,0x00,0x00,0xE2,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},/*"-",13*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x01,0xE0,0x00,0x00,0x01,0xE0,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x0E,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x0E,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x0E,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"/",15*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x00,0x00,0x7F,0xFF,0x00,0x00,0xF0,0x07,0x80,0x01,0x80,0x00,0xC0,0x03,0x00,0x00,0x60,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0x00,0x00,0x60,0x01,0x80,0x00,0xC0,0x00,0xE0,0x03,0x80,0x00,0x7F,0xFF,0x00,0x00,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00},/*"0",16*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x20,0x00,0x80,0x00,0x20,0x00,0x80,0x00,0x20,0x00,0x80,0x00,0x60,0x01,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",17*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0xE0,0x00,0x98,0x01,0x60,0x01,0x00,0x02,0x60,0x02,0x00,0x04,0x60,0x02,0x00,0x08,0x60,0x02,0x00,0x10,0x60,0x02,0x00,0x20,0x60,0x02,0x00,0x40,0x60,0x03,0x00,0x80,0x60,0x01,0x83,0x00,0x60,0x01,0xFE,0x00,0xE0,0x00,0x7C,0x07,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"2",18*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x80,0x01,0xF0,0x07,0xC0,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x03,0x03,0x80,0x20,0x01,0x86,0x80,0x40,0x01,0xFC,0xC0,0xC0,0x00,0x78,0x7F,0x80,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"3",19*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x48,0x00,0x00,0x01,0x88,0x00,0x00,0x06,0x08,0x00,0x00,0x0C,0x08,0x10,0x00,0x30,0x08,0x10,0x00,0x40,0x08,0x10,0x01,0xFF,0xFF,0xF0,0x03,0xFF,0xFF,0xF0,0x03,0xFF,0xFF,0xF0,0x00,0x00,0x08,0x10,0x00,0x00,0x08,0x10,0x00,0x00,0x08,0x10,0x00,0x00,0x00,0x00},/*"4",20*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x00,0x1F,0x86,0x40,0x03,0xE1,0x00,0x20,0x03,0x02,0x00,0x20,0x03,0x04,0x00,0x20,0x03,0x04,0x00,0x20,0x03,0x04,0x00,0x20,0x03,0x04,0x00,0x20,0x03,0x06,0x00,0x40,0x03,0x03,0x01,0xC0,0x03,0x01,0xFF,0x80,0x03,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"5",21*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFC,0x00,0x00,0x3F,0xFF,0x00,0x00,0x70,0xC3,0x80,0x00,0x81,0x80,0xC0,0x01,0x01,0x00,0x60,0x03,0x02,0x00,0x20,0x02,0x02,0x00,0x20,0x02,0x02,0x00,0x20,0x02,0x02,0x00,0x20,0x02,0x03,0x00,0x40,0x01,0xC1,0x80,0xC0,0x00,0xC0,0xFF,0x80,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00},/*"6",22*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0x80,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x07,0xE0,0x03,0x00,0x3F,0xE0,0x03,0x01,0xC0,0x00,0x03,0x06,0x00,0x00,0x03,0x18,0x00,0x00,0x03,0x60,0x00,0x00,0x03,0x80,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"7",23*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x78,0x3F,0x80,0x00,0xFC,0x60,0xC0,0x01,0x8E,0xC0,0x40,0x03,0x07,0x80,0x20,0x02,0x03,0x00,0x20,0x02,0x01,0x80,0x20,0x02,0x01,0x80,0x20,0x02,0x01,0xC0,0x20,0x03,0x01,0xE0,0x40,0x01,0x86,0x70,0xC0,0x00,0xFC,0x3F,0x80,0x00,0x78,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"8",24*/ +{0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0xFF,0x81,0xC0,0x01,0xC0,0xC1,0xC0,0x01,0x00,0x60,0x20,0x02,0x00,0x20,0x20,0x02,0x00,0x20,0x20,0x02,0x00,0x20,0x20,0x02,0x00,0x20,0x60,0x02,0x00,0x40,0xC0,0x01,0x00,0xC1,0x80,0x00,0xC1,0x8F,0x00,0x00,0x7F,0xFE,0x00,0x00,0x1F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"9",25*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xC0,0x00,0x07,0x81,0xE0,0x00,0x07,0x81,0xE0,0x00,0x03,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x66,0x00,0x06,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x01,0xC0,0x00,0x00,0x03,0x60,0x00,0x00,0x06,0x30,0x00,0x00,0x0C,0x18,0x00,0x00,0x18,0x0C,0x00,0x00,0x30,0x06,0x00,0x00,0x60,0x03,0x00,0x00,0xC0,0x01,0x80,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"<",28*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x00,0x00,0x00},/*"=",29*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x10,0x02,0x00,0x00,0x20,0x01,0x00,0x00,0x40,0x00,0xC0,0x01,0x80,0x00,0x60,0x03,0x00,0x00,0x30,0x06,0x00,0x00,0x18,0x0C,0x00,0x00,0x0C,0x18,0x00,0x00,0x06,0x30,0x00,0x00,0x03,0x60,0x00,0x00,0x01,0xC0,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*">",30*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x01,0xF8,0x00,0x00,0x02,0x38,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0xC0,0x04,0x00,0x79,0xE0,0x04,0x00,0x81,0xE0,0x04,0x01,0x00,0xC0,0x04,0x03,0x00,0x00,0x02,0x02,0x00,0x00,0x03,0x06,0x00,0x00,0x01,0xFC,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00},/*"?",31*/ +{0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x00,0x00,0x3F,0xFE,0x00,0x00,0x70,0x07,0x80,0x00,0xC0,0x00,0xC0,0x01,0x01,0xF8,0x40,0x03,0x07,0xFC,0x20,0x02,0x1E,0x04,0x20,0x02,0x30,0x08,0x20,0x02,0x20,0x30,0x20,0x02,0x3F,0xFC,0x20,0x01,0x3F,0x04,0x40,0x01,0x80,0x0C,0xC0,0x00,0xE0,0x31,0x80,0x00,0x1F,0xC2,0x00,0x00,0x00,0x00,0x00},/*"@",32*/ +{0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x60,0x00,0x00,0x03,0xE0,0x00,0x00,0x3E,0x20,0x00,0x03,0xE0,0x20,0x00,0x3E,0x20,0x00,0x03,0xE0,0x20,0x00,0x03,0x80,0x20,0x00,0x07,0xFC,0x20,0x00,0x00,0x3F,0xE0,0x00,0x00,0x03,0xFE,0x20,0x00,0x00,0x3F,0xE0,0x00,0x00,0x01,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"A",33*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x03,0x03,0x00,0x20,0x01,0x86,0x80,0x60,0x01,0xFC,0xC0,0xC0,0x00,0xF8,0x7F,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00},/*"B",34*/ +{0x00,0x00,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0x3F,0xFF,0x00,0x00,0x70,0x07,0x80,0x00,0xC0,0x00,0xC0,0x01,0x00,0x00,0x40,0x03,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x01,0x00,0x00,0x40,0x01,0x80,0x00,0xC0,0x03,0xC0,0x01,0x80,0x00,0x30,0x06,0x00,0x00,0x00,0x00,0x00},/*"C",35*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0x00,0x00,0x60,0x01,0x00,0x00,0x40,0x01,0x80,0x00,0xC0,0x00,0xF0,0x07,0x80,0x00,0x7F,0xFE,0x00,0x00,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00},/*"D",36*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x03,0x80,0x20,0x02,0x0F,0xE0,0x20,0x03,0x00,0x00,0x60,0x03,0xC0,0x00,0xE0,0x00,0x60,0x03,0x00,0x00,0x00,0x00,0x00},/*"E",37*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x00,0x02,0x01,0x00,0x00,0x02,0x01,0x00,0x00,0x02,0x01,0x00,0x00,0x02,0x03,0x80,0x00,0x03,0x0F,0xE0,0x00,0x03,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x60,0x00,0x00},/*"F",38*/ +{0x00,0x00,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0x3F,0xFE,0x00,0x00,0x70,0x07,0x80,0x01,0xC0,0x01,0xC0,0x01,0x00,0x00,0x40,0x03,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x01,0x00,0x20,0x20,0x01,0x00,0x20,0x40,0x03,0xC0,0x3F,0x80,0x00,0x30,0x3F,0x80,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00},/*"G",39*/ +{0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x80,0x20,0x02,0x00,0x80,0x20,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x02,0x00,0x80,0x20,0x02,0x00,0x80,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"H",40*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"I",41*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x01,0x02,0x00,0x00,0x01,0x02,0x00,0x00,0x01,0x02,0x00,0x00,0x03,0x02,0x00,0x00,0x06,0x03,0xFF,0xFF,0xFC,0x03,0xFF,0xFF,0xF8,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"J",42*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0xC0,0x20,0x02,0x01,0x00,0x20,0x00,0x07,0x80,0x00,0x00,0x0F,0xE0,0x00,0x00,0x30,0xF8,0x00,0x02,0x60,0x3E,0x20,0x03,0x80,0x0F,0x20,0x03,0x00,0x03,0xE0,0x02,0x00,0x00,0xE0,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x20},/*"K",43*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00},/*"L",44*/ +{0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xE0,0x00,0x20,0x03,0xFF,0x00,0x20,0x00,0x1F,0xF0,0x00,0x00,0x01,0xFF,0x80,0x00,0x00,0x0F,0xE0,0x00,0x00,0x1E,0x00,0x00,0x03,0xE0,0x00,0x00,0x3E,0x00,0x20,0x03,0xE0,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20},/*"M",45*/ +{0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0x80,0x00,0x20,0x03,0xF0,0x00,0x20,0x00,0xFC,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x07,0xC0,0x00,0x00,0x01,0xF0,0x00,0x00,0x00,0x7C,0x00,0x02,0x00,0x1F,0x80,0x02,0x00,0x07,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"N",46*/ +{0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x00,0x00,0x3F,0xFE,0x00,0x00,0xF0,0x07,0x80,0x01,0x80,0x00,0xC0,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x01,0x00,0x00,0x40,0x01,0x80,0x00,0xC0,0x00,0xF0,0x03,0x80,0x00,0x3F,0xFE,0x00,0x00,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00},/*"O",47*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x80,0x20,0x02,0x00,0x80,0x20,0x02,0x00,0x80,0x00,0x02,0x00,0x80,0x00,0x02,0x00,0x80,0x00,0x02,0x00,0x80,0x00,0x03,0x01,0x80,0x00,0x01,0x83,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00},/*"P",48*/ +{0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x00,0x00,0x7F,0xFF,0x00,0x00,0xF0,0x03,0x80,0x01,0x80,0x01,0xC0,0x01,0x00,0x06,0x40,0x02,0x00,0x04,0x20,0x02,0x00,0x04,0x20,0x02,0x00,0x06,0x20,0x02,0x00,0x03,0xE0,0x01,0x00,0x00,0xF8,0x01,0x80,0x00,0x5C,0x00,0xE0,0x03,0x8C,0x00,0x3F,0xFF,0x0C,0x00,0x0F,0xFC,0x18,0x00,0x00,0x00,0x00},/*"Q",49*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x80,0x00,0x02,0x01,0xE0,0x00,0x02,0x01,0xFC,0x00,0x03,0x03,0x3F,0x80,0x01,0x86,0x07,0xE0,0x01,0xFC,0x00,0xE0,0x00,0xF8,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"R",50*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x06,0x00,0x00,0xFE,0x01,0xE0,0x01,0x86,0x00,0xC0,0x03,0x03,0x00,0x40,0x02,0x03,0x00,0x20,0x02,0x01,0x80,0x20,0x02,0x01,0x80,0x20,0x02,0x01,0xC0,0x20,0x02,0x00,0xC0,0x20,0x01,0x00,0xE0,0x60,0x01,0x80,0x70,0xC0,0x03,0xE0,0x3F,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00},/*"S",51*/ +{0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x03,0x80,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x80,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*"T",52*/ +{0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0xFF,0xFF,0x00,0x03,0xFF,0xFF,0xC0,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x60,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x80,0x03,0xFF,0xFF,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"U",53*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xFC,0x00,0x00,0x02,0x3F,0xC0,0x00,0x00,0x03,0xF8,0x00,0x00,0x00,0x7F,0x80,0x00,0x00,0x07,0xE0,0x00,0x00,0x07,0x80,0x00,0x00,0x78,0x00,0x02,0x03,0xC0,0x00,0x02,0x3C,0x00,0x00,0x03,0xC0,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00},/*"V",54*/ +{0x02,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xFF,0x80,0x00,0x02,0x3F,0xFE,0x00,0x02,0x00,0x7F,0xE0,0x00,0x00,0x0F,0x00,0x02,0x00,0xF0,0x00,0x03,0xEF,0x00,0x00,0x03,0xFF,0x80,0x00,0x02,0x0F,0xFE,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x1F,0x00,0x02,0x07,0xE0,0x00,0x03,0xF8,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00},/*"W",55*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0x80,0x00,0xE0,0x03,0xF0,0x03,0x20,0x02,0xFC,0x0C,0x20,0x02,0x1F,0x30,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0xF0,0x00,0x02,0x18,0x7C,0x00,0x02,0x60,0x1F,0x20,0x03,0x80,0x03,0xE0,0x02,0x00,0x00,0xE0,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"X",56*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xF8,0x00,0x00,0x02,0x3E,0x00,0x20,0x02,0x0F,0xC0,0x20,0x00,0x01,0xFF,0xE0,0x00,0x00,0x7F,0xE0,0x00,0x03,0x80,0x20,0x02,0x1C,0x00,0x20,0x02,0x70,0x00,0x00,0x03,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"Y",57*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x60,0x00,0xE0,0x03,0x80,0x03,0xE0,0x03,0x00,0x0F,0xA0,0x02,0x00,0x3E,0x20,0x02,0x00,0xF8,0x20,0x02,0x03,0xE0,0x20,0x02,0x0F,0x80,0x20,0x02,0x3E,0x00,0x20,0x02,0x78,0x00,0x20,0x03,0xE0,0x00,0x60,0x03,0x80,0x00,0xE0,0x02,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"Z",58*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFC,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"[",59*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x07,0x80,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"\",60*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x1F,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"^",62*/ +{0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01},/*"_",63*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x00,0x01,0x8F,0xC0,0x00,0x03,0x8C,0x60,0x00,0x06,0x18,0x20,0x00,0x04,0x10,0x20,0x00,0x04,0x10,0x20,0x00,0x04,0x20,0x20,0x00,0x04,0x20,0x40,0x00,0x06,0x20,0x40,0x00,0x03,0xFF,0xC0,0x00,0x01,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00},/*"a",65*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xC0,0x00,0x01,0x80,0xC0,0x00,0x02,0x00,0x60,0x00,0x02,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x40,0x00,0x03,0x00,0xC0,0x00,0x01,0xFF,0x80,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00},/*"b",66*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x01,0xFF,0x80,0x00,0x03,0x81,0xC0,0x00,0x02,0x00,0x40,0x00,0x06,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x03,0xC0,0x40,0x00,0x01,0xC0,0x80,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"c",67*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x01,0xFF,0x80,0x00,0x03,0x80,0xC0,0x00,0x06,0x00,0x60,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x02,0x04,0x00,0x40,0x02,0x02,0x00,0x80,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00},/*"d",68*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x01,0xFF,0x80,0x00,0x03,0x11,0xC0,0x00,0x02,0x10,0x40,0x00,0x04,0x10,0x60,0x00,0x04,0x10,0x20,0x00,0x04,0x10,0x20,0x00,0x04,0x10,0x20,0x00,0x06,0x10,0x20,0x00,0x03,0x10,0x40,0x00,0x01,0xF0,0xC0,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"e",69*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x7F,0xFF,0xE0,0x01,0xFF,0xFF,0xE0,0x01,0x04,0x00,0x20,0x03,0x04,0x00,0x20,0x02,0x04,0x00,0x20,0x02,0x04,0x00,0x20,0x02,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0xC0,0x00,0x00,0x01,0xC0,0x00,0x00},/*"f",70*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0xE3,0x3E,0x00,0x03,0xFF,0xC2,0x00,0x02,0x0C,0xC3,0x00,0x04,0x04,0xC1,0x00,0x04,0x04,0xC1,0x00,0x04,0x04,0xC1,0x00,0x04,0x04,0xC1,0x00,0x06,0x0C,0xC1,0x00,0x03,0xF8,0xC3,0x00,0x05,0xF0,0x62,0x00,0x06,0x00,0x7E,0x00,0x06,0x00,0x3C,0x00,0x00,0x00,0x00},/*"g",71*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xE0,0x00,0x01,0x00,0x20,0x00,0x02,0x00,0x20,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x03,0xFF,0xE0,0x00,0x01,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20},/*"h",72*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x03,0x87,0xFF,0xE0,0x03,0x8F,0xFF,0xE0,0x03,0x80,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"i",73*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x04,0x00,0x03,0x00,0x04,0x00,0x06,0x03,0x87,0xFF,0xFC,0x03,0x8F,0xFF,0xF8,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"j",74*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xE0,0x00,0x00,0x08,0x20,0x00,0x00,0x10,0x20,0x00,0x00,0x30,0x00,0x00,0x00,0xFC,0x00,0x00,0x05,0x8E,0x00,0x00,0x07,0x07,0xA0,0x00,0x06,0x01,0xE0,0x00,0x04,0x00,0xE0,0x00,0x04,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"k",75*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"l",76*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x07,0xFF,0xE0,0x00,0x0F,0xFF,0xE0,0x00,0x02,0x00,0x20,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x07,0xFF,0xE0,0x00,0x03,0xFF,0xE0,0x00,0x02,0x00,0x20,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x07,0xFF,0xE0,0x00,0x03,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"m",77*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x07,0xFF,0xE0,0x00,0x0F,0xFF,0xE0,0x00,0x01,0x00,0x20,0x00,0x02,0x00,0x20,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x03,0xFF,0xE0,0x00,0x01,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20},/*"n",78*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0xFF,0x80,0x00,0x03,0x81,0xC0,0x00,0x02,0x00,0x40,0x00,0x06,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x02,0x00,0x40,0x00,0x03,0x81,0xC0,0x00,0x01,0xFF,0x80,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00},/*"o",79*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x07,0xFF,0xFF,0x00,0x0F,0xFF,0xFF,0x00,0x01,0x00,0xC1,0x00,0x02,0x00,0x41,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x40,0x00,0x03,0x01,0xC0,0x00,0x01,0xFF,0x80,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00},/*"p",80*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x01,0xFF,0x80,0x00,0x03,0x80,0xC0,0x00,0x02,0x00,0x60,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x02,0x00,0x41,0x00,0x03,0x00,0xC1,0x00,0x03,0xFF,0xFF,0x00,0x07,0xFF,0xFF,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01},/*"q",81*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x0F,0xFF,0xE0,0x00,0x0F,0xFF,0xE0,0x00,0x00,0xC0,0x20,0x00,0x01,0x00,0x20,0x00,0x02,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"r",82*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x00,0x01,0xC0,0xE0,0x00,0x03,0xE0,0x40,0x00,0x06,0x30,0x20,0x00,0x04,0x30,0x20,0x00,0x04,0x18,0x20,0x00,0x04,0x18,0x20,0x00,0x04,0x18,0x20,0x00,0x04,0x0C,0x20,0x00,0x02,0x0C,0x60,0x00,0x03,0x07,0xC0,0x00,0x07,0x83,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"s",83*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x1F,0xFF,0x80,0x00,0xFF,0xFF,0xC0,0x00,0x04,0x00,0x60,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x40,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"t",84*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x07,0xFF,0x80,0x00,0x0F,0xFF,0xC0,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x40,0x00,0x04,0x00,0x80,0x00,0x07,0xFF,0xE0,0x00,0x0F,0xFF,0xC0,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40},/*"u",85*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x07,0x80,0x00,0x00,0x07,0xF0,0x00,0x00,0x04,0xFE,0x00,0x00,0x04,0x1F,0xC0,0x00,0x00,0x03,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x1C,0x00,0x00,0x04,0x60,0x00,0x00,0x07,0x80,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"v",86*/ +{0x00,0x04,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0xFC,0x00,0x00,0x04,0x3F,0x80,0x00,0x00,0x03,0xE0,0x00,0x04,0x0F,0x80,0x00,0x06,0xF0,0x00,0x00,0x07,0xF0,0x00,0x00,0x07,0xFF,0x80,0x00,0x04,0x0F,0xE0,0x00,0x00,0x03,0x80,0x00,0x04,0x3C,0x00,0x00,0x07,0xC0,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00},/*"w",87*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x60,0x00,0x07,0x00,0xE0,0x00,0x07,0x83,0x20,0x00,0x07,0xE6,0x00,0x00,0x04,0xF8,0x00,0x00,0x00,0x3C,0x00,0x00,0x04,0x5E,0x20,0x00,0x05,0x87,0xA0,0x00,0x06,0x01,0xE0,0x00,0x04,0x00,0x60,0x00,0x04,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"x",88*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x03,0x00,0x07,0x00,0x03,0x00,0x07,0xE0,0x01,0x00,0x04,0xF8,0x01,0x00,0x04,0x1F,0x02,0x00,0x00,0x07,0xFC,0x00,0x00,0x00,0xE0,0x00,0x00,0x07,0x00,0x00,0x04,0x38,0x00,0x00,0x07,0xC0,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00},/*"y",89*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x60,0x00,0x06,0x00,0xE0,0x00,0x04,0x03,0xE0,0x00,0x04,0x07,0xA0,0x00,0x04,0x0E,0x20,0x00,0x04,0x3C,0x20,0x00,0x04,0x70,0x20,0x00,0x05,0xE0,0x20,0x00,0x07,0x80,0x20,0x00,0x07,0x00,0x60,0x00,0x04,0x00,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"z",90*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x01,0x40,0x00,0x07,0xFE,0x3F,0xF8,0x08,0x00,0x00,0x04,0x10,0x00,0x00,0x02,0x10,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"{",91*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0x10,0x00,0x00,0x02,0x08,0x00,0x00,0x04,0x07,0xFE,0x3F,0xF8,0x00,0x01,0x40,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ +{0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",94*/ +}; +#endif diff --git a/board/k210-emulator/third_party_driver/include/fpioa.h b/board/k210-emulator/third_party_driver/include/fpioa.h new file mode 100644 index 00000000..61d5155e --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/fpioa.h @@ -0,0 +1,1014 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 fpioa.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __FPIOA_H__ +#define __FPIOA_H__ + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Pad number settings */ +#define FPIOA_NUM_IO (48) +/* clang-format on */ + +/** + * @brief FPIOA IO functions + * + * @note FPIOA pin function table + * + * | Function | Name | Description | + * |-----------|------------------|-----------------------------------| + * | 0 | JTAG_TCLK | JTAG Test Clock | + * | 1 | JTAG_TDI | JTAG Test Data In | + * | 2 | JTAG_TMS | JTAG Test Mode Select | + * | 3 | JTAG_TDO | JTAG Test Data Out | + * | 4 | SPI0_D0 | SPI0 Data 0 | + * | 5 | SPI0_D1 | SPI0 Data 1 | + * | 6 | SPI0_D2 | SPI0 Data 2 | + * | 7 | SPI0_D3 | SPI0 Data 3 | + * | 8 | SPI0_D4 | SPI0 Data 4 | + * | 9 | SPI0_D5 | SPI0 Data 5 | + * | 10 | SPI0_D6 | SPI0 Data 6 | + * | 11 | SPI0_D7 | SPI0 Data 7 | + * | 12 | SPI0_SS0 | SPI0 Chip Select 0 | + * | 13 | SPI0_SS1 | SPI0 Chip Select 1 | + * | 14 | SPI0_SS2 | SPI0 Chip Select 2 | + * | 15 | SPI0_SS3 | SPI0 Chip Select 3 | + * | 16 | SPI0_ARB | SPI0 Arbitration | + * | 17 | SPI0_SCLK | SPI0 Serial Clock | + * | 18 | UARTHS_RX | UART High speed Receiver | + * | 19 | UARTHS_TX | UART High speed Transmitter | + * | 20 | RESV6 | Reserved function | + * | 21 | RESV7 | Reserved function | + * | 22 | CLK_SPI1 | Clock SPI1 | + * | 23 | CLK_I2C1 | Clock I2C1 | + * | 24 | GPIOHS0 | GPIO High speed 0 | + * | 25 | GPIOHS1 | GPIO High speed 1 | + * | 26 | GPIOHS2 | GPIO High speed 2 | + * | 27 | GPIOHS3 | GPIO High speed 3 | + * | 28 | GPIOHS4 | GPIO High speed 4 | + * | 29 | GPIOHS5 | GPIO High speed 5 | + * | 30 | GPIOHS6 | GPIO High speed 6 | + * | 31 | GPIOHS7 | GPIO High speed 7 | + * | 32 | GPIOHS8 | GPIO High speed 8 | + * | 33 | GPIOHS9 | GPIO High speed 9 | + * | 34 | GPIOHS10 | GPIO High speed 10 | + * | 35 | GPIOHS11 | GPIO High speed 11 | + * | 36 | GPIOHS12 | GPIO High speed 12 | + * | 37 | GPIOHS13 | GPIO High speed 13 | + * | 38 | GPIOHS14 | GPIO High speed 14 | + * | 39 | GPIOHS15 | GPIO High speed 15 | + * | 40 | GPIOHS16 | GPIO High speed 16 | + * | 41 | GPIOHS17 | GPIO High speed 17 | + * | 42 | GPIOHS18 | GPIO High speed 18 | + * | 43 | GPIOHS19 | GPIO High speed 19 | + * | 44 | GPIOHS20 | GPIO High speed 20 | + * | 45 | GPIOHS21 | GPIO High speed 21 | + * | 46 | GPIOHS22 | GPIO High speed 22 | + * | 47 | GPIOHS23 | GPIO High speed 23 | + * | 48 | GPIOHS24 | GPIO High speed 24 | + * | 49 | GPIOHS25 | GPIO High speed 25 | + * | 50 | GPIOHS26 | GPIO High speed 26 | + * | 51 | GPIOHS27 | GPIO High speed 27 | + * | 52 | GPIOHS28 | GPIO High speed 28 | + * | 53 | GPIOHS29 | GPIO High speed 29 | + * | 54 | GPIOHS30 | GPIO High speed 30 | + * | 55 | GPIOHS31 | GPIO High speed 31 | + * | 56 | GPIO0 | GPIO pin 0 | + * | 57 | GPIO1 | GPIO pin 1 | + * | 58 | GPIO2 | GPIO pin 2 | + * | 59 | GPIO3 | GPIO pin 3 | + * | 60 | GPIO4 | GPIO pin 4 | + * | 61 | GPIO5 | GPIO pin 5 | + * | 62 | GPIO6 | GPIO pin 6 | + * | 63 | GPIO7 | GPIO pin 7 | + * | 64 | UART1_RX | UART1 Receiver | + * | 65 | UART1_TX | UART1 Transmitter | + * | 66 | UART2_RX | UART2 Receiver | + * | 67 | UART2_TX | UART2 Transmitter | + * | 68 | UART3_RX | UART3 Receiver | + * | 69 | UART3_TX | UART3 Transmitter | + * | 70 | SPI1_D0 | SPI1 Data 0 | + * | 71 | SPI1_D1 | SPI1 Data 1 | + * | 72 | SPI1_D2 | SPI1 Data 2 | + * | 73 | SPI1_D3 | SPI1 Data 3 | + * | 74 | SPI1_D4 | SPI1 Data 4 | + * | 75 | SPI1_D5 | SPI1 Data 5 | + * | 76 | SPI1_D6 | SPI1 Data 6 | + * | 77 | SPI1_D7 | SPI1 Data 7 | + * | 78 | SPI1_SS0 | SPI1 Chip Select 0 | + * | 79 | SPI1_SS1 | SPI1 Chip Select 1 | + * | 80 | SPI1_SS2 | SPI1 Chip Select 2 | + * | 81 | SPI1_SS3 | SPI1 Chip Select 3 | + * | 82 | SPI1_ARB | SPI1 Arbitration | + * | 83 | SPI1_SCLK | SPI1 Serial Clock | + * | 84 | SPI_SLAVE_D0 | SPI Slave Data 0 | + * | 85 | SPI_SLAVE_SS | SPI Slave Select | + * | 86 | SPI_SLAVE_SCLK | SPI Slave Serial Clock | + * | 87 | I2S0_MCLK | I2S0 Master Clock | + * | 88 | I2S0_SCLK | I2S0 Serial Clock(BCLK) | + * | 89 | I2S0_WS | I2S0 Word Select(LRCLK) | + * | 90 | I2S0_IN_D0 | I2S0 Serial Data Input 0 | + * | 91 | I2S0_IN_D1 | I2S0 Serial Data Input 1 | + * | 92 | I2S0_IN_D2 | I2S0 Serial Data Input 2 | + * | 93 | I2S0_IN_D3 | I2S0 Serial Data Input 3 | + * | 94 | I2S0_OUT_D0 | I2S0 Serial Data Output 0 | + * | 95 | I2S0_OUT_D1 | I2S0 Serial Data Output 1 | + * | 96 | I2S0_OUT_D2 | I2S0 Serial Data Output 2 | + * | 97 | I2S0_OUT_D3 | I2S0 Serial Data Output 3 | + * | 98 | I2S1_MCLK | I2S1 Master Clock | + * | 99 | I2S1_SCLK | I2S1 Serial Clock(BCLK) | + * | 100 | I2S1_WS | I2S1 Word Select(LRCLK) | + * | 101 | I2S1_IN_D0 | I2S1 Serial Data Input 0 | + * | 102 | I2S1_IN_D1 | I2S1 Serial Data Input 1 | + * | 103 | I2S1_IN_D2 | I2S1 Serial Data Input 2 | + * | 104 | I2S1_IN_D3 | I2S1 Serial Data Input 3 | + * | 105 | I2S1_OUT_D0 | I2S1 Serial Data Output 0 | + * | 106 | I2S1_OUT_D1 | I2S1 Serial Data Output 1 | + * | 107 | I2S1_OUT_D2 | I2S1 Serial Data Output 2 | + * | 108 | I2S1_OUT_D3 | I2S1 Serial Data Output 3 | + * | 109 | I2S2_MCLK | I2S2 Master Clock | + * | 110 | I2S2_SCLK | I2S2 Serial Clock(BCLK) | + * | 111 | I2S2_WS | I2S2 Word Select(LRCLK) | + * | 112 | I2S2_IN_D0 | I2S2 Serial Data Input 0 | + * | 113 | I2S2_IN_D1 | I2S2 Serial Data Input 1 | + * | 114 | I2S2_IN_D2 | I2S2 Serial Data Input 2 | + * | 115 | I2S2_IN_D3 | I2S2 Serial Data Input 3 | + * | 116 | I2S2_OUT_D0 | I2S2 Serial Data Output 0 | + * | 117 | I2S2_OUT_D1 | I2S2 Serial Data Output 1 | + * | 118 | I2S2_OUT_D2 | I2S2 Serial Data Output 2 | + * | 119 | I2S2_OUT_D3 | I2S2 Serial Data Output 3 | + * | 120 | RESV0 | Reserved function | + * | 121 | RESV1 | Reserved function | + * | 122 | RESV2 | Reserved function | + * | 123 | RESV3 | Reserved function | + * | 124 | RESV4 | Reserved function | + * | 125 | RESV5 | Reserved function | + * | 126 | I2C0_SCLK | I2C0 Serial Clock | + * | 127 | I2C0_SDA | I2C0 Serial Data | + * | 128 | I2C1_SCLK | I2C1 Serial Clock | + * | 129 | I2C1_SDA | I2C1 Serial Data | + * | 130 | I2C2_SCLK | I2C2 Serial Clock | + * | 131 | I2C2_SDA | I2C2 Serial Data | + * | 132 | CMOS_XCLK | DVP System Clock | + * | 133 | CMOS_RST | DVP System Reset | + * | 134 | CMOS_PWDN | DVP Power Down Mode | + * | 135 | CMOS_VSYNC | DVP Vertical Sync | + * | 136 | CMOS_HREF | DVP Horizontal Reference output | + * | 137 | CMOS_PCLK | Pixel Clock | + * | 138 | CMOS_D0 | Data Bit 0 | + * | 139 | CMOS_D1 | Data Bit 1 | + * | 140 | CMOS_D2 | Data Bit 2 | + * | 141 | CMOS_D3 | Data Bit 3 | + * | 142 | CMOS_D4 | Data Bit 4 | + * | 143 | CMOS_D5 | Data Bit 5 | + * | 144 | CMOS_D6 | Data Bit 6 | + * | 145 | CMOS_D7 | Data Bit 7 | + * | 146 | SCCB_SCLK | SCCB Serial Clock | + * | 147 | SCCB_SDA | SCCB Serial Data | + * | 148 | UART1_CTS | UART1 Clear To Send | + * | 149 | UART1_DSR | UART1 Data Set Ready | + * | 150 | UART1_DCD | UART1 Data Carrier Detect | + * | 151 | UART1_RI | UART1 Ring Indicator | + * | 152 | UART1_SIR_IN | UART1 Serial Infrared Input | + * | 153 | UART1_DTR | UART1 Data Terminal Ready | + * | 154 | UART1_RTS | UART1 Request To Send | + * | 155 | UART1_OUT2 | UART1 User-designated Output 2 | + * | 156 | UART1_OUT1 | UART1 User-designated Output 1 | + * | 157 | UART1_SIR_OUT | UART1 Serial Infrared Output | + * | 158 | UART1_BAUD | UART1 Transmit Clock Output | + * | 159 | UART1_RE | UART1 Receiver Output Enable | + * | 160 | UART1_DE | UART1 Driver Output Enable | + * | 161 | UART1_RS485_EN | UART1 RS485 Enable | + * | 162 | UART2_CTS | UART2 Clear To Send | + * | 163 | UART2_DSR | UART2 Data Set Ready | + * | 164 | UART2_DCD | UART2 Data Carrier Detect | + * | 165 | UART2_RI | UART2 Ring Indicator | + * | 166 | UART2_SIR_IN | UART2 Serial Infrared Input | + * | 167 | UART2_DTR | UART2 Data Terminal Ready | + * | 168 | UART2_RTS | UART2 Request To Send | + * | 169 | UART2_OUT2 | UART2 User-designated Output 2 | + * | 170 | UART2_OUT1 | UART2 User-designated Output 1 | + * | 171 | UART2_SIR_OUT | UART2 Serial Infrared Output | + * | 172 | UART2_BAUD | UART2 Transmit Clock Output | + * | 173 | UART2_RE | UART2 Receiver Output Enable | + * | 174 | UART2_DE | UART2 Driver Output Enable | + * | 175 | UART2_RS485_EN | UART2 RS485 Enable | + * | 176 | UART3_CTS | UART3 Clear To Send | + * | 177 | UART3_DSR | UART3 Data Set Ready | + * | 178 | UART3_DCD | UART3 Data Carrier Detect | + * | 179 | UART3_RI | UART3 Ring Indicator | + * | 180 | UART3_SIR_IN | UART3 Serial Infrared Input | + * | 181 | UART3_DTR | UART3 Data Terminal Ready | + * | 182 | UART3_RTS | UART3 Request To Send | + * | 183 | UART3_OUT2 | UART3 User-designated Output 2 | + * | 184 | UART3_OUT1 | UART3 User-designated Output 1 | + * | 185 | UART3_SIR_OUT | UART3 Serial Infrared Output | + * | 186 | UART3_BAUD | UART3 Transmit Clock Output | + * | 187 | UART3_RE | UART3 Receiver Output Enable | + * | 188 | UART3_DE | UART3 Driver Output Enable | + * | 189 | UART3_RS485_EN | UART3 RS485 Enable | + * | 190 | TIMER0_TOGGLE1 | TIMER0 Toggle Output 1 | + * | 191 | TIMER0_TOGGLE2 | TIMER0 Toggle Output 2 | + * | 192 | TIMER0_TOGGLE3 | TIMER0 Toggle Output 3 | + * | 193 | TIMER0_TOGGLE4 | TIMER0 Toggle Output 4 | + * | 194 | TIMER1_TOGGLE1 | TIMER1 Toggle Output 1 | + * | 195 | TIMER1_TOGGLE2 | TIMER1 Toggle Output 2 | + * | 196 | TIMER1_TOGGLE3 | TIMER1 Toggle Output 3 | + * | 197 | TIMER1_TOGGLE4 | TIMER1 Toggle Output 4 | + * | 198 | TIMER2_TOGGLE1 | TIMER2 Toggle Output 1 | + * | 199 | TIMER2_TOGGLE2 | TIMER2 Toggle Output 2 | + * | 200 | TIMER2_TOGGLE3 | TIMER2 Toggle Output 3 | + * | 201 | TIMER2_TOGGLE4 | TIMER2 Toggle Output 4 | + * | 202 | CLK_SPI2 | Clock SPI2 | + * | 203 | CLK_I2C2 | Clock I2C2 | + * | 204 | INTERNAL0 | Internal function signal 0 | + * | 205 | INTERNAL1 | Internal function signal 1 | + * | 206 | INTERNAL2 | Internal function signal 2 | + * | 207 | INTERNAL3 | Internal function signal 3 | + * | 208 | INTERNAL4 | Internal function signal 4 | + * | 209 | INTERNAL5 | Internal function signal 5 | + * | 210 | INTERNAL6 | Internal function signal 6 | + * | 211 | INTERNAL7 | Internal function signal 7 | + * | 212 | INTERNAL8 | Internal function signal 8 | + * | 213 | INTERNAL9 | Internal function signal 9 | + * | 214 | INTERNAL10 | Internal function signal 10 | + * | 215 | INTERNAL11 | Internal function signal 11 | + * | 216 | INTERNAL12 | Internal function signal 12 | + * | 217 | INTERNAL13 | Internal function signal 13 | + * | 218 | INTERNAL14 | Internal function signal 14 | + * | 219 | INTERNAL15 | Internal function signal 15 | + * | 220 | INTERNAL16 | Internal function signal 16 | + * | 221 | INTERNAL17 | Internal function signal 17 | + * | 222 | CONSTANT | Constant function | + * | 223 | INTERNAL18 | Internal function signal 18 | + * | 224 | DEBUG0 | Debug function 0 | + * | 225 | DEBUG1 | Debug function 1 | + * | 226 | DEBUG2 | Debug function 2 | + * | 227 | DEBUG3 | Debug function 3 | + * | 228 | DEBUG4 | Debug function 4 | + * | 229 | DEBUG5 | Debug function 5 | + * | 230 | DEBUG6 | Debug function 6 | + * | 231 | DEBUG7 | Debug function 7 | + * | 232 | DEBUG8 | Debug function 8 | + * | 233 | DEBUG9 | Debug function 9 | + * | 234 | DEBUG10 | Debug function 10 | + * | 235 | DEBUG11 | Debug function 11 | + * | 236 | DEBUG12 | Debug function 12 | + * | 237 | DEBUG13 | Debug function 13 | + * | 238 | DEBUG14 | Debug function 14 | + * | 239 | DEBUG15 | Debug function 15 | + * | 240 | DEBUG16 | Debug function 16 | + * | 241 | DEBUG17 | Debug function 17 | + * | 242 | DEBUG18 | Debug function 18 | + * | 243 | DEBUG19 | Debug function 19 | + * | 244 | DEBUG20 | Debug function 20 | + * | 245 | DEBUG21 | Debug function 21 | + * | 246 | DEBUG22 | Debug function 22 | + * | 247 | DEBUG23 | Debug function 23 | + * | 248 | DEBUG24 | Debug function 24 | + * | 249 | DEBUG25 | Debug function 25 | + * | 250 | DEBUG26 | Debug function 26 | + * | 251 | DEBUG27 | Debug function 27 | + * | 252 | DEBUG28 | Debug function 28 | + * | 253 | DEBUG29 | Debug function 29 | + * | 254 | DEBUG30 | Debug function 30 | + * | 255 | DEBUG31 | Debug function 31 | + * + * Any IO of FPIOA have 256 functions, it is a IO-function matrix. + * All IO have default reset function, after reset, re-configure + * IO function is required. + */ + +/* clang-format off */ +typedef enum _fpioa_function +{ + FUNC_JTAG_TCLK = 0, /*!< JTAG Test Clock */ + FUNC_JTAG_TDI = 1, /*!< JTAG Test Data In */ + FUNC_JTAG_TMS = 2, /*!< JTAG Test Mode Select */ + FUNC_JTAG_TDO = 3, /*!< JTAG Test Data Out */ + FUNC_SPI0_D0 = 4, /*!< SPI0 Data 0 */ + FUNC_SPI0_D1 = 5, /*!< SPI0 Data 1 */ + FUNC_SPI0_D2 = 6, /*!< SPI0 Data 2 */ + FUNC_SPI0_D3 = 7, /*!< SPI0 Data 3 */ + FUNC_SPI0_D4 = 8, /*!< SPI0 Data 4 */ + FUNC_SPI0_D5 = 9, /*!< SPI0 Data 5 */ + FUNC_SPI0_D6 = 10, /*!< SPI0 Data 6 */ + FUNC_SPI0_D7 = 11, /*!< SPI0 Data 7 */ + FUNC_SPI0_SS0 = 12, /*!< SPI0 Chip Select 0 */ + FUNC_SPI0_SS1 = 13, /*!< SPI0 Chip Select 1 */ + FUNC_SPI0_SS2 = 14, /*!< SPI0 Chip Select 2 */ + FUNC_SPI0_SS3 = 15, /*!< SPI0 Chip Select 3 */ + FUNC_SPI0_ARB = 16, /*!< SPI0 Arbitration */ + FUNC_SPI0_SCLK = 17, /*!< SPI0 Serial Clock */ + FUNC_UARTHS_RX = 18, /*!< UART High speed Receiver */ + FUNC_UARTHS_TX = 19, /*!< UART High speed Transmitter */ + FUNC_RESV6 = 20, /*!< Reserved function */ + FUNC_RESV7 = 21, /*!< Reserved function */ + FUNC_CLK_SPI1 = 22, /*!< Clock SPI1 */ + FUNC_CLK_I2C1 = 23, /*!< Clock I2C1 */ + FUNC_GPIOHS0 = 24, /*!< GPIO High speed 0 */ + FUNC_GPIOHS1 = 25, /*!< GPIO High speed 1 */ + FUNC_GPIOHS2 = 26, /*!< GPIO High speed 2 */ + FUNC_GPIOHS3 = 27, /*!< GPIO High speed 3 */ + FUNC_GPIOHS4 = 28, /*!< GPIO High speed 4 */ + FUNC_GPIOHS5 = 29, /*!< GPIO High speed 5 */ + FUNC_GPIOHS6 = 30, /*!< GPIO High speed 6 */ + FUNC_GPIOHS7 = 31, /*!< GPIO High speed 7 */ + FUNC_GPIOHS8 = 32, /*!< GPIO High speed 8 */ + FUNC_GPIOHS9 = 33, /*!< GPIO High speed 9 */ + FUNC_GPIOHS10 = 34, /*!< GPIO High speed 10 */ + FUNC_GPIOHS11 = 35, /*!< GPIO High speed 11 */ + FUNC_GPIOHS12 = 36, /*!< GPIO High speed 12 */ + FUNC_GPIOHS13 = 37, /*!< GPIO High speed 13 */ + FUNC_GPIOHS14 = 38, /*!< GPIO High speed 14 */ + FUNC_GPIOHS15 = 39, /*!< GPIO High speed 15 */ + FUNC_GPIOHS16 = 40, /*!< GPIO High speed 16 */ + FUNC_GPIOHS17 = 41, /*!< GPIO High speed 17 */ + FUNC_GPIOHS18 = 42, /*!< GPIO High speed 18 */ + FUNC_GPIOHS19 = 43, /*!< GPIO High speed 19 */ + FUNC_GPIOHS20 = 44, /*!< GPIO High speed 20 */ + FUNC_GPIOHS21 = 45, /*!< GPIO High speed 21 */ + FUNC_GPIOHS22 = 46, /*!< GPIO High speed 22 */ + FUNC_GPIOHS23 = 47, /*!< GPIO High speed 23 */ + FUNC_GPIOHS24 = 48, /*!< GPIO High speed 24 */ + FUNC_GPIOHS25 = 49, /*!< GPIO High speed 25 */ + FUNC_GPIOHS26 = 50, /*!< GPIO High speed 26 */ + FUNC_GPIOHS27 = 51, /*!< GPIO High speed 27 */ + FUNC_GPIOHS28 = 52, /*!< GPIO High speed 28 */ + FUNC_GPIOHS29 = 53, /*!< GPIO High speed 29 */ + FUNC_GPIOHS30 = 54, /*!< GPIO High speed 30 */ + FUNC_GPIOHS31 = 55, /*!< GPIO High speed 31 */ + FUNC_GPIO0 = 56, /*!< GPIO pin 0 */ + FUNC_GPIO1 = 57, /*!< GPIO pin 1 */ + FUNC_GPIO2 = 58, /*!< GPIO pin 2 */ + FUNC_GPIO3 = 59, /*!< GPIO pin 3 */ + FUNC_GPIO4 = 60, /*!< GPIO pin 4 */ + FUNC_GPIO5 = 61, /*!< GPIO pin 5 */ + FUNC_GPIO6 = 62, /*!< GPIO pin 6 */ + FUNC_GPIO7 = 63, /*!< GPIO pin 7 */ + FUNC_UART1_RX = 64, /*!< UART1 Receiver */ + FUNC_UART1_TX = 65, /*!< UART1 Transmitter */ + FUNC_UART2_RX = 66, /*!< UART2 Receiver */ + FUNC_UART2_TX = 67, /*!< UART2 Transmitter */ + FUNC_UART3_RX = 68, /*!< UART3 Receiver */ + FUNC_UART3_TX = 69, /*!< UART3 Transmitter */ + FUNC_SPI1_D0 = 70, /*!< SPI1 Data 0 */ + FUNC_SPI1_D1 = 71, /*!< SPI1 Data 1 */ + FUNC_SPI1_D2 = 72, /*!< SPI1 Data 2 */ + FUNC_SPI1_D3 = 73, /*!< SPI1 Data 3 */ + FUNC_SPI1_D4 = 74, /*!< SPI1 Data 4 */ + FUNC_SPI1_D5 = 75, /*!< SPI1 Data 5 */ + FUNC_SPI1_D6 = 76, /*!< SPI1 Data 6 */ + FUNC_SPI1_D7 = 77, /*!< SPI1 Data 7 */ + FUNC_SPI1_SS0 = 78, /*!< SPI1 Chip Select 0 */ + FUNC_SPI1_SS1 = 79, /*!< SPI1 Chip Select 1 */ + FUNC_SPI1_SS2 = 80, /*!< SPI1 Chip Select 2 */ + FUNC_SPI1_SS3 = 81, /*!< SPI1 Chip Select 3 */ + FUNC_SPI1_ARB = 82, /*!< SPI1 Arbitration */ + FUNC_SPI1_SCLK = 83, /*!< SPI1 Serial Clock */ + FUNC_SPI_SLAVE_D0 = 84, /*!< SPI Slave Data 0 */ + FUNC_SPI_SLAVE_SS = 85, /*!< SPI Slave Select */ + FUNC_SPI_SLAVE_SCLK = 86, /*!< SPI Slave Serial Clock */ + FUNC_I2S0_MCLK = 87, /*!< I2S0 Master Clock */ + FUNC_I2S0_SCLK = 88, /*!< I2S0 Serial Clock(BCLK) */ + FUNC_I2S0_WS = 89, /*!< I2S0 Word Select(LRCLK) */ + FUNC_I2S0_IN_D0 = 90, /*!< I2S0 Serial Data Input 0 */ + FUNC_I2S0_IN_D1 = 91, /*!< I2S0 Serial Data Input 1 */ + FUNC_I2S0_IN_D2 = 92, /*!< I2S0 Serial Data Input 2 */ + FUNC_I2S0_IN_D3 = 93, /*!< I2S0 Serial Data Input 3 */ + FUNC_I2S0_OUT_D0 = 94, /*!< I2S0 Serial Data Output 0 */ + FUNC_I2S0_OUT_D1 = 95, /*!< I2S0 Serial Data Output 1 */ + FUNC_I2S0_OUT_D2 = 96, /*!< I2S0 Serial Data Output 2 */ + FUNC_I2S0_OUT_D3 = 97, /*!< I2S0 Serial Data Output 3 */ + FUNC_I2S1_MCLK = 98, /*!< I2S1 Master Clock */ + FUNC_I2S1_SCLK = 99, /*!< I2S1 Serial Clock(BCLK) */ + FUNC_I2S1_WS = 100, /*!< I2S1 Word Select(LRCLK) */ + FUNC_I2S1_IN_D0 = 101, /*!< I2S1 Serial Data Input 0 */ + FUNC_I2S1_IN_D1 = 102, /*!< I2S1 Serial Data Input 1 */ + FUNC_I2S1_IN_D2 = 103, /*!< I2S1 Serial Data Input 2 */ + FUNC_I2S1_IN_D3 = 104, /*!< I2S1 Serial Data Input 3 */ + FUNC_I2S1_OUT_D0 = 105, /*!< I2S1 Serial Data Output 0 */ + FUNC_I2S1_OUT_D1 = 106, /*!< I2S1 Serial Data Output 1 */ + FUNC_I2S1_OUT_D2 = 107, /*!< I2S1 Serial Data Output 2 */ + FUNC_I2S1_OUT_D3 = 108, /*!< I2S1 Serial Data Output 3 */ + FUNC_I2S2_MCLK = 109, /*!< I2S2 Master Clock */ + FUNC_I2S2_SCLK = 110, /*!< I2S2 Serial Clock(BCLK) */ + FUNC_I2S2_WS = 111, /*!< I2S2 Word Select(LRCLK) */ + FUNC_I2S2_IN_D0 = 112, /*!< I2S2 Serial Data Input 0 */ + FUNC_I2S2_IN_D1 = 113, /*!< I2S2 Serial Data Input 1 */ + FUNC_I2S2_IN_D2 = 114, /*!< I2S2 Serial Data Input 2 */ + FUNC_I2S2_IN_D3 = 115, /*!< I2S2 Serial Data Input 3 */ + FUNC_I2S2_OUT_D0 = 116, /*!< I2S2 Serial Data Output 0 */ + FUNC_I2S2_OUT_D1 = 117, /*!< I2S2 Serial Data Output 1 */ + FUNC_I2S2_OUT_D2 = 118, /*!< I2S2 Serial Data Output 2 */ + FUNC_I2S2_OUT_D3 = 119, /*!< I2S2 Serial Data Output 3 */ + FUNC_RESV0 = 120, /*!< Reserved function */ + FUNC_RESV1 = 121, /*!< Reserved function */ + FUNC_RESV2 = 122, /*!< Reserved function */ + FUNC_RESV3 = 123, /*!< Reserved function */ + FUNC_RESV4 = 124, /*!< Reserved function */ + FUNC_RESV5 = 125, /*!< Reserved function */ + FUNC_I2C0_SCLK = 126, /*!< I2C0 Serial Clock */ + FUNC_I2C0_SDA = 127, /*!< I2C0 Serial Data */ + FUNC_I2C1_SCLK = 128, /*!< I2C1 Serial Clock */ + FUNC_I2C1_SDA = 129, /*!< I2C1 Serial Data */ + FUNC_I2C2_SCLK = 130, /*!< I2C2 Serial Clock */ + FUNC_I2C2_SDA = 131, /*!< I2C2 Serial Data */ + FUNC_CMOS_XCLK = 132, /*!< DVP System Clock */ + FUNC_CMOS_RST = 133, /*!< DVP System Reset */ + FUNC_CMOS_PWDN = 134, /*!< DVP Power Down Mode */ + FUNC_CMOS_VSYNC = 135, /*!< DVP Vertical Sync */ + FUNC_CMOS_HREF = 136, /*!< DVP Horizontal Reference output */ + FUNC_CMOS_PCLK = 137, /*!< Pixel Clock */ + FUNC_CMOS_D0 = 138, /*!< Data Bit 0 */ + FUNC_CMOS_D1 = 139, /*!< Data Bit 1 */ + FUNC_CMOS_D2 = 140, /*!< Data Bit 2 */ + FUNC_CMOS_D3 = 141, /*!< Data Bit 3 */ + FUNC_CMOS_D4 = 142, /*!< Data Bit 4 */ + FUNC_CMOS_D5 = 143, /*!< Data Bit 5 */ + FUNC_CMOS_D6 = 144, /*!< Data Bit 6 */ + FUNC_CMOS_D7 = 145, /*!< Data Bit 7 */ + FUNC_SCCB_SCLK = 146, /*!< SCCB Serial Clock */ + FUNC_SCCB_SDA = 147, /*!< SCCB Serial Data */ + FUNC_UART1_CTS = 148, /*!< UART1 Clear To Send */ + FUNC_UART1_DSR = 149, /*!< UART1 Data Set Ready */ + FUNC_UART1_DCD = 150, /*!< UART1 Data Carrier Detect */ + FUNC_UART1_RI = 151, /*!< UART1 Ring Indicator */ + FUNC_UART1_SIR_IN = 152, /*!< UART1 Serial Infrared Input */ + FUNC_UART1_DTR = 153, /*!< UART1 Data Terminal Ready */ + FUNC_UART1_RTS = 154, /*!< UART1 Request To Send */ + FUNC_UART1_OUT2 = 155, /*!< UART1 User-designated Output 2 */ + FUNC_UART1_OUT1 = 156, /*!< UART1 User-designated Output 1 */ + FUNC_UART1_SIR_OUT = 157, /*!< UART1 Serial Infrared Output */ + FUNC_UART1_BAUD = 158, /*!< UART1 Transmit Clock Output */ + FUNC_UART1_RE = 159, /*!< UART1 Receiver Output Enable */ + FUNC_UART1_DE = 160, /*!< UART1 Driver Output Enable */ + FUNC_UART1_RS485_EN = 161, /*!< UART1 RS485 Enable */ + FUNC_UART2_CTS = 162, /*!< UART2 Clear To Send */ + FUNC_UART2_DSR = 163, /*!< UART2 Data Set Ready */ + FUNC_UART2_DCD = 164, /*!< UART2 Data Carrier Detect */ + FUNC_UART2_RI = 165, /*!< UART2 Ring Indicator */ + FUNC_UART2_SIR_IN = 166, /*!< UART2 Serial Infrared Input */ + FUNC_UART2_DTR = 167, /*!< UART2 Data Terminal Ready */ + FUNC_UART2_RTS = 168, /*!< UART2 Request To Send */ + FUNC_UART2_OUT2 = 169, /*!< UART2 User-designated Output 2 */ + FUNC_UART2_OUT1 = 170, /*!< UART2 User-designated Output 1 */ + FUNC_UART2_SIR_OUT = 171, /*!< UART2 Serial Infrared Output */ + FUNC_UART2_BAUD = 172, /*!< UART2 Transmit Clock Output */ + FUNC_UART2_RE = 173, /*!< UART2 Receiver Output Enable */ + FUNC_UART2_DE = 174, /*!< UART2 Driver Output Enable */ + FUNC_UART2_RS485_EN = 175, /*!< UART2 RS485 Enable */ + FUNC_UART3_CTS = 176, /*!< UART3 Clear To Send */ + FUNC_UART3_DSR = 177, /*!< UART3 Data Set Ready */ + FUNC_UART3_DCD = 178, /*!< UART3 Data Carrier Detect */ + FUNC_UART3_RI = 179, /*!< UART3 Ring Indicator */ + FUNC_UART3_SIR_IN = 180, /*!< UART3 Serial Infrared Input */ + FUNC_UART3_DTR = 181, /*!< UART3 Data Terminal Ready */ + FUNC_UART3_RTS = 182, /*!< UART3 Request To Send */ + FUNC_UART3_OUT2 = 183, /*!< UART3 User-designated Output 2 */ + FUNC_UART3_OUT1 = 184, /*!< UART3 User-designated Output 1 */ + FUNC_UART3_SIR_OUT = 185, /*!< UART3 Serial Infrared Output */ + FUNC_UART3_BAUD = 186, /*!< UART3 Transmit Clock Output */ + FUNC_UART3_RE = 187, /*!< UART3 Receiver Output Enable */ + FUNC_UART3_DE = 188, /*!< UART3 Driver Output Enable */ + FUNC_UART3_RS485_EN = 189, /*!< UART3 RS485 Enable */ + FUNC_TIMER0_TOGGLE1 = 190, /*!< TIMER0 Toggle Output 1 */ + FUNC_TIMER0_TOGGLE2 = 191, /*!< TIMER0 Toggle Output 2 */ + FUNC_TIMER0_TOGGLE3 = 192, /*!< TIMER0 Toggle Output 3 */ + FUNC_TIMER0_TOGGLE4 = 193, /*!< TIMER0 Toggle Output 4 */ + FUNC_TIMER1_TOGGLE1 = 194, /*!< TIMER1 Toggle Output 1 */ + FUNC_TIMER1_TOGGLE2 = 195, /*!< TIMER1 Toggle Output 2 */ + FUNC_TIMER1_TOGGLE3 = 196, /*!< TIMER1 Toggle Output 3 */ + FUNC_TIMER1_TOGGLE4 = 197, /*!< TIMER1 Toggle Output 4 */ + FUNC_TIMER2_TOGGLE1 = 198, /*!< TIMER2 Toggle Output 1 */ + FUNC_TIMER2_TOGGLE2 = 199, /*!< TIMER2 Toggle Output 2 */ + FUNC_TIMER2_TOGGLE3 = 200, /*!< TIMER2 Toggle Output 3 */ + FUNC_TIMER2_TOGGLE4 = 201, /*!< TIMER2 Toggle Output 4 */ + FUNC_CLK_SPI2 = 202, /*!< Clock SPI2 */ + FUNC_CLK_I2C2 = 203, /*!< Clock I2C2 */ + FUNC_INTERNAL0 = 204, /*!< Internal function signal 0 */ + FUNC_INTERNAL1 = 205, /*!< Internal function signal 1 */ + FUNC_INTERNAL2 = 206, /*!< Internal function signal 2 */ + FUNC_INTERNAL3 = 207, /*!< Internal function signal 3 */ + FUNC_INTERNAL4 = 208, /*!< Internal function signal 4 */ + FUNC_INTERNAL5 = 209, /*!< Internal function signal 5 */ + FUNC_INTERNAL6 = 210, /*!< Internal function signal 6 */ + FUNC_INTERNAL7 = 211, /*!< Internal function signal 7 */ + FUNC_INTERNAL8 = 212, /*!< Internal function signal 8 */ + FUNC_INTERNAL9 = 213, /*!< Internal function signal 9 */ + FUNC_INTERNAL10 = 214, /*!< Internal function signal 10 */ + FUNC_INTERNAL11 = 215, /*!< Internal function signal 11 */ + FUNC_INTERNAL12 = 216, /*!< Internal function signal 12 */ + FUNC_INTERNAL13 = 217, /*!< Internal function signal 13 */ + FUNC_INTERNAL14 = 218, /*!< Internal function signal 14 */ + FUNC_INTERNAL15 = 219, /*!< Internal function signal 15 */ + FUNC_INTERNAL16 = 220, /*!< Internal function signal 16 */ + FUNC_INTERNAL17 = 221, /*!< Internal function signal 17 */ + FUNC_CONSTANT = 222, /*!< Constant function */ + FUNC_INTERNAL18 = 223, /*!< Internal function signal 18 */ + FUNC_DEBUG0 = 224, /*!< Debug function 0 */ + FUNC_DEBUG1 = 225, /*!< Debug function 1 */ + FUNC_DEBUG2 = 226, /*!< Debug function 2 */ + FUNC_DEBUG3 = 227, /*!< Debug function 3 */ + FUNC_DEBUG4 = 228, /*!< Debug function 4 */ + FUNC_DEBUG5 = 229, /*!< Debug function 5 */ + FUNC_DEBUG6 = 230, /*!< Debug function 6 */ + FUNC_DEBUG7 = 231, /*!< Debug function 7 */ + FUNC_DEBUG8 = 232, /*!< Debug function 8 */ + FUNC_DEBUG9 = 233, /*!< Debug function 9 */ + FUNC_DEBUG10 = 234, /*!< Debug function 10 */ + FUNC_DEBUG11 = 235, /*!< Debug function 11 */ + FUNC_DEBUG12 = 236, /*!< Debug function 12 */ + FUNC_DEBUG13 = 237, /*!< Debug function 13 */ + FUNC_DEBUG14 = 238, /*!< Debug function 14 */ + FUNC_DEBUG15 = 239, /*!< Debug function 15 */ + FUNC_DEBUG16 = 240, /*!< Debug function 16 */ + FUNC_DEBUG17 = 241, /*!< Debug function 17 */ + FUNC_DEBUG18 = 242, /*!< Debug function 18 */ + FUNC_DEBUG19 = 243, /*!< Debug function 19 */ + FUNC_DEBUG20 = 244, /*!< Debug function 20 */ + FUNC_DEBUG21 = 245, /*!< Debug function 21 */ + FUNC_DEBUG22 = 246, /*!< Debug function 22 */ + FUNC_DEBUG23 = 247, /*!< Debug function 23 */ + FUNC_DEBUG24 = 248, /*!< Debug function 24 */ + FUNC_DEBUG25 = 249, /*!< Debug function 25 */ + FUNC_DEBUG26 = 250, /*!< Debug function 26 */ + FUNC_DEBUG27 = 251, /*!< Debug function 27 */ + FUNC_DEBUG28 = 252, /*!< Debug function 28 */ + FUNC_DEBUG29 = 253, /*!< Debug function 29 */ + FUNC_DEBUG30 = 254, /*!< Debug function 30 */ + FUNC_DEBUG31 = 255, /*!< Debug function 31 */ + FUNC_MAX = 256, /*!< Function numbers */ +} fpioa_function_t; +/* clang-format on */ + +/** + * @brief FPIOA pull settings + * + * @note FPIOA pull settings description + * + * | PU | PD | Description | + * |-----|-----|-----------------------------------| + * | 0 | 0 | No Pull | + * | 0 | 1 | Pull Down | + * | 1 | 0 | Pull Up | + * | 1 | 1 | Undefined | + * + */ + +/* clang-format off */ +typedef enum _fpioa_pull +{ + FPIOA_PULL_NONE, /*!< No Pull */ + FPIOA_PULL_DOWN, /*!< Pull Down */ + FPIOA_PULL_UP, /*!< Pull Up */ + FPIOA_PULL_MAX /*!< Count of pull settings */ +} fpioa_pull_t; +/* clang-format on */ + +/** + * @brief FPIOA driving settings + * + * @note FPIOA driving settings description + * There are 16 kinds of driving settings + * + * @note Low Level Output Current + * + * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)| + * |--------|-------|-------|-------| + * |0000 |3.2 |5.4 |8.3 | + * |0001 |4.7 |8.0 |12.3 | + * |0010 |6.3 |10.7 |16.4 | + * |0011 |7.8 |13.2 |20.2 | + * |0100 |9.4 |15.9 |24.2 | + * |0101 |10.9 |18.4 |28.1 | + * |0110 |12.4 |20.9 |31.8 | + * |0111 |13.9 |23.4 |35.5 | + * + * @note High Level Output Current + * + * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)| + * |--------|-------|-------|-------| + * |0000 |5.0 |7.6 |11.2 | + * |0001 |7.5 |11.4 |16.8 | + * |0010 |10.0 |15.2 |22.3 | + * |0011 |12.4 |18.9 |27.8 | + * |0100 |14.9 |22.6 |33.3 | + * |0101 |17.4 |26.3 |38.7 | + * |0110 |19.8 |30.0 |44.1 | + * |0111 |22.3 |33.7 |49.5 | + * + */ + +/* clang-format off */ +typedef enum _fpioa_driving +{ + FPIOA_DRIVING_0, /*!< 0000 */ + FPIOA_DRIVING_1, /*!< 0001 */ + FPIOA_DRIVING_2, /*!< 0010 */ + FPIOA_DRIVING_3, /*!< 0011 */ + FPIOA_DRIVING_4, /*!< 0100 */ + FPIOA_DRIVING_5, /*!< 0101 */ + FPIOA_DRIVING_6, /*!< 0110 */ + FPIOA_DRIVING_7, /*!< 0111 */ + FPIOA_DRIVING_8, /*!< 1000 */ + FPIOA_DRIVING_9, /*!< 1001 */ + FPIOA_DRIVING_10, /*!< 1010 */ + FPIOA_DRIVING_11, /*!< 1011 */ + FPIOA_DRIVING_12, /*!< 1100 */ + FPIOA_DRIVING_13, /*!< 1101 */ + FPIOA_DRIVING_14, /*!< 1110 */ + FPIOA_DRIVING_15, /*!< 1111 */ + FPIOA_DRIVING_MAX /*!< Count of driving settings */ +} fpioa_driving_t; +/* clang-format on */ + +/** + * @brief FPIOA IO + * + * FPIOA IO is the specific pin of the chip package. Every IO + * has a 32bit width register that can independently implement + * schmitt trigger, invert input, invert output, strong pull + * up, driving selector, static input and static output. And more, + * it can implement any pin of any peripheral devices. + * + * @note FPIOA IO's register bits Layout + * + * | Bits | Name |Description | + * |-----------|----------|---------------------------------------------------| + * | 31 | PAD_DI | Read current IO's data input. | + * | 30:24 | NA | Reserved bits. | + * | 23 | ST | Schmitt trigger. | + * | 22 | DI_INV | Invert Data input. | + * | 21 | IE_INV | Invert the input enable signal. | + * | 20 | IE_EN | Input enable. It can disable or enable IO input. | + * | 19 | SL | Slew rate control enable. | + * | 18 | SPU | Strong pull up. | + * | 17 | PD | Pull select: 0 for pull down, 1 for pull up. | + * | 16 | PU | Pull enable. | + * | 15 | DO_INV | Invert the result of data output select (DO_SEL). | + * | 14 | DO_SEL | Data output select: 0 for DO, 1 for OE. | + * | 13 | OE_INV | Invert the output enable signal. | + * | 12 | OE_EN | Output enable.It can disable or enable IO output. | + * | 11:8 | DS | Driving selector. | + * | 7:0 | CH_SEL | Channel select from 256 input. | + * + */ +typedef struct _fpioa_io_config +{ + uint32_t ch_sel : 8; + /*!< Channel select from 256 input. */ + uint32_t ds : 4; + /*!< Driving selector. */ + uint32_t oe_en : 1; + /*!< Static output enable, will AND with OE_INV. */ + uint32_t oe_inv : 1; + /*!< Invert output enable. */ + uint32_t do_sel : 1; + /*!< Data output select: 0 for DO, 1 for OE. */ + uint32_t do_inv : 1; + /*!< Invert the result of data output select (DO_SEL). */ + uint32_t pu : 1; + /*!< Pull up enable. 0 for nothing, 1 for pull up. */ + uint32_t pd : 1; + /*!< Pull down enable. 0 for nothing, 1 for pull down. */ + uint32_t resv0 : 1; + /*!< Reserved bits. */ + uint32_t sl : 1; + /*!< Slew rate control enable. */ + uint32_t ie_en : 1; + /*!< Static input enable, will AND with IE_INV. */ + uint32_t ie_inv : 1; + /*!< Invert input enable. */ + uint32_t di_inv : 1; + /*!< Invert Data input. */ + uint32_t st : 1; + /*!< Schmitt trigger. */ + uint32_t resv1 : 7; + /*!< Reserved bits. */ + uint32_t pad_di : 1; + /*!< Read current IO's data input. */ +} __attribute__((packed, aligned(4))) fpioa_io_config_t; + +/** + * @brief FPIOA tie setting + * + * FPIOA Object have 48 IO pin object and 256 bit input tie bits. + * All SPI arbitration signal will tie high by default. + * + * @note FPIOA function tie bits RAM Layout + * + * | Address | Name |Description | + * |-----------|------------------|----------------------------------| + * | 0x000 | TIE_EN[31:0] | Input tie enable bits [31:0] | + * | 0x004 | TIE_EN[63:32] | Input tie enable bits [63:32] | + * | 0x008 | TIE_EN[95:64] | Input tie enable bits [95:64] | + * | 0x00C | TIE_EN[127:96] | Input tie enable bits [127:96] | + * | 0x010 | TIE_EN[159:128] | Input tie enable bits [159:128] | + * | 0x014 | TIE_EN[191:160] | Input tie enable bits [191:160] | + * | 0x018 | TIE_EN[223:192] | Input tie enable bits [223:192] | + * | 0x01C | TIE_EN[255:224] | Input tie enable bits [255:224] | + * | 0x020 | TIE_VAL[31:0] | Input tie value bits [31:0] | + * | 0x024 | TIE_VAL[63:32] | Input tie value bits [63:32] | + * | 0x028 | TIE_VAL[95:64] | Input tie value bits [95:64] | + * | 0x02C | TIE_VAL[127:96] | Input tie value bits [127:96] | + * | 0x030 | TIE_VAL[159:128] | Input tie value bits [159:128] | + * | 0x034 | TIE_VAL[191:160] | Input tie value bits [191:160] | + * | 0x038 | TIE_VAL[223:192] | Input tie value bits [223:192] | + * | 0x03C | TIE_VAL[255:224] | Input tie value bits [255:224] | + * + * @note Function which input tie high by default + * + * | Name |Description | + * |---------------|---------------------------------------| + * | SPI0_ARB | Arbitration function of SPI master 0 | + * | SPI1_ARB | Arbitration function of SPI master 1 | + * + * Tie high means the SPI Arbitration input is 1 + * + */ +typedef struct _fpioa_tie +{ + uint32_t en[FUNC_MAX / 32]; + /*!< FPIOA GPIO multiplexer tie enable array */ + uint32_t val[FUNC_MAX / 32]; + /*!< FPIOA GPIO multiplexer tie value array */ +} __attribute__((packed, aligned(4))) fpioa_tie_t; + +/** + * @brief FPIOA Object + * + * FPIOA Object have 48 IO pin object and 256 bit input tie bits. + * All SPI arbitration signal will tie high by default. + * + * @note FPIOA IO Pin RAM Layout + * + * | Address | Name |Description | + * |-----------|----------|--------------------------------| + * | 0x000 | PAD0 | FPIOA GPIO multiplexer io 0 | + * | 0x004 | PAD1 | FPIOA GPIO multiplexer io 1 | + * | 0x008 | PAD2 | FPIOA GPIO multiplexer io 2 | + * | 0x00C | PAD3 | FPIOA GPIO multiplexer io 3 | + * | 0x010 | PAD4 | FPIOA GPIO multiplexer io 4 | + * | 0x014 | PAD5 | FPIOA GPIO multiplexer io 5 | + * | 0x018 | PAD6 | FPIOA GPIO multiplexer io 6 | + * | 0x01C | PAD7 | FPIOA GPIO multiplexer io 7 | + * | 0x020 | PAD8 | FPIOA GPIO multiplexer io 8 | + * | 0x024 | PAD9 | FPIOA GPIO multiplexer io 9 | + * | 0x028 | PAD10 | FPIOA GPIO multiplexer io 10 | + * | 0x02C | PAD11 | FPIOA GPIO multiplexer io 11 | + * | 0x030 | PAD12 | FPIOA GPIO multiplexer io 12 | + * | 0x034 | PAD13 | FPIOA GPIO multiplexer io 13 | + * | 0x038 | PAD14 | FPIOA GPIO multiplexer io 14 | + * | 0x03C | PAD15 | FPIOA GPIO multiplexer io 15 | + * | 0x040 | PAD16 | FPIOA GPIO multiplexer io 16 | + * | 0x044 | PAD17 | FPIOA GPIO multiplexer io 17 | + * | 0x048 | PAD18 | FPIOA GPIO multiplexer io 18 | + * | 0x04C | PAD19 | FPIOA GPIO multiplexer io 19 | + * | 0x050 | PAD20 | FPIOA GPIO multiplexer io 20 | + * | 0x054 | PAD21 | FPIOA GPIO multiplexer io 21 | + * | 0x058 | PAD22 | FPIOA GPIO multiplexer io 22 | + * | 0x05C | PAD23 | FPIOA GPIO multiplexer io 23 | + * | 0x060 | PAD24 | FPIOA GPIO multiplexer io 24 | + * | 0x064 | PAD25 | FPIOA GPIO multiplexer io 25 | + * | 0x068 | PAD26 | FPIOA GPIO multiplexer io 26 | + * | 0x06C | PAD27 | FPIOA GPIO multiplexer io 27 | + * | 0x070 | PAD28 | FPIOA GPIO multiplexer io 28 | + * | 0x074 | PAD29 | FPIOA GPIO multiplexer io 29 | + * | 0x078 | PAD30 | FPIOA GPIO multiplexer io 30 | + * | 0x07C | PAD31 | FPIOA GPIO multiplexer io 31 | + * | 0x080 | PAD32 | FPIOA GPIO multiplexer io 32 | + * | 0x084 | PAD33 | FPIOA GPIO multiplexer io 33 | + * | 0x088 | PAD34 | FPIOA GPIO multiplexer io 34 | + * | 0x08C | PAD35 | FPIOA GPIO multiplexer io 35 | + * | 0x090 | PAD36 | FPIOA GPIO multiplexer io 36 | + * | 0x094 | PAD37 | FPIOA GPIO multiplexer io 37 | + * | 0x098 | PAD38 | FPIOA GPIO multiplexer io 38 | + * | 0x09C | PAD39 | FPIOA GPIO multiplexer io 39 | + * | 0x0A0 | PAD40 | FPIOA GPIO multiplexer io 40 | + * | 0x0A4 | PAD41 | FPIOA GPIO multiplexer io 41 | + * | 0x0A8 | PAD42 | FPIOA GPIO multiplexer io 42 | + * | 0x0AC | PAD43 | FPIOA GPIO multiplexer io 43 | + * | 0x0B0 | PAD44 | FPIOA GPIO multiplexer io 44 | + * | 0x0B4 | PAD45 | FPIOA GPIO multiplexer io 45 | + * | 0x0B8 | PAD46 | FPIOA GPIO multiplexer io 46 | + * | 0x0BC | PAD47 | FPIOA GPIO multiplexer io 47 | + * + */ +typedef struct _fpioa +{ + fpioa_io_config_t io[FPIOA_NUM_IO]; + /*!< FPIOA GPIO multiplexer io array */ + fpioa_tie_t tie; + /*!< FPIOA GPIO multiplexer tie */ +} __attribute__((packed, aligned(4))) fpioa_t; + +/** + * @brief FPIOA object instanse + */ +extern volatile fpioa_t *const fpioa; + +/** + * @brief Initialize FPIOA user custom default settings + * + * @note This function will set all FPIOA pad registers to user-defined + * values from kconfig + * + * @return result + * - 0 Success + * - Other Fail + */ +int FpioaInit(void); + +/** + * @brief Get IO configuration + * + * @param[in] number The IO number + * @param cfg Pointer to struct of IO configuration for specified IO + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_get_io(int number, fpioa_io_config_t *cfg); + +/** + * @brief Set IO configuration + * + * @param[in] number The IO number + * @param[in] cfg Pointer to struct of IO configuration for specified IO + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io(int number, fpioa_io_config_t *cfg); + +/** + * @brief Set IO configuration with function number + * + * @note The default IO configuration which bind to function number will + * set automatically + * + * @param[in] number The IO number + * @param[in] function The function enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_function_raw(int number, fpioa_function_t function); + +/** + * @brief Set only IO configuration with function number + * + * @note The default IO configuration which bind to function number will + * set automatically + * + * @param[in] number The IO number + * @param[in] function The function enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int FpioaSetFunction(int number, fpioa_function_t function); + +/** + * @brief Set tie enable to function + * + * @param[in] function The function enum number + * @param[in] enable Tie enable to set, 1 is enable, 0 is disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_tie_enable(fpioa_function_t function, int enable); + +/** + * @brief Set tie value to function + * + * @param[in] function The function enum number + * @param[in] value Tie value to set, 1 is HIGH, 0 is LOW + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_tie_value(fpioa_function_t function, int value); + +/** + * @brief Set IO pull function + * + * @param[in] number The IO number + * @param[in] pull The pull enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io_pull(int number, fpioa_pull_t pull); + +/** + * @brief Get IO pull function + * + * @param[in] number The IO number + * + * @return result + * - -1 Fail + * - Other The pull enum number + */ +int fpioa_get_io_pull(int number); + +/** + * @brief Set IO driving + * + * @param[in] number The IO number + * @param[in] driving The driving enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io_driving(int number, fpioa_driving_t driving); + +/** + * @brief Get IO driving + * + * @param[in] number The IO number + * + * @return result + * - -1 Fail + * - Other The driving enum number + */ +int fpioa_get_io_driving(int number); + +/** + * @brief Get IO by function + * + * @param[in] function The function enum number + * + * @return result + * - -1 Fail + * - Other The IO number + */ +int fpioa_get_io_by_function(fpioa_function_t function); + +/** + * @brief Set IO slew rate control + * + * @param[in] number The IO number + * @param[in] sl_value Enable slew rate. 0: disable 1:enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_sl(int number, uint8_t sl_enable); + +/** + * @brief Set IO slew rate + * + * @param[in] number The IO number + * @param[in] st_enable Enable schmitt trigger. 0: disable 1:enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_st(int number, uint8_t st_enable); + +#ifdef __cplusplus +} +#endif + +#endif /* __FPIOA_H__ */ + diff --git a/board/k210-emulator/third_party_driver/include/gpio.h b/board/k210-emulator/third_party_driver/include/gpio.h new file mode 100644 index 00000000..223f4d0f --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/gpio.h @@ -0,0 +1,178 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 gpio.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#include "platform.h" +#include +#include +#include "gpio_common.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Structure for accessing GPIO registers by individual bit + */ +typedef struct _gpio_bits +{ + uint32_t b0 : 1; + uint32_t b1 : 1; + uint32_t b2 : 1; + uint32_t b3 : 1; + uint32_t b4 : 1; + uint32_t b5 : 1; + uint32_t b6 : 1; + uint32_t b7 : 1; + uint32_t b8 : 1; + uint32_t b9 : 1; + uint32_t b10 : 1; + uint32_t b11 : 1; + uint32_t b12 : 1; + uint32_t b13 : 1; + uint32_t b14 : 1; + uint32_t b15 : 1; + uint32_t b16 : 1; + uint32_t b17 : 1; + uint32_t b18 : 1; + uint32_t b19 : 1; + uint32_t b20 : 1; + uint32_t b21 : 1; + uint32_t b22 : 1; + uint32_t b23 : 1; + uint32_t b24 : 1; + uint32_t b25 : 1; + uint32_t b26 : 1; + uint32_t b27 : 1; + uint32_t b28 : 1; + uint32_t b29 : 1; + uint32_t b30 : 1; + uint32_t b31 : 1; +} __attribute__((packed, aligned(4))) gpio_bits_t; + +/** + * @brief Structure of templates for accessing GPIO registers + */ +typedef union _gpio_access_tp +{ + /* 32x1 bit mode */ + uint32_t u32[1]; + /* 16x2 bit mode */ + uint16_t u16[2]; + /* 8x4 bit mode */ + uint8_t u8[4]; + /* 1 bit mode */ + gpio_bits_t bits; +} __attribute__((packed, aligned(4))) gpio_access_tp_t; + +/** + * @brief The GPIO address map + */ +typedef struct _gpio +{ + /* Offset 0x00: Data (output) registers */ + gpio_access_tp_t data_output; + /* Offset 0x04: Data direction registers */ + gpio_access_tp_t direction; + /* Offset 0x08: Data source registers */ + gpio_access_tp_t source; + /* Offset 0x10 - 0x2f: Unused registers, 9x4 bytes */ + uint32_t unused_0[9]; + /* Offset 0x30: Interrupt enable/disable registers */ + gpio_access_tp_t interrupt_enable; + /* Offset 0x34: Interrupt mask registers */ + gpio_access_tp_t interrupt_mask; + /* Offset 0x38: Interrupt level registers */ + gpio_access_tp_t interrupt_level; + /* Offset 0x3c: Interrupt polarity registers */ + gpio_access_tp_t interrupt_polarity; + /* Offset 0x40: Interrupt status registers */ + gpio_access_tp_t interrupt_status; + /* Offset 0x44: Raw interrupt status registers */ + gpio_access_tp_t interrupt_status_raw; + /* Offset 0x48: Interrupt debounce registers */ + gpio_access_tp_t interrupt_debounce; + /* Offset 0x4c: Registers for clearing interrupts */ + gpio_access_tp_t interrupt_clear; + /* Offset 0x50: External port (data input) registers */ + gpio_access_tp_t data_input; + /* Offset 0x54 - 0x5f: Unused registers, 3x4 bytes */ + uint32_t unused_1[3]; + /* Offset 0x60: Sync level registers */ + gpio_access_tp_t sync_level; + /* Offset 0x64: ID code */ + gpio_access_tp_t id_code; + /* Offset 0x68: Interrupt both edge type */ + gpio_access_tp_t interrupt_bothedge; + +} __attribute__((packed, aligned(4))) gpio_t; + +/** + * @brief Bus GPIO object instance + */ +extern volatile gpio_t *const gpio; + +/** + * @brief Gpio initialize + * + * @return Result + * - 0 Success + * - Other Fail + */ +int gpio_init(void); + +/** + * @brief Set Gpio drive mode + * + * @param[in] pin Gpio pin + * @param[in] mode Gpio pin drive mode + */ +void gpio_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode); + +/** + * @brief Get Gpio pin value + * + * @param[in] pin Gpio pin + * @return Pin value + * + * - GPIO_PV_Low Gpio pin low + * - GPIO_PV_High Gpio pin high + */ +gpio_pin_value_t gpio_get_pin(uint8_t pin); + +/** + * @brief Set Gpio pin value + * + * @param[in] pin Gpio pin + * @param[in] value Gpio pin value + */ +void gpio_set_pin(uint8_t pin, gpio_pin_value_t value); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPIO_H__ */ + diff --git a/board/k210-emulator/third_party_driver/include/gpio_common.h b/board/k210-emulator/third_party_driver/include/gpio_common.h new file mode 100644 index 00000000..8a91216a --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/gpio_common.h @@ -0,0 +1,61 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 gpio_common.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __GPIO_COMMON_H__ +#define __GPIO_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _gpio_drive_mode +{ + GPIO_DM_INPUT, + GPIO_DM_INPUT_PULL_DOWN, + GPIO_DM_INPUT_PULL_UP, + GPIO_DM_OUTPUT, +} gpio_drive_mode_t; + +typedef enum _gpio_pin_edge +{ + GPIO_PE_NONE, + GPIO_PE_FALLING, + GPIO_PE_RISING, + GPIO_PE_BOTH, + GPIO_PE_LOW, + GPIO_PE_HIGH = 8, +} GpioPinEdgeT; + +typedef enum _gpio_pin_value +{ + GPIO_PV_LOW, + GPIO_PV_HIGH +} gpio_pin_value_t; + +#ifdef __cplusplus +} +#endif + +#endif /* __GPIO_COMMON_H__ */ + diff --git a/board/k210-emulator/third_party_driver/include/gpiohs.h b/board/k210-emulator/third_party_driver/include/gpiohs.h new file mode 100644 index 00000000..ea0a0784 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/gpiohs.h @@ -0,0 +1,277 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 gpiohs.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __GPIOHS_H__ +#define __GPIOHS_H__ + +#include +#include "platform.h" +#include +#include "gpio_common.h" +#include "plic.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define GPIOHS_INPUT_VAL (0x00) +#define GPIOHS_INPUT_EN (0x04) +#define GPIOHS_OUTPUT_EN (0x08) +#define GPIOHS_OUTPUT_VAL (0x0C) +#define GPIOHS_PULLUP_EN (0x10) +#define GPIOHS_DRIVE (0x14) +#define GPIOHS_RISE_IE (0x18) +#define GPIOHS_RISE_IP (0x1C) +#define GPIOHS_FALL_IE (0x20) +#define GPIOHS_FALL_IP (0x24) +#define GPIOHS_HIGH_IE (0x28) +#define GPIOHS_HIGH_IP (0x2C) +#define GPIOHS_LOW_IE (0x30) +#define GPIOHS_LOW_IP (0x34) +#define GPIOHS_IOF_EN (0x38) +#define GPIOHS_IOF_SEL (0x3C) +#define GPIOHS_OUTPUT_XOR (0x40) +/* clang-format on */ + +/** + * @brief GPIO bits raw object + */ +typedef struct _gpiohs_raw +{ + /* Address offset 0x00 */ + uint32_t input_val; + /* Address offset 0x04 */ + uint32_t input_en; + /* Address offset 0x08 */ + uint32_t output_en; + /* Address offset 0x0c */ + uint32_t output_val; + /* Address offset 0x10 */ + uint32_t pullup_en; + /* Address offset 0x14 */ + uint32_t drive; + /* Address offset 0x18 */ + uint32_t rise_ie; + /* Address offset 0x1c */ + uint32_t rise_ip; + /* Address offset 0x20 */ + uint32_t fall_ie; + /* Address offset 0x24 */ + uint32_t fall_ip; + /* Address offset 0x28 */ + uint32_t high_ie; + /* Address offset 0x2c */ + uint32_t high_ip; + /* Address offset 0x30 */ + uint32_t low_ie; + /* Address offset 0x34 */ + uint32_t low_ip; + /* Address offset 0x38 */ + uint32_t iof_en; + /* Address offset 0x3c */ + uint32_t iof_sel; + /* Address offset 0x40 */ + uint32_t output_xor; +} __attribute__((packed, aligned(4))) gpiohs_raw_t; + +/** + * @brief GPIO bits object + */ +typedef struct _gpiohs_bits +{ + uint32_t b0 : 1; + uint32_t b1 : 1; + uint32_t b2 : 1; + uint32_t b3 : 1; + uint32_t b4 : 1; + uint32_t b5 : 1; + uint32_t b6 : 1; + uint32_t b7 : 1; + uint32_t b8 : 1; + uint32_t b9 : 1; + uint32_t b10 : 1; + uint32_t b11 : 1; + uint32_t b12 : 1; + uint32_t b13 : 1; + uint32_t b14 : 1; + uint32_t b15 : 1; + uint32_t b16 : 1; + uint32_t b17 : 1; + uint32_t b18 : 1; + uint32_t b19 : 1; + uint32_t b20 : 1; + uint32_t b21 : 1; + uint32_t b22 : 1; + uint32_t b23 : 1; + uint32_t b24 : 1; + uint32_t b25 : 1; + uint32_t b26 : 1; + uint32_t b27 : 1; + uint32_t b28 : 1; + uint32_t b29 : 1; + uint32_t b30 : 1; + uint32_t b31 : 1; +} __attribute__((packed, aligned(4))) gpiohs_bits_t; + +/** + * @brief GPIO bits multi access union + */ +typedef union _gpiohs_u32 +{ + /* 32x1 bit mode */ + uint32_t u32[1]; + /* 16x2 bit mode */ + uint16_t u16[2]; + /* 8x4 bit mode */ + uint8_t u8[4]; + /* 1 bit mode */ + gpiohs_bits_t bits; +} __attribute__((packed, aligned(4))) gpiohs_u32_t; + +/** + * @brief GPIO object + * + * The GPIO controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of the actual + * GPIO pads on the device (direction, pull up-enable, and drive + * value), as well as selecting between various sources of the + * controls for these signals. The GPIO controller allows seperate + * configuration of each of N GPIO bits. + * + * Once the interrupt is pending, it will remain set until a 1 is + * written to the *_ip register at that bit. + */ + +typedef struct _gpiohs +{ + /* Address offset 0x00, Input Values */ + gpiohs_u32_t input_val; + /* Address offset 0x04, Input enable */ + gpiohs_u32_t input_en; + /* Address offset 0x08, Output enable */ + gpiohs_u32_t output_en; + /* Address offset 0x0c, Onput Values */ + gpiohs_u32_t output_val; + /* Address offset 0x10, Internal Pull-Ups enable */ + gpiohs_u32_t pullup_en; + /* Address offset 0x14, Drive Strength */ + gpiohs_u32_t drive; + /* Address offset 0x18, Rise interrupt enable */ + gpiohs_u32_t rise_ie; + /* Address offset 0x1c, Rise interrupt pending */ + gpiohs_u32_t rise_ip; + /* Address offset 0x20, Fall interrupt enable */ + gpiohs_u32_t fall_ie; + /* Address offset 0x24, Fall interrupt pending */ + gpiohs_u32_t fall_ip; + /* Address offset 0x28, High interrupt enable */ + gpiohs_u32_t high_ie; + /* Address offset 0x2c, High interrupt pending */ + gpiohs_u32_t high_ip; + /* Address offset 0x30, Low interrupt enable */ + gpiohs_u32_t low_ie; + /* Address offset 0x34, Low interrupt pending */ + gpiohs_u32_t low_ip; + /* Address offset 0x38, HW I/O Function enable */ + gpiohs_u32_t iof_en; + /* Address offset 0x3c, HW I/O Function select */ + gpiohs_u32_t iof_sel; + /* Address offset 0x40, Output XOR (invert) */ + gpiohs_u32_t output_xor; +} __attribute__((packed, aligned(4))) gpiohs_t; + +/** + * @brief GPIO High-speed object instanse + */ +extern volatile gpiohs_t *const gpiohs; + +/** + * @brief Set Gpiohs drive mode + * + * @param[in] pin Gpiohs pin + * @param[in] mode Gpiohs pin drive mode + */ +void gpiohs_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode); + +/** + * @brief Get Gpiohs pin value + * + * @param[in] pin Gpiohs pin + * @return Pin value + * + * - GPIO_PV_Low Gpiohs pin low + * - GPIO_PV_High Gpiohs pin high + */ +gpio_pin_value_t gpiohs_get_pin(uint8_t pin); + +/** + * @brief Set Gpiohs pin value + * + * @param[in] pin Gpiohs pin + * @param[in] value Gpiohs pin value + */ +void gpiohs_set_pin(uint8_t pin, gpio_pin_value_t value); + +/** + * @brief Set Gpiohs pin edge for interrupt + * + * @param[in] pin Gpiohs pin + * @param[in] edge Gpiohs pin edge type + */ +void gpiohs_set_pin_edge(uint8_t pin, GpioPinEdgeT edge); + +/** + * @brief Set Gpiohs pin interrupt + * + * @param[in] pin Gpiohs pin + * @param[in] priority Gpiohs pin interrupt priority + * @param[in] func Gpiohs pin interrupt service routine + */ +void gpiohs_set_irq(uint8_t pin, uint32_t priority, void(*func)()); + +/** + * @brief Set Gpiohs pin interrupt + * + * @param[in] pin Gpiohs pin + * @param[in] priority Gpiohs pin interrupt priority + * @param[in] callback Gpiohs pin interrupt service routine + * @param[in] ctx Gpiohs interrupt param + */ +void gpiohs_irq_register(uint8_t pin, uint32_t priority, plic_irq_callback_t callback, void *ctx); + +/** + * @brief Unregister Gpiohs pin interrupt + * + * @param[in] pin Gpiohs pin + */ +void gpiohs_irq_unregister(uint8_t pin); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPIOHS_H__ */ + diff --git a/board/k210-emulator/third_party_driver/include/hardware_hwtimer.h b/board/k210-emulator/third_party_driver/include/hardware_hwtimer.h new file mode 100644 index 00000000..57ac51a3 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/hardware_hwtimer.h @@ -0,0 +1,171 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_hwtimer.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __HARDWARE_HWTIMER_H__ +#define __HARDWARE_HWTIMER_H__ + +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _timer_channel +{ + /* TIMER_N Load Count Register (0x00+(N-1)*0x14) */ + volatile uint32_t load_count; + /* TIMER_N Current Value Register (0x04+(N-1)*0x14) */ + volatile uint32_t current_value; + /* TIMER_N Control Register (0x08+(N-1)*0x14) */ + volatile uint32_t control; + /* TIMER_N Interrupt Clear Register (0x0c+(N-1)*0x14) */ + volatile uint32_t eoi; + /* TIMER_N Interrupt Status Register (0x10+(N-1)*0x14) */ + volatile uint32_t intr_stat; +} __attribute__((packed, aligned(4))) timer_channel_t; + +typedef struct _kendryte_timer +{ + /* TIMER_N Register (0x00-0x4c) */ + volatile timer_channel_t channel[4]; + /* reserverd (0x50-0x9c) */ + volatile uint32_t resv1[20]; + /* TIMER Interrupt Status Register (0xa0) */ + volatile uint32_t intr_stat; + /* TIMER Interrupt Clear Register (0xa4) */ + volatile uint32_t eoi; + /* TIMER Raw Interrupt Status Register (0xa8) */ + volatile uint32_t raw_intr_stat; + /* TIMER Component Version Register (0xac) */ + volatile uint32_t comp_version; + /* TIMER_N Load Count2 Register (0xb0-0xbc) */ + volatile uint32_t load_count2[4]; +} __attribute__((packed, aligned(4))) kendryte_timer_t; + +typedef enum _timer_deivce_number +{ + TIMER_DEVICE_0, + TIMER_DEVICE_1, + TIMER_DEVICE_2, + TIMER_DEVICE_MAX, +} timer_device_number_t; + +typedef enum _timer_channel_number +{ + TIMER_CHANNEL_0, + TIMER_CHANNEL_1, + TIMER_CHANNEL_2, + TIMER_CHANNEL_3, + TIMER_CHANNEL_MAX, +} timer_channel_number_t; + +/* TIMER Control Register */ +#define TIMER_CR_ENABLE 0x00000001 +#define TIMER_CR_MODE_MASK 0x00000002 +#define TIMER_CR_FREE_MODE 0x00000000 +#define TIMER_CR_USER_MODE 0x00000002 +#define TIMER_CR_INTERRUPT_MASK 0x00000004 +#define TIMER_CR_PWM_ENABLE 0x00000008 +/* clang-format on */ + +extern volatile kendryte_timer_t *const timer[3]; + +/** + * @brief Definitions for the timer callbacks + */ +typedef int (*timer_callback_t)(void *ctx); + +/** + * @brief Set timer timeout + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] nanoseconds timeout + * + * @return the real timeout + */ +size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t nanoseconds); + +/** + * @brief Init timer + * + * @param[in] timer timer + */ +void timer_init(timer_device_number_t timer_number); + +/** + * @brief [DEPRECATED] Set timer timeout function + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] func timeout function + * @param[in] priority interrupt priority + * + */ +void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority); + +/** + * @brief Register timer interrupt user callback function + * + * @param[in] device The timer device number + * @param[in] channel The channel + * @param[in] is_one_shot Indicates if single shot + * @param[in] priority The priority + * @param[in] callback The callback function + * @param[in] ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx); + +/** + * @brief Deregister timer interrupt user callback function + * + * @param[in] device The timer device number + * @param[in] channel The channel + * + * @return result + * - 0 Success + * - Other Fail + */ +int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel); + +/** + * @brief Enable timer + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] enable Enable or disable + * + */ +void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIMER_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/hardware_i2c.h b/board/k210-emulator/third_party_driver/include/hardware_i2c.h new file mode 100644 index 00000000..2ff74705 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/hardware_i2c.h @@ -0,0 +1,482 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_i2c.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __HARDWARE_I2C_H__ +#define __HARDWARE_I2C_H__ + +#include +#include +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2C_MAX_NUM 3 + +/* clang-format off */ +typedef struct _i2c +{ + /* I2C Control Register (0x00) */ + volatile uint32_t con; + /* I2C Target Address Register (0x04) */ + volatile uint32_t tar; + /* I2C Slave Address Register (0x08) */ + volatile uint32_t sar; + /* reserved (0x0c) */ + volatile uint32_t resv1; + /* I2C Data Buffer and Command Register (0x10) */ + volatile uint32_t data_cmd; + /* I2C Standard Speed Clock SCL High Count Register (0x14) */ + volatile uint32_t ss_scl_hcnt; + /* I2C Standard Speed Clock SCL Low Count Register (0x18) */ + volatile uint32_t ss_scl_lcnt; + /* reserverd (0x1c-0x28) */ + volatile uint32_t resv2[4]; + /* I2C Interrupt Status Register (0x2c) */ + volatile uint32_t intr_stat; + /* I2C Interrupt Mask Register (0x30) */ + volatile uint32_t intr_mask; + /* I2C Raw Interrupt Status Register (0x34) */ + volatile uint32_t raw_intr_stat; + /* I2C Receive FIFO Threshold Register (0x38) */ + volatile uint32_t rx_tl; + /* I2C Transmit FIFO Threshold Register (0x3c) */ + volatile uint32_t tx_tl; + /* I2C Clear Combined and Individual Interrupt Register (0x40) */ + volatile uint32_t clr_intr; + /* I2C Clear RX_UNDER Interrupt Register (0x44) */ + volatile uint32_t clr_rx_under; + /* I2C Clear RX_OVER Interrupt Register (0x48) */ + volatile uint32_t clr_rx_over; + /* I2C Clear TX_OVER Interrupt Register (0x4c) */ + volatile uint32_t clr_tx_over; + /* I2C Clear RD_REQ Interrupt Register (0x50) */ + volatile uint32_t clr_rd_req; + /* I2C Clear TX_ABRT Interrupt Register (0x54) */ + volatile uint32_t clr_tx_abrt; + /* I2C Clear RX_DONE Interrupt Register (0x58) */ + volatile uint32_t clr_rx_done; + /* I2C Clear ACTIVITY Interrupt Register (0x5c) */ + volatile uint32_t clr_activity; + /* I2C Clear STOP_DET Interrupt Register (0x60) */ + volatile uint32_t clr_stop_det; + /* I2C Clear START_DET Interrupt Register (0x64) */ + volatile uint32_t clr_start_det; + /* I2C Clear GEN_CALL Interrupt Register (0x68) */ + volatile uint32_t clr_gen_call; + /* I2C Enable Register (0x6c) */ + volatile uint32_t enable; + /* I2C Status Register (0x70) */ + volatile uint32_t status; + /* I2C Transmit FIFO Level Register (0x74) */ + volatile uint32_t txflr; + /* I2C Receive FIFO Level Register (0x78) */ + volatile uint32_t rxflr; + /* I2C SDA Hold Time Length Register (0x7c) */ + volatile uint32_t sda_hold; + /* I2C Transmit Abort Source Register (0x80) */ + volatile uint32_t tx_abrt_source; + /* reserved (0x84) */ + volatile uint32_t resv3; + /* I2C DMA Control Register (0x88) */ + volatile uint32_t dma_cr; + /* I2C DMA Transmit Data Level Register (0x8c) */ + volatile uint32_t dma_tdlr; + /* I2C DMA Receive Data Level Register (0x90) */ + volatile uint32_t dma_rdlr; + /* I2C SDA Setup Register (0x94) */ + volatile uint32_t sda_setup; + /* I2C ACK General Call Register (0x98) */ + volatile uint32_t general_call; + /* I2C Enable Status Register (0x9c) */ + volatile uint32_t enable_status; + /* I2C SS, FS or FM+ spike suppression limit (0xa0) */ + volatile uint32_t fs_spklen; + /* reserved (0xa4-0xf0) */ + volatile uint32_t resv4[20]; + /* I2C Component Parameter Register 1 (0xf4) */ + volatile uint32_t comp_param_1; + /* I2C Component Version Register (0xf8) */ + volatile uint32_t comp_version; + /* I2C Component Type Register (0xfc) */ + volatile uint32_t comp_type; +} __attribute__((packed, aligned(4))) i2c_t; + +/* I2C Control Register*/ +#define I2C_CON_MASTER_MODE 0x00000001U +#define I2C_CON_SPEED_MASK 0x00000006U +#define I2C_CON_SPEED(x) ((x) << 1) +#define I2C_CON_10BITADDR_SLAVE 0x00000008U +#define I2C_CON_RESTART_EN 0x00000020U +#define I2C_CON_SLAVE_DISABLE 0x00000040U +#define I2C_CON_STOP_DET_IFADDRESSED 0x00000080U +#define I2C_CON_TX_EMPTY_CTRL 0x00000100U + +/* I2C Target Address Register*/ +#define I2C_TAR_ADDRESS_MASK 0x000003FFU +#define I2C_TAR_ADDRESS(x) ((x) << 0) +#define I2C_TAR_GC_OR_START 0x00000400U +#define I2C_TAR_SPECIAL 0x00000800U +#define I2C_TAR_10BITADDR_MASTER 0x00001000U + +/* I2C Slave Address Register*/ +#define I2C_SAR_ADDRESS_MASK 0x000003FFU +#define I2C_SAR_ADDRESS(x) ((x) << 0) + +/* I2C Rx/Tx Data Buffer and Command Register*/ +#define I2C_DATA_CMD_CMD 0x00000100U +#define I2C_DATA_CMD_DATA_MASK 0x000000FFU +#define I2C_DATA_CMD_DATA(x) ((x) << 0) + +/* Standard Speed I2C Clock SCL High Count Register*/ +#define I2C_SS_SCL_HCNT_COUNT_MASK 0x0000FFFFU +#define I2C_SS_SCL_HCNT_COUNT(x) ((x) << 0) + +/* Standard Speed I2C Clock SCL Low Count Register*/ +#define I2C_SS_SCL_LCNT_COUNT_MASK 0x0000FFFFU +#define I2C_SS_SCL_LCNT_COUNT(x) ((x) << 0) + +/* I2C Interrupt Status Register*/ +#define I2C_INTR_STAT_RX_UNDER 0x00000001U +#define I2C_INTR_STAT_RX_OVER 0x00000002U +#define I2C_INTR_STAT_RX_FULL 0x00000004U +#define I2C_INTR_STAT_TX_OVER 0x00000008U +#define I2C_INTR_STAT_TX_EMPTY 0x00000010U +#define I2C_INTR_STAT_RD_REQ 0x00000020U +#define I2C_INTR_STAT_TX_ABRT 0x00000040U +#define I2C_INTR_STAT_RX_DONE 0x00000080U +#define I2C_INTR_STAT_ACTIVITY 0x00000100U +#define I2C_INTR_STAT_STOP_DET 0x00000200U +#define I2C_INTR_STAT_START_DET 0x00000400U +#define I2C_INTR_STAT_GEN_CALL 0x00000800U + +/* I2C Interrupt Mask Register*/ +#define I2C_INTR_MASK_RX_UNDER 0x00000001U +#define I2C_INTR_MASK_RX_OVER 0x00000002U +#define I2C_INTR_MASK_RX_FULL 0x00000004U +#define I2C_INTR_MASK_TX_OVER 0x00000008U +#define I2C_INTR_MASK_TX_EMPTY 0x00000010U +#define I2C_INTR_MASK_RD_REQ 0x00000020U +#define I2C_INTR_MASK_TX_ABRT 0x00000040U +#define I2C_INTR_MASK_RX_DONE 0x00000080U +#define I2C_INTR_MASK_ACTIVITY 0x00000100U +#define I2C_INTR_MASK_STOP_DET 0x00000200U +#define I2C_INTR_MASK_START_DET 0x00000400U +#define I2C_INTR_MASK_GEN_CALL 0x00000800U + +/* I2C Raw Interrupt Status Register*/ +#define I2C_RAW_INTR_MASK_RX_UNDER 0x00000001U +#define I2C_RAW_INTR_MASK_RX_OVER 0x00000002U +#define I2C_RAW_INTR_MASK_RX_FULL 0x00000004U +#define I2C_RAW_INTR_MASK_TX_OVER 0x00000008U +#define I2C_RAW_INTR_MASK_TX_EMPTY 0x00000010U +#define I2C_RAW_INTR_MASK_RD_REQ 0x00000020U +#define I2C_RAW_INTR_MASK_TX_ABRT 0x00000040U +#define I2C_RAW_INTR_MASK_RX_DONE 0x00000080U +#define I2C_RAW_INTR_MASK_ACTIVITY 0x00000100U +#define I2C_RAW_INTR_MASK_STOP_DET 0x00000200U +#define I2C_RAW_INTR_MASK_START_DET 0x00000400U +#define I2C_RAW_INTR_MASK_GEN_CALL 0x00000800U + +/* I2C Receive FIFO Threshold Register*/ +#define I2C_RX_TL_VALUE_MASK 0x00000007U +#define I2C_RX_TL_VALUE(x) ((x) << 0) + +/* I2C Transmit FIFO Threshold Register*/ +#define I2C_TX_TL_VALUE_MASK 0x00000007U +#define I2C_TX_TL_VALUE(x) ((x) << 0) + +/* Clear Combined and Individual Interrupt Register*/ +#define I2C_CLR_INTR_CLR 0x00000001U + +/* Clear RX_UNDER Interrupt Register*/ +#define I2C_CLR_RX_UNDER_CLR 0x00000001U + +/* Clear RX_OVER Interrupt Register*/ +#define I2C_CLR_RX_OVER_CLR 0x00000001U + +/* Clear TX_OVER Interrupt Register*/ +#define I2C_CLR_TX_OVER_CLR 0x00000001U + +/* Clear RD_REQ Interrupt Register*/ +#define I2C_CLR_RD_REQ_CLR 0x00000001U + +/* Clear TX_ABRT Interrupt Register*/ +#define I2C_CLR_TX_ABRT_CLR 0x00000001U + +/* Clear RX_DONE Interrupt Register*/ +#define I2C_CLR_RX_DONE_CLR 0x00000001U + +/* Clear ACTIVITY Interrupt Register*/ +#define I2C_CLR_ACTIVITY_CLR 0x00000001U + +/* Clear STOP_DET Interrupt Register*/ +#define I2C_CLR_STOP_DET_CLR 0x00000001U + +/* Clear START_DET Interrupt Register*/ +#define I2C_CLR_START_DET_CLR 0x00000001U + +/* Clear GEN_CALL Interrupt Register*/ +#define I2C_CLR_GEN_CALL_CLR 0x00000001U + +/* I2C Enable Register*/ +#define I2C_ENABLE_ENABLE 0x00000001U +#define I2C_ENABLE_ABORT 0x00000002U +#define I2C_ENABLE_TX_CMD_BLOCK 0x00000004U + +/* I2C Status Register*/ +#define I2C_STATUS_ACTIVITY 0x00000001U +#define I2C_STATUS_TFNF 0x00000002U +#define I2C_STATUS_TFE 0x00000004U +#define I2C_STATUS_RFNE 0x00000008U +#define I2C_STATUS_RFF 0x00000010U +#define I2C_STATUS_MST_ACTIVITY 0x00000020U +#define I2C_STATUS_SLV_ACTIVITY 0x00000040U + +/* I2C Transmit FIFO Level Register*/ +#define I2C_TXFLR_VALUE_MASK 0x00000007U +#define I2C_TXFLR_VALUE(x) ((x) << 0) + +/* I2C Receive FIFO Level Register*/ +#define I2C_RXFLR_VALUE_MASK 0x00000007U +#define I2C_RXFLR_VALUE(x) ((x) << 0) + +/* I2C SDA Hold Time Length Register*/ +#define I2C_SDA_HOLD_TX_MASK 0x0000FFFFU +#define I2C_SDA_HOLD_TX(x) ((x) << 0) +#define I2C_SDA_HOLD_RX_MASK 0x00FF0000U +#define I2C_SDA_HOLD_RX(x) ((x) << 16) + +/* I2C Transmit Abort Source Register*/ +#define I2C_TX_ABRT_SOURCE_7B_ADDR_NOACK 0x00000001U +#define I2C_TX_ABRT_SOURCE_10B_ADDR1_NOACK 0x00000002U +#define I2C_TX_ABRT_SOURCE_10B_ADDR2_NOACK 0x00000004U +#define I2C_TX_ABRT_SOURCE_TXDATA_NOACK 0x00000008U +#define I2C_TX_ABRT_SOURCE_GCALL_NOACK 0x00000010U +#define I2C_TX_ABRT_SOURCE_GCALL_READ 0x00000020U +#define I2C_TX_ABRT_SOURCE_HS_ACKDET 0x00000040U +#define I2C_TX_ABRT_SOURCE_SBYTE_ACKDET 0x00000080U +#define I2C_TX_ABRT_SOURCE_HS_NORSTRT 0x00000100U +#define I2C_TX_ABRT_SOURCE_SBYTE_NORSTRT 0x00000200U +#define I2C_TX_ABRT_SOURCE_10B_RD_NORSTRT 0x00000400U +#define I2C_TX_ABRT_SOURCE_MASTER_DIS 0x00000800U +#define I2C_TX_ABRT_SOURCE_MST_ARBLOST 0x00001000U +#define I2C_TX_ABRT_SOURCE_SLVFLUSH_TXFIFO 0x00002000U +#define I2C_TX_ABRT_SOURCE_SLV_ARBLOST 0x00004000U +#define I2C_TX_ABRT_SOURCE_SLVRD_INTX 0x00008000U +#define I2C_TX_ABRT_SOURCE_USER_ABRT 0x00010000U + +/* DMA Control Register*/ +#define I2C_DMA_CR_RDMAE 0x00000001U +#define I2C_DMA_CR_TDMAE 0x00000002U + +/* DMA Transmit Data Level Register*/ +#define I2C_DMA_TDLR_VALUE_MASK 0x00000007U +#define I2C_DMA_TDLR_VALUE(x) ((x) << 0) + +/* DMA Receive Data Level Register*/ +#define I2C_DMA_RDLR_VALUE_MASK 0x00000007U +#define I2C_DMA_RDLR_VALUE(x) ((x) << 0) + +/* I2C SDA Setup Register*/ +#define I2C_SDA_SETUP_VALUE_MASK 0x000000FFU +#define I2C_SDA_SETUP_VALUE(x) ((x) << 0) + +/* I2C ACK General Call Register*/ +#define I2C_ACK_GENERAL_CALL_ENABLE 0x00000001U + +/* I2C Enable Status Register*/ +#define I2C_ENABLE_STATUS_IC_ENABLE 0x00000001U +#define I2C_ENABLE_STATUS_SLV_DIS_BUSY 0x00000002U +#define I2C_ENABLE_STATUS_SLV_RX_DATA_LOST 0x00000004U + +/* I2C SS, FS or FM+ spike suppression limit*/ +#define I2C_FS_SPKLEN_VALUE_MASK 0x000000FFU +#define I2C_FS_SPKLEN_VALUE(x) ((x) << 0) + +/* Component Parameter Register 1*/ +#define I2C_COMP_PARAM1_APB_DATA_WIDTH 0x00000003U +#define I2C_COMP_PARAM1_MAX_SPEED_MODE 0x0000000CU +#define I2C_COMP_PARAM1_HC_COUNT_VALUES 0x00000010U +#define I2C_COMP_PARAM1_INTR_IO 0x00000020U +#define I2C_COMP_PARAM1_HAS_DMA 0x00000040U +#define I2C_COMP_PARAM1_ENCODED_PARAMS 0x00000080U +#define I2C_COMP_PARAM1_RX_BUFFER_DEPTH 0x0000FF00U +#define I2C_COMP_PARAM1_TX_BUFFER_DEPTH 0x00FF0000U + +/* I2C Component Version Register*/ +#define I2C_COMP_VERSION_VALUE 0xFFFFFFFFU + +/* I2C Component Type Register*/ +#define I2C_COMP_TYPE_VALUE 0xFFFFFFFFU +/* clang-format on */ + +extern volatile i2c_t *const i2c[3]; + +typedef enum _i2c_device_number +{ + I2C_DEVICE_0, + I2C_DEVICE_1, + I2C_DEVICE_2, + I2C_DEVICE_MAX, +} i2c_device_number_t; + +typedef enum _i2c_bus_speed_mode +{ + I2C_BS_STANDARD, + I2C_BS_FAST, + I2C_BS_HIGHSPEED +} i2c_bus_speed_mode_t; + +typedef enum _i2c_event +{ + I2C_EV_START, + I2C_EV_RESTART, + I2C_EV_STOP +} i2c_event_id_t; + +typedef struct _i2c_slave_handler +{ + void(*on_receive)(uint32_t data); + uint32_t(*on_transmit)(); + void(*on_event)(i2c_event_id_t event); +} i2c_slave_handler_t; + +typedef enum _i2c_transfer_mode +{ + I2C_SEND, + I2C_RECEIVE, +} i2c_transfer_mode_t; + +typedef struct _i2c_data_t +{ + dmac_channel_number_t tx_channel; + dmac_channel_number_t rx_channel; + uint32_t *tx_buf; + size_t tx_len; + uint32_t *rx_buf; + size_t rx_len; + i2c_transfer_mode_t TransferMode; +} i2c_data_t; + +/** + * @brief Set i2c params + * + * @param[in] i2c_num i2c number + * @param[in] slave_address i2c slave device address + * @param[in] address_width address width 7bit or 10bit + * @param[in] i2c_clk i2c clk rate + */ +void i2c_init(i2c_device_number_t i2c_num, uint32_t slave_address, uint32_t address_width, + uint32_t i2c_clk); + +/** + * @brief I2c send data + * + * @param[in] i2c_num i2c number + * @param[in] SendBuf send data + * @param[in] send_buf_len send data length + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2c_send_data(i2c_device_number_t i2c_num, const uint8_t *SendBuf, size_t send_buf_len); + +/** + * @brief Init i2c as slave mode. + * + * @param[in] i2c_num i2c number + * @param[in] slave_address i2c slave device address + * @param[in] address_width address width 7bit or 10bit + * @param[in] handler Handle of i2c slave interrupt function. + */ +void i2c_init_as_slave(i2c_device_number_t i2c_num, uint32_t slave_address, uint32_t address_width, + const i2c_slave_handler_t *handler); + +/** + * @brief I2c send data by dma + * + * @param[in] dma_channel_num dma channel + * @param[in] i2c_num i2c number + * @param[in] SendBuf send data + * @param[in] send_buf_len send data length + * + * @return result + * - 0 Success + * - Other Fail + */ +void i2c_send_data_dma(dmac_channel_number_t dma_channel_num, i2c_device_number_t i2c_num, const uint8_t *SendBuf, + size_t send_buf_len); + +/** + * @brief I2c receive data + * + * @param[in] i2c_num i2c number + * @param[in] SendBuf send data address + * @param[in] send_buf_len length of send buf + * @param[in] receive_buf receive buf address + * @param[in] receive_buf_len length of receive buf + * + * @return result + * - 0 Success + * - Other Fail +*/ +int i2c_recv_data(i2c_device_number_t i2c_num, const uint8_t *SendBuf, size_t send_buf_len, uint8_t *receive_buf, + size_t receive_buf_len); + +/** + * @brief I2c receive data by dma + * + * @param[in] dma_send_channel_num send dma channel + * @param[in] dma_receive_channel_num receive dma channel + * @param[in] i2c_num i2c number + * @param[in] SendBuf send data address + * @param[in] send_buf_len length of send buf + * @param[in] receive_buf receive buf address + * @param[in] receive_buf_len length of receive buf + * + * @return result + * - 0 Success + * - Other Fail +*/ +void i2c_recv_data_dma(dmac_channel_number_t dma_send_channel_num, dmac_channel_number_t dma_receive_channel_num, + i2c_device_number_t i2c_num, const uint8_t *SendBuf, size_t send_buf_len, + uint8_t *receive_buf, size_t receive_buf_len); +/** + * @brief I2c handle transfer data operations + * + * @param[in] i2c_num i2c number + * @param[in] data i2c data information + * @param[in] cb i2c dma callback + * +*/ +void i2c_handle_data_dma(i2c_device_number_t i2c_num, i2c_data_t data, plic_interrupt_t *cb); + +#ifdef __cplusplus +} +#endif + +#endif /* __HARDWARE_I2C_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/hardware_rtc.h b/board/k210-emulator/third_party_driver/include/hardware_rtc.h new file mode 100644 index 00000000..1a08e26a --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/hardware_rtc.h @@ -0,0 +1,443 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_rtc.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __HARDWARE_RTC_H__ +#define __HARDWARE_RTC_H__ + +#include +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief RTC timer mode + * + * Timer mode selector + * | Mode | Description | + * |------|------------------------| + * | 0 | Timer pause | + * | 1 | Timer time running | + * | 2 | Timer time setting | + */ +typedef enum _rtc_timer_mode_e +{ + /* 0: Timer pause */ + RTC_TIMER_PAUSE, + /* 1: Timer time running */ + RTC_TIMER_RUNNING, + /* 2: Timer time setting */ + RTC_TIMER_SETTING, + /* Max count of this enum*/ + RTC_TIMER_MAX +} rtc_timer_mode_t; + +/* + * @brief RTC tick interrupt mode + * + * Tick interrupt mode selector + * | Mode | Description | + * |------|------------------------| + * | 0 | Interrupt every second | + * | 1 | Interrupt every minute | + * | 2 | Interrupt every hour | + * | 3 | Interrupt every day | + */ +typedef enum _rtc_tick_interrupt_mode_e +{ + /* 0: Interrupt every second */ + RTC_INT_SECOND, + /* 1: Interrupt every minute */ + RTC_INT_MINUTE, + /* 2: Interrupt every hour */ + RTC_INT_HOUR, + /* 3: Interrupt every day */ + RTC_INT_DAY, + /* Max count of this enum*/ + RTC_INT_MAX +} rtc_tick_interrupt_mode_t; + +/** + * @brief RTC mask structure + * + * RTC mask structure for common use + */ +typedef struct _rtc_mask +{ + /* Reserved */ + uint32_t resv : 1; + /* Second mask */ + uint32_t second : 1; + /* Minute mask */ + uint32_t minute : 1; + /* Hour mask */ + uint32_t hour : 1; + /* Week mask */ + uint32_t week : 1; + /* Day mask */ + uint32_t day : 1; + /* Month mask */ + uint32_t month : 1; + /* Year mask */ + uint32_t year : 1; +} __attribute__((packed, aligned(1))) rtc_mask_t; + +/** + * @brief RTC register + * + * @note RTC register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | date | Timer date information | + * | 0x04 | time | Timer time information | + * | 0x08 | alarm_date | Alarm date information | + * | 0x0c | alarm_time | Alarm time information | + * | 0x10 | initial_count | Timer counter initial value | + * | 0x14 | current_count | Timer counter current value | + * | 0x18 | interrupt_ctrl | RTC interrupt settings | + * | 0x1c | register_ctrl | RTC register settings | + * | 0x20 | reserved0 | Reserved | + * | 0x24 | reserved1 | Reserved | + * | 0x28 | extended | Timer extended information | + * + */ + + +/** + * @brief Timer date information + * + * No. 0 Register (0x00) + */ +typedef struct _rtc_date +{ + /* Week. Range [0,6]. 0 is Sunday. */ + uint32_t week : 3; + /* Reserved */ + uint32_t resv0 : 5; + /* Day. Range [1,31] or [1,30] or [1,29] or [1,28] */ + uint32_t day : 5; + /* Reserved */ + uint32_t resv1 : 3; + /* Month. Range [1,12] */ + uint32_t month : 4; + /* Year. Range [0,99] */ + uint32_t year : 12; +} __attribute__((packed, aligned(4))) rtc_date_t; + +/** + * @brief Timer time information + * + * No. 1 Register (0x04) + */ +typedef struct _rtc_time +{ + /* Reserved */ + uint32_t resv0 : 10; + /* Second. Range [0,59] */ + uint32_t second : 6; + /* Minute. Range [0,59] */ + uint32_t minute : 6; + /* Reserved */ + uint32_t resv1 : 2; + /* Hour. Range [0,23] */ + uint32_t hour : 5; + /* Reserved */ + uint32_t resv2 : 3; +} __attribute__((packed, aligned(4))) rtc_time_t; + +/** + * @brief Alarm date information + * + * No. 2 Register (0x08) + */ +typedef struct _rtc_alarm_date +{ + /* Alarm Week. Range [0,6]. 0 is Sunday. */ + uint32_t week : 3; + /* Reserved */ + uint32_t resv0 : 5; + /* Alarm Day. Range [1,31] or [1,30] or [1,29] or [1,28] */ + uint32_t day : 5; + /* Reserved */ + uint32_t resv1 : 3; + /* Alarm Month. Range [1,12] */ + uint32_t month : 4; + /* Alarm Year. Range [0,99] */ + uint32_t year : 12; +} __attribute__((packed, aligned(4))) rtc_alarm_date_t; + +/** + * @brief Alarm time information + * + * No. 3 Register (0x0c) + */ +typedef struct _rtc_alarm_time +{ + /* Reserved */ + uint32_t resv0 : 10; + /* Alarm Second. Range [0,59] */ + uint32_t second : 6; + /* Alarm Minute. Range [0,59] */ + uint32_t minute : 6; + /* Reserved */ + uint32_t resv1 : 2; + /* Alarm Hour. Range [0,23] */ + uint32_t hour : 5; + /* Reserved */ + uint32_t resv2 : 3; +} __attribute__((packed, aligned(4))) rtc_alarm_time_t; + +/** + * @brief Timer counter initial value + * + * No. 4 Register (0x10) + */ +typedef struct _rtc_initial_count +{ + /* RTC counter initial value */ + uint32_t count : 32; +} __attribute__((packed, aligned(4))) rtc_initial_count_t; + +/** + * @brief Timer counter current value + * + * No. 5 Register (0x14) + */ +typedef struct _rtc_current_count +{ + /* RTC counter current value */ + uint32_t count : 32; +} __attribute__((packed, aligned(4))) rtc_current_count_t; + +/** + * @brief RTC interrupt settings + * + * No. 6 Register (0x18) + */ +typedef struct _rtc_interrupt_ctrl +{ + /* Reserved */ + uint32_t tick_enable : 1; + /* Alarm interrupt enable */ + uint32_t alarm_enable : 1; + /* Tick interrupt enable */ + uint32_t tick_int_mode : 2; + /* Reserved */ + uint32_t resv : 20; + /* Alarm compare mask for interrupt */ + uint32_t alarm_compare_mask : 8; +} __attribute__((packed, aligned(4))) rtc_interrupt_ctrl_t; + +/** + * @brief RTC register settings + * + * No. 7 Register (0x1c) + */ +typedef struct _rtc_register_ctrl +{ + /* RTC timer read enable */ + uint32_t read_enable : 1; + /* RTC timer write enable */ + uint32_t write_enable : 1; + /* Reserved */ + uint32_t resv0 : 11; + /* RTC timer mask */ + uint32_t TimerMask : 8; + /* RTC alarm mask */ + uint32_t alarm_mask : 8; + /* RTC counter initial count value mask */ + uint32_t initial_count_mask : 1; + /* RTC interrupt register mask */ + uint32_t interrupt_register_mask : 1; + /* Reserved */ + uint32_t resv1 : 1; +} __attribute__((packed, aligned(4))) rtc_register_ctrl_t; + +/** + * @brief Reserved + * + * No. 8 Register (0x20) + */ +typedef struct _rtc_reserved0 +{ + /* Reserved */ + uint32_t resv : 32; +} __attribute__((packed, aligned(4))) rtc_reserved0_t; + +/** + * @brief Reserved + * + * No. 9 Register (0x24) + */ +typedef struct _rtc_reserved1 +{ + /* Reserved */ + uint32_t resv : 32; +} __attribute__((packed, aligned(4))) rtc_reserved1_t; + +/** + * @brief Timer extended information + * + * No. 10 Register (0x28) + */ +typedef struct _rtc_extended +{ + /* Century. Range [0,31] */ + uint32_t century : 5; + /* Is leap year. 1 is leap year, 0 is not leap year */ + uint32_t leap_year : 1; + /* Reserved */ + uint32_t resv : 26; +} __attribute__((packed, aligned(4))) rtc_extended_t; + + +/** + * @brief Real-time clock struct + * + * A real-time clock (RTC) is a computer clock that keeps track of + * the current time. + */ +typedef struct _rtc +{ + /* No. 0 (0x00): Timer date information */ + rtc_date_t date; + /* No. 1 (0x04): Timer time information */ + rtc_time_t time; + /* No. 2 (0x08): Alarm date information */ + rtc_alarm_date_t alarm_date; + /* No. 3 (0x0c): Alarm time information */ + rtc_alarm_time_t alarm_time; + /* No. 4 (0x10): Timer counter initial value */ + rtc_initial_count_t initial_count; + /* No. 5 (0x14): Timer counter current value */ + rtc_current_count_t current_count; + /* No. 6 (0x18): RTC interrupt settings */ + rtc_interrupt_ctrl_t interrupt_ctrl; + /* No. 7 (0x1c): RTC register settings */ + rtc_register_ctrl_t register_ctrl; + /* No. 8 (0x20): Reserved */ + rtc_reserved0_t reserved0; + /* No. 9 (0x24): Reserved */ + rtc_reserved1_t reserved1; + /* No. 10 (0x28): Timer extended information */ + rtc_extended_t extended; +} __attribute__((packed, aligned(4))) rtc_t; + + +/** + * @brief Real-time clock object + */ +extern volatile rtc_t *const rtc; +extern volatile uint32_t *const rtc_base; + +/** + * @brief Set date time to RTC + * + * @param[in] year The year + * @param[in] month The month + * @param[in] day The day + * @param[in] hour The hour + * @param[in] minute The minute + * @param[in] second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set(int year, int month, int day, int hour, int minute, int second); + +/** + * @brief Get date time from RTC + * + * @param year The year + * @param month The month + * @param day The day + * @param hour The hour + * @param minute The minute + * @param second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second); + +/** + * @brief Initialize RTC + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_init(void); + +/** + * @brief Set RTC in protect mode or not + * + * @param enable Enable flag + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_protect_set(int enable); + +/** + * @brief Set RTC timer mode + * + * @param timer_mode Timer mode + * + */ +void rtc_timer_set_mode(rtc_timer_mode_t timer_mode); + +/** + * @brief Set RTC timer clock frequency + * + * @param frequency Frequency + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set_clock_frequency(unsigned int frequency); + +/** + * @brief Set RTC timer clock count value + * + * @param count Count + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set_clock_count_value(unsigned int count); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_RTC_H */ diff --git a/board/k210-emulator/third_party_driver/include/hardware_spi.h b/board/k210-emulator/third_party_driver/include/hardware_spi.h new file mode 100644 index 00000000..e198644a --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/hardware_spi.h @@ -0,0 +1,494 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_spi.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __HARDWARE_SPI_H__ +#define __HARDWARE_SPI_H__ + +#include +#include +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _spi +{ + /* SPI Control Register 0 (0x00)*/ + volatile uint32_t ctrlr0; + /* SPI Control Register 1 (0x04)*/ + volatile uint32_t ctrlr1; + /* SPI Enable Register (0x08)*/ + volatile uint32_t ssienr; + /* SPI Microwire Control Register (0x0c)*/ + volatile uint32_t mwcr; + /* SPI Slave Enable Register (0x10)*/ + volatile uint32_t ser; + /* SPI Baud Rate Select (0x14)*/ + volatile uint32_t baudr; + /* SPI Transmit FIFO Threshold Level (0x18)*/ + volatile uint32_t txftlr; + /* SPI Receive FIFO Threshold Level (0x1c)*/ + volatile uint32_t rxftlr; + /* SPI Transmit FIFO Level Register (0x20)*/ + volatile uint32_t txflr; + /* SPI Receive FIFO Level Register (0x24)*/ + volatile uint32_t rxflr; + /* SPI Status Register (0x28)*/ + volatile uint32_t sr; + /* SPI Interrupt Mask Register (0x2c)*/ + volatile uint32_t imr; + /* SPI Interrupt Status Register (0x30)*/ + volatile uint32_t isr; + /* SPI Raw Interrupt Status Register (0x34)*/ + volatile uint32_t risr; + /* SPI Transmit FIFO Overflow Interrupt Clear Register (0x38)*/ + volatile uint32_t txoicr; + /* SPI Receive FIFO Overflow Interrupt Clear Register (0x3c)*/ + volatile uint32_t rxoicr; + /* SPI Receive FIFO Underflow Interrupt Clear Register (0x40)*/ + volatile uint32_t rxuicr; + /* SPI Multi-Master Interrupt Clear Register (0x44)*/ + volatile uint32_t msticr; + /* SPI Interrupt Clear Register (0x48)*/ + volatile uint32_t icr; + /* SPI DMA Control Register (0x4c)*/ + volatile uint32_t dmacr; + /* SPI DMA Transmit Data Level (0x50)*/ + volatile uint32_t dmatdlr; + /* SPI DMA Receive Data Level (0x54)*/ + volatile uint32_t dmardlr; + /* SPI Identification Register (0x58)*/ + volatile uint32_t idr; + /* SPI DWC_ssi component version (0x5c)*/ + volatile uint32_t ssic_version_id; + /* SPI Data Register 0-36 (0x60 -- 0xec)*/ + volatile uint32_t dr[36]; + /* SPI RX Sample Delay Register (0xf0)*/ + volatile uint32_t rx_sample_delay; + /* SPI SPI Control Register (0xf4)*/ + volatile uint32_t spi_ctrlr0; + /* reserved (0xf8)*/ + volatile uint32_t resv; + /* SPI XIP Mode bits (0xfc)*/ + volatile uint32_t xip_mode_bits; + /* SPI XIP INCR transfer opcode (0x100)*/ + volatile uint32_t xip_incr_inst; + /* SPI XIP WRAP transfer opcode (0x104)*/ + volatile uint32_t xip_wrap_inst; + /* SPI XIP Control Register (0x108)*/ + volatile uint32_t xip_ctrl; + /* SPI XIP Slave Enable Register (0x10c)*/ + volatile uint32_t xip_ser; + /* SPI XIP Receive FIFO Overflow Interrupt Clear Register (0x110)*/ + volatile uint32_t xrxoicr; + /* SPI XIP time out register for continuous transfers (0x114)*/ + volatile uint32_t xip_cnt_time_out; + volatile uint32_t endian; +} __attribute__((packed, aligned(4))) spi_t; +/* clang-format on */ + +typedef enum _spi_device_num +{ + SPI_DEVICE_0, + SPI_DEVICE_1, + SPI_DEVICE_2, + SPI_DEVICE_3, + SPI_DEVICE_MAX, +} spi_device_num_t; + +typedef enum _spi_work_mode +{ + SPI_WORK_MODE_0, + SPI_WORK_MODE_1, + SPI_WORK_MODE_2, + SPI_WORK_MODE_3, +} spi_work_mode_t; + +typedef enum _spi_frame_format +{ + SPI_FF_STANDARD, + SPI_FF_DUAL, + SPI_FF_QUAD, + SPI_FF_OCTAL +} spi_frame_format_t; + +typedef enum _spi_instruction_address_trans_mode +{ + SPI_AITM_STANDARD, + SPI_AITM_ADDR_STANDARD, + SPI_AITM_AS_FRAME_FORMAT +} spi_instruction_address_trans_mode_t; + +typedef enum _spi_transfer_mode +{ + SPI_TMOD_TRANS_RECV, + SPI_TMOD_TRANS, + SPI_TMOD_RECV, + SPI_TMOD_EEROM +} spi_transfer_mode_t; + + +typedef enum _spi_transfer_width +{ + SPI_TRANS_CHAR = 0x1, + SPI_TRANS_SHORT = 0x2, + SPI_TRANS_INT = 0x4, +} spi_transfer_width_t; + +typedef enum _spi_chip_select +{ + SPI_CHIP_SELECT_0, + SPI_CHIP_SELECT_1, + SPI_CHIP_SELECT_2, + SPI_CHIP_SELECT_3, + SPI_CHIP_SELECT_MAX, +} spi_chip_select_t; + +typedef enum +{ + WRITE_CONFIG, + READ_CONFIG, + WRITE_DATA_BYTE, + READ_DATA_BYTE, + WRITE_DATA_BLOCK, + READ_DATA_BLOCK, +} spi_slave_command_e; + +typedef struct +{ + uint8_t cmd; + uint8_t err; + uint32_t addr; + uint32_t len; +} spi_slave_command_t; + +typedef enum +{ + IDLE, + COMMAND, + TRANSFER, +} spi_slave_status_e; + +typedef int (*spi_slave_receive_callback_t)(void *ctx); + +typedef struct _spi_slave_instance +{ + uint8_t int_pin; + uint8_t ready_pin; + dmac_channel_number_t dmac_channel; + uint8_t dfs; + uint8_t slv_oe; + uint8_t work_mode; + size_t data_bit_length; + volatile spi_slave_status_e status; + volatile spi_slave_command_t command; + volatile uint8_t *config_ptr; + uint32_t config_len; + spi_slave_receive_callback_t callback; +} spi_slave_instance_t; + +typedef struct _spi_data_t +{ + dmac_channel_number_t tx_channel; + dmac_channel_number_t rx_channel; + uint32_t *tx_buf; + size_t tx_len; + uint32_t *rx_buf; + size_t rx_len; + spi_transfer_mode_t TransferMode; + bool fill_mode; +} spi_data_t; + +extern volatile spi_t *const spi[4]; + +/** + * @brief Set spi configuration + * + * @param[in] spi_num Spi bus number + * @param[in] mode Spi mode + * @param[in] frame_format Spi frame format + * @param[in] data_bit_length Spi data bit length + * @param[in] endian 0:little-endian 1:big-endian + * + * @return Void + */ +void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format, + size_t data_bit_length, uint32_t endian); + +/** + * @brief Set multiline configuration + * + * @param[in] spi_num Spi bus number + * @param[in] instruction_length Instruction length + * @param[in] address_length Address length + * @param[in] wait_cycles Wait cycles + * @param[in] instruction_address_trans_mode Spi transfer mode + * + */ +void spi_init_non_standard(spi_device_num_t spi_num, uint32_t instruction_length, uint32_t address_length, + uint32_t wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode); + +/** + * @brief Spi send data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi receive data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special receive data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special send data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi send data by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint8_t *CmdBuff, size_t CmdLen, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi receive data by dma + * + * @param[in] w_channel_num Dmac write channel number + * @param[in] r_channel_num Dmac read channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special send data by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint32_t *CmdBuff, size_t CmdLen, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi special receive data by dma + * + * @param[in] dma_send_channel_num Dmac write channel number + * @param[in] dma_receive_channel_num Dmac read channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi fill dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] tx_buff Spi command buffer point + * @param[in] tx_len Spi command length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint32_t *tx_buff, size_t tx_len); + +/** + * @brief Spi normal send by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * @param[in] stw Spi transfer width + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const void *tx_buff, size_t tx_len, spi_transfer_width_t spi_transfer_width); + +/** + * @brief Spi normal send by dma + * + * @param[in] spi_num Spi bus number + * @param[in] spi_clk Spi clock rate + * + * @return The real spi clock rate + */ +uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk); + +/** + * @brief Spi full duplex send receive data by dma + * + * @param[in] dma_send_channel_num Dmac write channel number + * @param[in] dma_receive_channel_num Dmac read channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] tx_buf Spi send buffer + * @param[in] tx_len Spi send buffer length + * @param[in] rx_buf Spi receive buffer + * @param[in] rx_len Spi receive buffer length + * + */ +void spi_dup_send_receive_data_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint8_t *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len); + +/** + * @brief Set spi slave configuration + * + * @param[in] int_pin SPI master starts sending data interrupt. + * @param[in] ready_pin SPI slave ready. + * @param[in] dmac_channel Dmac channel number for block. + * @param[in] data_bit_length Spi data bit length + * @param[in] data SPI slave device data buffer. + * @param[in] len The length of SPI slave device data buffer. + * @param[in] callback Callback of spi slave. + * + * @return Void + */ +void spi_slave_config(uint8_t int_pin, uint8_t ready_pin, dmac_channel_number_t dmac_channel, size_t data_bit_length, uint8_t *data, uint32_t len, spi_slave_receive_callback_t callback); + +/** + * @brief Spi handle transfer data operations + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] data Spi transfer data information + * @param[in] cb Spi DMA callback + * + */ +void spi_handle_data_dma(spi_device_num_t spi_num, spi_chip_select_t chip_select, spi_data_t data, plic_interrupt_t *cb); + +#ifdef __cplusplus +} +#endif + +#endif /* __HARDWARE_SPI_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/hardware_uart.h b/board/k210-emulator/third_party_driver/include/hardware_uart.h new file mode 100644 index 00000000..f284d374 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/hardware_uart.h @@ -0,0 +1,364 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 + * @brief Universal Asynchronous Receiver/Transmitter (UART) + * + * The UART peripheral supports the following features: + * + * - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start + * bit, 1 or 2 stop bits + * + * - 8-entry transmit and receive FIFO buffers with programmable + * watermark interrupts + * + * - 16× Rx oversampling with 2/3 majority voting per bit + * + * The UART peripheral does not support hardware flow control or + * other modem control signals, or synchronous serial data + * tranfesrs. + * + * + */ + +/** +* @file hardware_uart.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __HARDWARE_UART_H__ +#define __HARDWARE_UART_H__ + +#include +#include "platform.h" +#include "plic.h" +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _uart_dev +{ + UART_DEV1 = 0, + UART_DEV2, + UART_DEV3, +} uart_dev_t; + +typedef struct _uart +{ + union + { + volatile uint32_t RBR; + volatile uint32_t DLL; + volatile uint32_t THR; + }; + + union + { + volatile uint32_t DLH; + volatile uint32_t IER; + }; + + union + { + volatile uint32_t FCR; + volatile uint32_t IIR; + }; + + volatile uint32_t LCR; + volatile uint32_t MCR; + volatile uint32_t LSR; + volatile uint32_t MSR; + + volatile uint32_t SCR; + volatile uint32_t LPDLL; + volatile uint32_t LPDLH; + + volatile uint32_t reserved1[2]; + + union + { + volatile uint32_t SRBR[16]; + volatile uint32_t STHR[16]; + }; + + volatile uint32_t FAR; + volatile uint32_t TFR; + volatile uint32_t RFW; + volatile uint32_t USR; + volatile uint32_t TFL; + volatile uint32_t RFL; + volatile uint32_t SRR; + volatile uint32_t SRTS; + volatile uint32_t SBCR; + volatile uint32_t SDMAM; + volatile uint32_t SFE; + volatile uint32_t SRT; + volatile uint32_t STET; + volatile uint32_t HTX; + volatile uint32_t DMASA; + volatile uint32_t TCR; + volatile uint32_t DE_EN; + volatile uint32_t RE_EN; + volatile uint32_t DET; + volatile uint32_t TAT; + volatile uint32_t DLF; + volatile uint32_t RAR; + volatile uint32_t TAR; + volatile uint32_t LCR_EXT; + volatile uint32_t reserved2[9]; + volatile uint32_t CPR; + volatile uint32_t UCV; + volatile uint32_t CTR; +} UartT; + +typedef enum _uart_device_number +{ + UART_DEVICE_1, + UART_DEVICE_2, + UART_DEVICE_3, + UART_DEVICE_MAX, +} UartDeviceNumberT; + +typedef enum _uart_bitwidth +{ + UART_BITWIDTH_5BIT = 5, + UART_BITWIDTH_6BIT, + UART_BITWIDTH_7BIT, + UART_BITWIDTH_8BIT, +} UartBitwidthPointer; + +typedef enum _uart_stopbit +{ + UART_STOP_1, + UART_STOP_1_5, + UART_STOP_2 +} UartStopbitT; + +typedef enum _uart_rede_sel +{ + DISABLE = 0, + ENABLE, +} uart_rede_sel_t; + +typedef enum _uart_parity +{ + UART_PARITY_NONE, + UART_PARITY_ODD, + UART_PARITY_EVEN +} UartParityT; + +typedef enum _uart_interrupt_mode +{ + UART_SEND = 1, + UART_RECEIVE = 2, +} UartInterruptModeT; + +typedef enum _uart_send_trigger +{ + UART_SEND_FIFO_0, + UART_SEND_FIFO_2, + UART_SEND_FIFO_4, + UART_SEND_FIFO_8, +} uart_send_trigger_t; + +typedef enum _uart_receive_trigger +{ + UART_RECEIVE_FIFO_1, + UART_RECEIVE_FIFO_4, + UART_RECEIVE_FIFO_8, + UART_RECEIVE_FIFO_14, +} uart_receive_trigger_t; + +typedef struct _uart_data_t +{ + dmac_channel_number_t tx_channel; + dmac_channel_number_t rx_channel; + uint32_t *tx_buf; + size_t tx_len; + uint32_t *rx_buf; + size_t rx_len; + UartInterruptModeT TransferMode; +} uart_data_t; + +/** + * @brief Send data from uart + * + * @param[in] channel Uart index + * @param[in] buffer The data be transfer + * @param[in] len The data length + * + * @return Transfer length + */ +int UartSendData(UartDeviceNumberT channel, const char *buffer, size_t BufLen); + +/** + * @brief Read data from uart + * + * @param[in] channel Uart index + * @param[in] buffer The Data received + * @param[in] len Receive length + * + * @return Receive length + */ +int UartReceiveData(UartDeviceNumberT channel, char *buffer, size_t BufLen); + +/** + * @brief Init uart + * + * @param[in] channel Uart index + * + */ +void UartInit(UartDeviceNumberT channel); + +/** + * @brief Set uart param + * + * @param[in] channel Uart index + * @param[in] BaudRate Baudrate + * @param[in] DataWidth Data width + * @param[in] stopbit Stop bit + * @param[in] parity Odd Even parity + * + */ +void uart_config(UartDeviceNumberT channel, uint32_t BaudRate, UartBitwidthPointer DataWidth, UartStopbitT stopbit, UartParityT parity); + +/** + * @brief Set uart param + * + * @param[in] channel Uart index + * @param[in] BaudRate Baudrate + * @param[in] DataWidth Data width + * @param[in] stopbit Stop bit + * @param[in] parity Odd Even parity + * + */ +void uart_configure(UartDeviceNumberT channel, uint32_t BaudRate, UartBitwidthPointer DataWidth, UartStopbitT stopbit, UartParityT parity); + +/** + * @brief Register uart interrupt + * + * @param[in] channel Uart index + * @param[in] interrupt_mode Interrupt Mode receive or send + * @param[in] uart_callback Call back + * @param[in] ctx Param of call back + * @param[in] priority Interrupt priority + * + */ +void uart_irq_register(UartDeviceNumberT channel, UartInterruptModeT interrupt_mode, plic_irq_callback_t uart_callback, void *ctx, uint32_t priority); + +/** + * @brief Deregister uart interrupt + * + * @param[in] channel Uart index + * @param[in] interrupt_mode Interrupt Mode receive or send + * + */ +void uart_irq_unregister(UartDeviceNumberT channel, UartInterruptModeT interrupt_mode); + +/** + * @brief Set send interrupt threshold + * + * @param[in] channel Uart index + * @param[in] trigger Threshold of send interrupt + * + */ +void UartSetSendTrigger(UartDeviceNumberT channel, uart_send_trigger_t trigger); + +/** + * @brief Set receive interrupt threshold + * + * @param[in] channel Uart index + * @param[in] trigger Threshold of receive interrupt + * + */ +void uart_set_receive_trigger(UartDeviceNumberT channel, uart_receive_trigger_t trigger); + +/** + * @brief Send data by dma + * + * @param[in] channel Uart index + * @param[in] dmac_channel Dmac channel + * @param[in] buffer Send data + * @param[in] BufLen Data length + * + */ +void UartSendDataDma(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, const uint8_t *buffer, size_t BufLen); + +/** + * @brief Receive data by dma + * + * @param[in] channel Uart index + * @param[in] dmac_channel Dmac channel + * @param[in] buffer Receive data + * @param[in] BufLen Data length + * + */ +void UartReceiveDataDma(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, uint8_t *buffer, size_t BufLen); + + +/** + * @brief Send data by dma + * + * @param[in] uart_channel Uart index + * @param[in] dmac_channel Dmac channel + * @param[in] buffer Send data + * @param[in] BufLen Data length + * @param[in] uart_callback Call back + * @param[in] ctx Param of call back + * @param[in] priority Interrupt priority + * + */ +void UartSendDataDmaIrq(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, + const uint8_t *buffer, size_t BufLen, plic_irq_callback_t uart_callback, + void *ctx, uint32_t priority); + +/** + * @brief Receive data by dma + * + * @param[in] uart_channel Uart index + * @param[in] dmac_channel Dmac channel + * @param[in] buffer Receive data + * @param[in] BufLen Data length + * @param[in] uart_callback Call back + * @param[in] ctx Param of call back + * @param[in] priority Interrupt priority + * + */ +void UartReceiveDataDmaIrq(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, + uint8_t *buffer, size_t BufLen, plic_irq_callback_t uart_callback, + void *ctx, uint32_t priority); + +/** + * @brief Uart handle transfer data operations + * + * @param[in] uart_channel Uart index + * @param[in] data Uart data information + * @param[in] buffer Uart DMA callback + * + */ +void uart_handle_data_dma(UartDeviceNumberT uart_channel ,uart_data_t data, plic_interrupt_t *cb); + +#ifdef __cplusplus +} +#endif + +#endif /* __UART_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/hardware_uarths.h b/board/k210-emulator/third_party_driver/include/hardware_uarths.h new file mode 100644 index 00000000..f319c921 --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/hardware_uarths.h @@ -0,0 +1,302 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 + * @brief Universal Asynchronous Receiver/Transmitter (UART) + * + * The UART peripheral supports the following features: + * + * - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start + * bit, 1 or 2 stop bits + * + * - 8-entry transmit and receive FIFO buffers with programmable + * watermark interrupts + * + * - 16× Rx oversampling with 2/3 majority voting per bit + * + * The UART peripheral does not support hardware flow control or + * other modem control signals, or synchronous serial data + * tranfesrs. + * + * @note UART RAM Layout + * + * | Address | Name | Description | + * |-----------|----------|---------------------------------| + * | 0x000 | txdata | Transmit data register | + * | 0x004 | rxdata | Receive data register | + * | 0x008 | txctrl | Transmit control register | + * | 0x00C | rxctrl | Receive control register | + * | 0x010 | ie | UART interrupt enable | + * | 0x014 | ip | UART Interrupt pending | + * | 0x018 | div | Baud rate divisor | + * + */ + +/** +* @file hardware_uarths.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __HARDWARE_UARTHS_H__ +#define __HARDWARE_UARTHS_H__ + +#include +#include +#include "platform.h" +#include "plic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define UARTHS_REG_TXFIFO (0x00) +#define UARTHS_REG_RXFIFO (0x04) +#define UARTHS_REG_TXCTRL (0x08) +#define UARTHS_REG_RXCTRL (0x0c) +#define UARTHS_REG_IE (0x10) +#define UARTHS_REG_IP (0x14) +#define UARTHS_REG_DIV (0x18) + +/* TXCTRL register */ +#define UARTHS_TXEN (0x01) +#define UARTHS_TXWM(x) (((x) & 0xffff) << 16) + +/* RXCTRL register */ +#define UARTHS_RXEN (0x01) +#define UARTHS_RXWM(x) (((x) & 0xffff) << 16) + +/* IP register */ +#define UARTHS_IP_TXWM (0x01) +#define UARTHS_IP_RXWM (0x02) +/* clang-format on */ + +typedef struct _uarths_txdata +{ + /* Bits [7:0] is data */ + uint32_t data : 8; + /* Bits [30:8] is 0 */ + uint32_t zero : 23; + /* Bit 31 is full status */ + uint32_t full : 1; +} __attribute__((packed, aligned(4))) uarths_txdata_t; + +typedef struct _uarths_rxdata +{ + /* Bits [7:0] is data */ + uint32_t data : 8; + /* Bits [30:8] is 0 */ + uint32_t zero : 23; + /* Bit 31 is empty status */ + uint32_t empty : 1; +} __attribute__((packed, aligned(4))) uarths_rxdata_t; + +typedef struct _uarths_txctrl +{ + /* Bit 0 is txen, controls whether the Tx channel is active. */ + uint32_t txen : 1; + /* Bit 1 is nstop, 0 for one stop bit and 1 for two stop bits */ + uint32_t nstop : 1; + /* Bits [15:2] is reserved */ + uint32_t resv0 : 14; + /* Bits [18:16] is threshold of interrupt triggers */ + uint32_t txcnt : 3; + /* Bits [31:19] is reserved */ + uint32_t resv1 : 13; +} __attribute__((packed, aligned(4))) uarths_txctrl_t; + +typedef struct _uarths_rxctrl +{ + /* Bit 0 is txen, controls whether the Tx channel is active. */ + uint32_t rxen : 1; + /* Bits [15:1] is reserved */ + uint32_t resv0 : 15; + /* Bits [18:16] is threshold of interrupt triggers */ + uint32_t rxcnt : 3; + /* Bits [31:19] is reserved */ + uint32_t resv1 : 13; +} __attribute__((packed, aligned(4))) uarths_rxctrl_t; + +typedef struct _uarths_ip +{ + /* Bit 0 is txwm, raised less than txcnt */ + uint32_t txwm : 1; + /* Bit 1 is txwm, raised greater than rxcnt */ + uint32_t rxwm : 1; + /* Bits [31:2] is 0 */ + uint32_t zero : 30; +} __attribute__((packed, aligned(4))) uarths_ip_t; + +typedef struct _uarths_ie +{ + /* Bit 0 is txwm, raised less than txcnt */ + uint32_t txwm : 1; + /* Bit 1 is txwm, raised greater than rxcnt */ + uint32_t rxwm : 1; + /* Bits [31:2] is 0 */ + uint32_t zero : 30; +} __attribute__((packed, aligned(4))) uarths_ie_t; + +typedef struct _uarths_div +{ + /* Bits [31:2] is baud rate divisor register */ + uint32_t div : 16; + /* Bits [31:16] is 0 */ + uint32_t zero : 16; +} __attribute__((packed, aligned(4))) uarths_div_t; + +typedef struct _uarths +{ + /* Address offset 0x00 */ + uarths_txdata_t txdata; + /* Address offset 0x04 */ + uarths_rxdata_t rxdata; + /* Address offset 0x08 */ + uarths_txctrl_t txctrl; + /* Address offset 0x0c */ + uarths_rxctrl_t rxctrl; + /* Address offset 0x10 */ + uarths_ie_t ie; + /* Address offset 0x14 */ + uarths_ip_t ip; + /* Address offset 0x18 */ + uarths_div_t div; +} __attribute__((packed, aligned(4))) UarthsT; + +typedef enum _uarths_interrupt_mode +{ + UARTHS_SEND = 1, + UARTHS_RECEIVE = 2, + UARTHS_SEND_RECEIVE = 3, +} uarths_interrupt_mode_t; + +typedef enum _uarths_stopbit +{ + UARTHS_STOP_1, + UARTHS_STOP_2 +} uarths_stopbit_t; + +extern volatile UarthsT *const uarths; + +/** + * @brief Initialization Core UART + * + * @return result + * - 0 Success + * - Other Fail + */ +void uarths_init(void); + +/** + * @brief Put a char to UART + * + * @param[in] c The char to put + * + * @note If c is '\n', a '\r' will be appended automatically + * + * @return result + * - 0 Success + * - Other Fail + */ +int uarths_putchar(char c); + +/** + * @brief Send a string to UART + * + * @param[in] s The string to send + * + * @note The string must ending with '\0' + * + * @return result + * - 0 Success + * - Other Fail + */ +int uarths_puts(const char *s); + + +/** + * @brief Get a byte from UART + * + * @return byte as int type from UART + */ +int uarths_getc(void); + +/** + * @brief Set uarths interrupt callback + * + * @param[in] interrupt_mode Interrupt mode recevice or send + * @param[in] uarths_callback Interrupt callback + * @param[in] ctx Param of callback + * @param[in] priority Interrupt priority + * + */ +void uarths_set_irq(uarths_interrupt_mode_t interrupt_mode, plic_irq_callback_t uarths_callback, void *ctx, uint32_t priority); + +/** + * @brief Uarths receive data + * + * @param[in] buf The data received + * @param[in] BufLen The length of data + * + * @return Number of received data + */ +size_t uarths_receive_data(uint8_t *buf, size_t BufLen); + +/** + * @brief Uarths receive data + * + * @param[in] buf The data sended + * @param[in] BufLen The length of data + * + * @return Number of sended data + */ +size_t uarths_send_data(const uint8_t *buf, size_t BufLen); + +/** + * @brief Get interrupt mode + * + * @return Mode of interrupt + */ +uarths_interrupt_mode_t uarths_get_interrupt_mode(void); + +/** + * @brief Set uarths baud rate and stopbit + * + * @param[in] BaudRate The baud rate + * @param[in] stopbit The stopbit of data + * + */ +void uarths_config(uint32_t BaudRate, uarths_stopbit_t stopbit); + +/** + * @brief Set uart interrupt condition + * + * @param[in] interrupt_mode The interrupt mode + * @param[in] cnt The count of tigger + * + */ +void uarths_set_interrupt_cnt(uarths_interrupt_mode_t interrupt_mode, uint8_t cnt); + +#ifdef __cplusplus +} +#endif + +#endif /* __UARTHS_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/io.h b/board/k210-emulator/third_party_driver/include/io.h new file mode 100644 index 00000000..ea61bb8c --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/io.h @@ -0,0 +1,60 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 io.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __IO_H__ +#define __IO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define readb(addr) (*(volatile uint8_t *)(addr)) +#define readw(addr) (*(volatile uint16_t *)(addr)) +#define readl(addr) (*(volatile uint32_t *)(addr)) +#define readq(addr) (*(volatile uint64_t *)(addr)) + +#define writeb(v, addr) \ + { \ + (*(volatile uint8_t *)(addr)) = (v); \ + } +#define writew(v, addr) \ + { \ + (*(volatile uint16_t *)(addr)) = (v); \ + } +#define writel(v, addr) \ + { \ + (*(volatile uint32_t *)(addr)) = (v); \ + } +#define writeq(v, addr) \ + { \ + (*(volatile uint64_t *)(addr)) = (v); \ + } + +#ifdef __cplusplus +} +#endif + +#endif /* __IO_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/plic.h b/board/k210-emulator/third_party_driver/include/plic.h new file mode 100644 index 00000000..a293785e --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/plic.h @@ -0,0 +1,467 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 plic.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __PLIC_H__ +#define __PLIC_H__ + +#include +#include "encoding.h" +#include "platform.h" + +/* For c++ compatibility */ +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* IRQ number settings */ +#define PLIC_NUM_SOURCES (IRQN_MAX - 1) +#define PLIC_NUM_PRIORITIES (7) + +/* Real number of cores */ +#define PLIC_NUM_CORES (2) +/* clang-format on */ + +/** + * @brief PLIC External Interrupt Numbers + * + * @note PLIC interrupt sources + * + * | Source | Name | Description | + * |--------|--------------------------|------------------------------------| + * | 0 | IRQN_NO_INTERRUPT | The non-existent interrupt | + * | 1 | IRQN_SPI0_INTERRUPT | SPI0 interrupt | + * | 2 | IRQN_SPI1_INTERRUPT | SPI1 interrupt | + * | 3 | IRQN_SPI_SLAVE_INTERRUPT | SPI_SLAVE interrupt | + * | 4 | IRQN_SPI3_INTERRUPT | SPI3 interrupt | + * | 5 | IRQN_I2S0_INTERRUPT | I2S0 interrupt | + * | 6 | IRQN_I2S1_INTERRUPT | I2S1 interrupt | + * | 7 | IRQN_I2S2_INTERRUPT | I2S2 interrupt | + * | 8 | IRQN_I2C0_INTERRUPT | I2C0 interrupt | + * | 9 | IRQN_I2C1_INTERRUPT | I2C1 interrupt | + * | 10 | IRQN_I2C2_INTERRUPT | I2C2 interrupt | + * | 11 | IRQN_UART1_INTERRUPT | UART1 interrupt | + * | 12 | IRQN_UART2_INTERRUPT | UART2 interrupt | + * | 13 | IRQN_UART3_INTERRUPT | UART3 interrupt | + * | 14 | IRQN_TIMER0A_INTERRUPT | TIMER0 channel 0 or 1 interrupt | + * | 15 | IRQN_TIMER0B_INTERRUPT | TIMER0 channel 2 or 3 interrupt | + * | 16 | IRQN_TIMER1A_INTERRUPT | TIMER1 channel 0 or 1 interrupt | + * | 17 | IRQN_TIMER1B_INTERRUPT | TIMER1 channel 2 or 3 interrupt | + * | 18 | IRQN_TIMER2A_INTERRUPT | TIMER2 channel 0 or 1 interrupt | + * | 19 | IRQN_TIMER2B_INTERRUPT | TIMER2 channel 2 or 3 interrupt | + * | 20 | IRQN_RTC_INTERRUPT | RTC tick and alarm interrupt | + * | 21 | IRQN_WDT0_INTERRUPT | Watching dog timer0 interrupt | + * | 22 | IRQN_WDT1_INTERRUPT | Watching dog timer1 interrupt | + * | 23 | IRQN_APB_GPIO_INTERRUPT | APB GPIO interrupt | + * | 24 | IRQN_DVP_INTERRUPT | Digital video port interrupt | + * | 25 | IRQN_AI_INTERRUPT | AI accelerator interrupt | + * | 26 | IRQN_FFT_INTERRUPT | FFT accelerator interrupt | + * | 27 | IRQN_DMA0_INTERRUPT | DMA channel0 interrupt | + * | 28 | IRQN_DMA1_INTERRUPT | DMA channel1 interrupt | + * | 29 | IRQN_DMA2_INTERRUPT | DMA channel2 interrupt | + * | 30 | IRQN_DMA3_INTERRUPT | DMA channel3 interrupt | + * | 31 | IRQN_DMA4_INTERRUPT | DMA channel4 interrupt | + * | 32 | IRQN_DMA5_INTERRUPT | DMA channel5 interrupt | + * | 33 | IRQN_UARTHS_INTERRUPT | Hi-speed UART0 interrupt | + * | 34 | IRQN_GPIOHS0_INTERRUPT | Hi-speed GPIO0 interrupt | + * | 35 | IRQN_GPIOHS1_INTERRUPT | Hi-speed GPIO1 interrupt | + * | 36 | IRQN_GPIOHS2_INTERRUPT | Hi-speed GPIO2 interrupt | + * | 37 | IRQN_GPIOHS3_INTERRUPT | Hi-speed GPIO3 interrupt | + * | 38 | IRQN_GPIOHS4_INTERRUPT | Hi-speed GPIO4 interrupt | + * | 39 | IRQN_GPIOHS5_INTERRUPT | Hi-speed GPIO5 interrupt | + * | 40 | IRQN_GPIOHS6_INTERRUPT | Hi-speed GPIO6 interrupt | + * | 41 | IRQN_GPIOHS7_INTERRUPT | Hi-speed GPIO7 interrupt | + * | 42 | IRQN_GPIOHS8_INTERRUPT | Hi-speed GPIO8 interrupt | + * | 43 | IRQN_GPIOHS9_INTERRUPT | Hi-speed GPIO9 interrupt | + * | 44 | IRQN_GPIOHS10_INTERRUPT | Hi-speed GPIO10 interrupt | + * | 45 | IRQN_GPIOHS11_INTERRUPT | Hi-speed GPIO11 interrupt | + * | 46 | IRQN_GPIOHS12_INTERRUPT | Hi-speed GPIO12 interrupt | + * | 47 | IRQN_GPIOHS13_INTERRUPT | Hi-speed GPIO13 interrupt | + * | 48 | IRQN_GPIOHS14_INTERRUPT | Hi-speed GPIO14 interrupt | + * | 49 | IRQN_GPIOHS15_INTERRUPT | Hi-speed GPIO15 interrupt | + * | 50 | IRQN_GPIOHS16_INTERRUPT | Hi-speed GPIO16 interrupt | + * | 51 | IRQN_GPIOHS17_INTERRUPT | Hi-speed GPIO17 interrupt | + * | 52 | IRQN_GPIOHS18_INTERRUPT | Hi-speed GPIO18 interrupt | + * | 53 | IRQN_GPIOHS19_INTERRUPT | Hi-speed GPIO19 interrupt | + * | 54 | IRQN_GPIOHS20_INTERRUPT | Hi-speed GPIO20 interrupt | + * | 55 | IRQN_GPIOHS21_INTERRUPT | Hi-speed GPIO21 interrupt | + * | 56 | IRQN_GPIOHS22_INTERRUPT | Hi-speed GPIO22 interrupt | + * | 57 | IRQN_GPIOHS23_INTERRUPT | Hi-speed GPIO23 interrupt | + * | 58 | IRQN_GPIOHS24_INTERRUPT | Hi-speed GPIO24 interrupt | + * | 59 | IRQN_GPIOHS25_INTERRUPT | Hi-speed GPIO25 interrupt | + * | 60 | IRQN_GPIOHS26_INTERRUPT | Hi-speed GPIO26 interrupt | + * | 61 | IRQN_GPIOHS27_INTERRUPT | Hi-speed GPIO27 interrupt | + * | 62 | IRQN_GPIOHS28_INTERRUPT | Hi-speed GPIO28 interrupt | + * | 63 | IRQN_GPIOHS29_INTERRUPT | Hi-speed GPIO29 interrupt | + * | 64 | IRQN_GPIOHS30_INTERRUPT | Hi-speed GPIO30 interrupt | + * | 65 | IRQN_GPIOHS31_INTERRUPT | Hi-speed GPIO31 interrupt | + * + */ +/* clang-format off */ +typedef enum _plic_irq +{ + IRQN_NO_INTERRUPT = 0, /*!< The non-existent interrupt */ + IRQN_SPI0_INTERRUPT = 1, /*!< SPI0 interrupt */ + IRQN_SPI1_INTERRUPT = 2, /*!< SPI1 interrupt */ + IRQN_SPI_SLAVE_INTERRUPT = 3, /*!< SPI_SLAVE interrupt */ + //IRQN_SPI3_INTERRUPT = 4, /*!< SPI3 interrupt */ + IRQN_I2S0_INTERRUPT = 5, /*!< I2S0 interrupt */ + IRQN_I2S1_INTERRUPT = 6, /*!< I2S1 interrupt */ + IRQN_I2S2_INTERRUPT = 7, /*!< I2S2 interrupt */ + IRQN_I2C0_INTERRUPT = 8, /*!< I2C0 interrupt */ + IRQN_I2C1_INTERRUPT = 9, /*!< I2C1 interrupt */ + IRQN_I2C2_INTERRUPT = 10, /*!< I2C2 interrupt */ + IRQN_UART1_INTERRUPT = 11, /*!< UART1 interrupt */ + IRQN_UART2_INTERRUPT = 12, /*!< UART2 interrupt */ + IRQN_UART3_INTERRUPT = 13, /*!< UART3 interrupt */ + IRQN_TIMER0A_INTERRUPT = 14, /*!< TIMER0 channel 0 or 1 interrupt */ + IRQN_TIMER0B_INTERRUPT = 15, /*!< TIMER0 channel 2 or 3 interrupt */ + IRQN_TIMER1A_INTERRUPT = 16, /*!< TIMER1 channel 0 or 1 interrupt */ + IRQN_TIMER1B_INTERRUPT = 17, /*!< TIMER1 channel 2 or 3 interrupt */ + IRQN_TIMER2A_INTERRUPT = 18, /*!< TIMER2 channel 0 or 1 interrupt */ + IRQN_TIMER2B_INTERRUPT = 19, /*!< TIMER2 channel 2 or 3 interrupt */ + IRQN_RTC_INTERRUPT = 20, /*!< RTC tick and alarm interrupt */ + IRQN_WDT0_INTERRUPT = 21, /*!< Watching dog timer0 interrupt */ + IRQN_WDT1_INTERRUPT = 22, /*!< Watching dog timer1 interrupt */ + IRQN_APB_GPIO_INTERRUPT = 23, /*!< APB GPIO interrupt */ + IRQN_DVP_INTERRUPT = 24, /*!< Digital video port interrupt */ + IRQN_AI_INTERRUPT = 25, /*!< AI accelerator interrupt */ + IRQN_FFT_INTERRUPT = 26, /*!< FFT accelerator interrupt */ + IRQN_DMA0_INTERRUPT = 27, /*!< DMA channel0 interrupt */ + IRQN_DMA1_INTERRUPT = 28, /*!< DMA channel1 interrupt */ + IRQN_DMA2_INTERRUPT = 29, /*!< DMA channel2 interrupt */ + IRQN_DMA3_INTERRUPT = 30, /*!< DMA channel3 interrupt */ + IRQN_DMA4_INTERRUPT = 31, /*!< DMA channel4 interrupt */ + IRQN_DMA5_INTERRUPT = 32, /*!< DMA channel5 interrupt */ + IRQN_UARTHS_INTERRUPT = 4, /*!< Hi-speed UART0 interrupt */ + IRQN_GPIOHS0_INTERRUPT = 34, /*!< Hi-speed GPIO0 interrupt */ + IRQN_GPIOHS1_INTERRUPT = 35, /*!< Hi-speed GPIO1 interrupt */ + IRQN_GPIOHS2_INTERRUPT = 36, /*!< Hi-speed GPIO2 interrupt */ + IRQN_GPIOHS3_INTERRUPT = 37, /*!< Hi-speed GPIO3 interrupt */ + IRQN_GPIOHS4_INTERRUPT = 38, /*!< Hi-speed GPIO4 interrupt */ + IRQN_GPIOHS5_INTERRUPT = 39, /*!< Hi-speed GPIO5 interrupt */ + IRQN_GPIOHS6_INTERRUPT = 40, /*!< Hi-speed GPIO6 interrupt */ + IRQN_GPIOHS7_INTERRUPT = 41, /*!< Hi-speed GPIO7 interrupt */ + IRQN_GPIOHS8_INTERRUPT = 42, /*!< Hi-speed GPIO8 interrupt */ + IRQN_GPIOHS9_INTERRUPT = 43, /*!< Hi-speed GPIO9 interrupt */ + IRQN_GPIOHS10_INTERRUPT = 44, /*!< Hi-speed GPIO10 interrupt */ + IRQN_GPIOHS11_INTERRUPT = 45, /*!< Hi-speed GPIO11 interrupt */ + IRQN_GPIOHS12_INTERRUPT = 46, /*!< Hi-speed GPIO12 interrupt */ + IRQN_GPIOHS13_INTERRUPT = 47, /*!< Hi-speed GPIO13 interrupt */ + IRQN_GPIOHS14_INTERRUPT = 48, /*!< Hi-speed GPIO14 interrupt */ + IRQN_GPIOHS15_INTERRUPT = 49, /*!< Hi-speed GPIO15 interrupt */ + IRQN_GPIOHS16_INTERRUPT = 50, /*!< Hi-speed GPIO16 interrupt */ + IRQN_GPIOHS17_INTERRUPT = 51, /*!< Hi-speed GPIO17 interrupt */ + IRQN_GPIOHS18_INTERRUPT = 52, /*!< Hi-speed GPIO18 interrupt */ + IRQN_GPIOHS19_INTERRUPT = 53, /*!< Hi-speed GPIO19 interrupt */ + IRQN_GPIOHS20_INTERRUPT = 54, /*!< Hi-speed GPIO20 interrupt */ + IRQN_GPIOHS21_INTERRUPT = 55, /*!< Hi-speed GPIO21 interrupt */ + IRQN_GPIOHS22_INTERRUPT = 56, /*!< Hi-speed GPIO22 interrupt */ + IRQN_GPIOHS23_INTERRUPT = 57, /*!< Hi-speed GPIO23 interrupt */ + IRQN_GPIOHS24_INTERRUPT = 58, /*!< Hi-speed GPIO24 interrupt */ + IRQN_GPIOHS25_INTERRUPT = 59, /*!< Hi-speed GPIO25 interrupt */ + IRQN_GPIOHS26_INTERRUPT = 60, /*!< Hi-speed GPIO26 interrupt */ + IRQN_GPIOHS27_INTERRUPT = 61, /*!< Hi-speed GPIO27 interrupt */ + IRQN_GPIOHS28_INTERRUPT = 62, /*!< Hi-speed GPIO28 interrupt */ + IRQN_GPIOHS29_INTERRUPT = 63, /*!< Hi-speed GPIO29 interrupt */ + IRQN_GPIOHS30_INTERRUPT = 64, /*!< Hi-speed GPIO30 interrupt */ + IRQN_GPIOHS31_INTERRUPT = 65, /*!< Hi-speed GPIO31 interrupt */ + IRQN_MAX +} plic_irq_t; +/* clang-format on */ + +/** + * @brief Interrupt Source Priorities + * + * Each external interrupt source can be assigned a priority by + * writing to its 32-bit memory-mapped priority register. The + * number and value of supported priority levels can vary by + * implementa- tion, with the simplest implementations having all + * devices hardwired at priority 1, in which case, interrupts with + * the lowest ID have the highest effective priority. The priority + * registers are all WARL. + */ +typedef struct _plic_source_priorities +{ + /* 0x0C000000: Reserved, 0x0C000004-0x0C000FFC: 1-1023 priorities */ + uint32_t priority[1024]; +} __attribute__((packed, aligned(4))) plic_source_priorities_t; + +/** + * @brief Interrupt Pending Bits + * + * The current status of the interrupt source pending bits in the + * PLIC core can be read from the pending array, organized as 32 + * words of 32 bits. The pending bit for interrupt ID N is stored + * in bit (N mod 32) of word (N/32). Bit 0 of word 0, which + * represents the non-existent interrupt source 0, is always + * hardwired to zero. The pending bits are read-only. A pending + * bit in the PLIC core can be cleared by setting enable bits to + * only enable the desired interrupt, then performing a claim. A + * pending bit can be set by instructing the associated gateway to + * send an interrupt service request. + */ +typedef struct _plic_pending_bits +{ + /* 0x0C001000-0x0C00107C: Bit 0 is zero, Bits 1-1023 is pending bits */ + uint32_t u32[32]; + /* 0x0C001080-0x0C001FFF: Reserved */ + uint8_t resv[0xF80]; +} __attribute__((packed, aligned(4))) plic_pending_bits_t; + +/** + * @brief Target Interrupt Enables + * + * For each interrupt target, each device’s interrupt can be + * enabled by setting the corresponding bit in that target’s + * enables registers. The enables for a target are accessed as a + * contiguous array of 32×32-bit words, packed the same way as the + * pending bits. For each target, bit 0 of enable word 0 + * represents the non-existent interrupt ID 0 and is hardwired to + * 0. Unused interrupt IDs are also hardwired to zero. The enables + * arrays for different targets are packed contiguously in the + * address space. Only 32-bit word accesses are supported by the + * enables array in RV32 systems. Implementations can trap on + * accesses to enables for non-existent targets, but must allow + * access to the full enables array for any extant target, + * treating all non-existent interrupt source’s enables as + * hardwired to zero. + */ +typedef struct _plic_target_enables +{ + /* 0x0C002000-0x0C1F1F80: target 0-15871 enables */ + struct + { + uint32_t enable[32 * 2];/* Offset 0x00-0x7C: Bit 0 is zero, Bits 1-1023 is bits*/ + } target[15872 / 2]; + + /* 0x0C1F2000-0x0C1FFFFC: Reserved, size 0xE000 */ + uint8_t resv[0xE000]; +} __attribute__((packed, aligned(4))) plic_target_enables_t; + +/** + * @brief PLIC Targets + * + * Target Priority Thresholds The threshold for a pending + * interrupt priority that can interrupt each target can be set in + * the target’s threshold register. The threshold is a WARL field, + * where different implementations can support different numbers + * of thresholds. The simplest implementation has a threshold + * hardwired to zero. + * + * Target Claim Each target can perform a claim by reading the + * claim/complete register, which returns the ID of the highest + * priority pending interrupt or zero if there is no pending + * interrupt for the target. A successful claim will also + * atomically clear the corresponding pending bit on the interrupt + * source. A target can perform a claim at any time, even if the + * EIP is not set. The claim operation is not affected by the + * setting of the target’s priority threshold register. + * + * Target Completion A target signals it has completed running a + * handler by writing the interrupt ID it received from the claim + * to the claim/complete register. This is routed to the + * corresponding interrupt gateway, which can now send another + * interrupt request to the PLIC. The PLIC does not check whether + * the completion ID is the same as the last claim ID for that + * target. If the completion ID does not match an interrupt source + * that is currently enabled for the target, the completion is + * silently ignored. + */ +typedef struct _plic_target +{ + /* 0x0C200000-0x0FFFF004: target 0-15871 */ + struct { + uint32_t priority_threshold;/* Offset 0x000 */ + uint32_t claim_complete; /* Offset 0x004 */ + uint8_t resv[0x1FF8]; /* Offset 0x008, Size 0xFF8 */ + } target[15872 / 2]; +} __attribute__((packed, aligned(4))) plic_target_t; + +/** + * @brief Platform-Level Interrupt Controller + * + * PLIC is Platform-Level Interrupt Controller. The PLIC complies + * with the RISC-V Privileged Architecture specification, and can + * support a maximum of 1023 external interrupt sources targeting + * up to 15,872 core contexts. + */ +typedef struct _plic +{ + /* 0x0C000000-0x0C000FFC */ + plic_source_priorities_t source_priorities; + /* 0x0C001000-0x0C001FFF */ + const plic_pending_bits_t pending_bits; + /* 0x0C002000-0x0C1FFFFC */ + plic_target_enables_t target_enables; + /* 0x0C200000-0x0FFFF004 */ + plic_target_t targets; +} __attribute__((packed, aligned(4))) plic_t; + +extern volatile plic_t *const plic; + +/** + * @brief Definitions for the interrupt callbacks + */ +typedef int (*plic_irq_callback_t)(void *ctx); + +/** + * @brief Definitions for IRQ table instance + */ +typedef struct _plic_instance_t +{ + plic_irq_callback_t callback; + void *ctx; +} plic_instance_t; + +typedef struct _plic_callback_t +{ + plic_irq_callback_t callback; + void *ctx; + uint32_t priority; +} plic_interrupt_t; + +/** + * @brief Initialize PLIC external interrupt + * + * @note This function will set MIP_MEIP. The MSTATUS_MIE must set by user. + * + * @return result + * - 0 Success + * - Other Fail + */ +void plic_init(void); + +/** + * @brief Enable PLIC external interrupt + * + * @param[in] irq_number external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ + +int plic_irq_enable(plic_irq_t irq_number); + +/** + * @brief Disable PLIC external interrupt + * + * @param[in] irq_number The external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_irq_disable(plic_irq_t irq_number); + +/** + * @brief Set IRQ priority + * + * @param[in] irq_number The external interrupt number + * @param[in] priority The priority of external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_set_priority(plic_irq_t irq_number, uint32_t priority); + +/** + * @brief Get IRQ priority + * + * @param[in] irq_number The external interrupt number + * + * @return The priority of external interrupt number + */ +uint32_t plic_get_priority(plic_irq_t irq_number); + +/** + * @brief Claim an IRQ + * + * @return The current IRQ number + */ +uint32_t plic_irq_claim(void); + +/** + * @brief Complete an IRQ + * + * @param[in] source The source IRQ number to complete + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_irq_complete(uint32_t source); + +/** + * @brief Register user callback function by IRQ number + * + * @param[in] irq The irq + * @param[in] callback The callback + * @param ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx); + +/** + * @brief Deegister user callback function by IRQ number + * + * @param[in] irq The irq + * + * @return result + * - 0 Success + * - Other Fail + */ +void plic_irq_deregister(plic_irq_t irq); + +/** + * @brief Deegister user callback function by IRQ number + * + * @param[in] irq The irq + * + * @return result + * - 0 Success + * - Other Fail + */ +void plic_irq_unregister(plic_irq_t irq); + +/** + * @brief Get IRQ table, Usage: + * plic_instance_t (*plic_instance)[IRQN_MAX] = plic_get_instance(); + * ... plic_instance[x][y] ...; + * + * @return the point of IRQ table + */ +plic_instance_t (*plic_get_instance(void))[IRQN_MAX]; + +/* For c++ compatibility */ +#ifdef __cplusplus +} +#endif + +#endif /* __PLIC_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/sysctl.h b/board/k210-emulator/third_party_driver/include/sysctl.h new file mode 100644 index 00000000..72c0451e --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/sysctl.h @@ -0,0 +1,1088 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 sysctl.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __SYSCTL_H__ +#define __SYSCTL_H__ + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief System controller register + * + * @note System controller register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | git_id | Git short commit id | + * | 0x04 | clk_freq | System clock base frequency | + * | 0x08 | pll0 | PLL0 controller | + * | 0x0c | pll1 | PLL1 controller | + * | 0x10 | pll2 | PLL2 controller | + * | 0x14 | resv5 | Reserved | + * | 0x18 | pll_lock | PLL lock tester | + * | 0x1c | rom_error | AXI ROM detector | + * | 0x20 | clk_sel0 | Clock select controller0 | + * | 0x24 | clk_sel1 | Clock select controller1 | + * | 0x28 | clk_en_cent | Central clock enable | + * | 0x2c | clk_en_peri | Peripheral clock enable | + * | 0x30 | soft_reset | Soft reset ctrl | + * | 0x34 | peri_reset | Peripheral reset controller | + * | 0x38 | clk_th0 | Clock threshold controller 0 | + * | 0x3c | clk_th1 | Clock threshold controller 1 | + * | 0x40 | clk_th2 | Clock threshold controller 2 | + * | 0x44 | clk_th3 | Clock threshold controller 3 | + * | 0x48 | clk_th4 | Clock threshold controller 4 | + * | 0x4c | clk_th5 | Clock threshold controller 5 | + * | 0x50 | clk_th6 | Clock threshold controller 6 | + * | 0x54 | misc | Miscellaneous controller | + * | 0x58 | peri | Peripheral controller | + * | 0x5c | spi_sleep | SPI sleep controller | + * | 0x60 | reset_status | Reset source status | + * | 0x64 | dma_sel0 | DMA handshake selector | + * | 0x68 | dma_sel1 | DMA handshake selector | + * | 0x6c | power_sel | IO Power Mode Select controller | + * | 0x70 | resv28 | Reserved | + * | 0x74 | resv29 | Reserved | + * | 0x78 | resv30 | Reserved | + * | 0x7c | resv31 | Reserved | + * + */ + +typedef enum _sysctl_pll_t +{ + SYSCTL_PLL0, + SYSCTL_PLL1, + SYSCTL_PLL2, + SYSCTL_PLL_MAX +} sysctl_pll_t; + +typedef enum _sysctl_clock_source_t +{ + SYSCTL_SOURCE_IN0, + SYSCTL_SOURCE_PLL0, + SYSCTL_SOURCE_PLL1, + SYSCTL_SOURCE_PLL2, + SYSCTL_SOURCE_ACLK, + SYSCTL_SOURCE_MAX +} sysctl_clock_source_t; + +typedef enum _sysctl_dma_channel_t +{ + SYSCTL_DMA_CHANNEL_0, + SYSCTL_DMA_CHANNEL_1, + SYSCTL_DMA_CHANNEL_2, + SYSCTL_DMA_CHANNEL_3, + SYSCTL_DMA_CHANNEL_4, + SYSCTL_DMA_CHANNEL_5, + SYSCTL_DMA_CHANNEL_MAX +} sysctl_dma_channel_t; + +typedef enum _sysctl_dma_select_t +{ + SYSCTL_DMA_SELECT_SSI0_RX_REQ, + SYSCTL_DMA_SELECT_SSI0_TX_REQ, + SYSCTL_DMA_SELECT_SSI1_RX_REQ, + SYSCTL_DMA_SELECT_SSI1_TX_REQ, + SYSCTL_DMA_SELECT_SSI2_RX_REQ, + SYSCTL_DMA_SELECT_SSI2_TX_REQ, + SYSCTL_DMA_SELECT_SSI3_RX_REQ, + SYSCTL_DMA_SELECT_SSI3_TX_REQ, + SYSCTL_DMA_SELECT_I2C0_RX_REQ, + SYSCTL_DMA_SELECT_I2C0_TX_REQ, + SYSCTL_DMA_SELECT_I2C1_RX_REQ, + SYSCTL_DMA_SELECT_I2C1_TX_REQ, + SYSCTL_DMA_SELECT_I2C2_RX_REQ, + SYSCTL_DMA_SELECT_I2C2_TX_REQ, + SYSCTL_DMA_SELECT_UART1_RX_REQ, + SYSCTL_DMA_SELECT_UART1_TX_REQ, + SYSCTL_DMA_SELECT_UART2_RX_REQ, + SYSCTL_DMA_SELECT_UART2_TX_REQ, + SYSCTL_DMA_SELECT_UART3_RX_REQ, + SYSCTL_DMA_SELECT_UART3_TX_REQ, + SYSCTL_DMA_SELECT_AES_REQ, + SYSCTL_DMA_SELECT_SHA_RX_REQ, + SYSCTL_DMA_SELECT_AI_RX_REQ, + SYSCTL_DMA_SELECT_FFT_RX_REQ, + SYSCTL_DMA_SELECT_FFT_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_RX_REQ, + SYSCTL_DMA_SELECT_I2S1_TX_REQ, + SYSCTL_DMA_SELECT_I2S1_RX_REQ, + SYSCTL_DMA_SELECT_I2S2_TX_REQ, + SYSCTL_DMA_SELECT_I2S2_RX_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_DIR_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_VOICE_REQ, + SYSCTL_DMA_SELECT_MAX +} sysctl_dma_select_t; + +/** + * @brief System controller clock id + */ +typedef enum _sysctl_clock_t +{ + SYSCTL_CLOCK_PLL0, + SYSCTL_CLOCK_PLL1, + SYSCTL_CLOCK_PLL2, + SYSCTL_CLOCK_CPU, + SYSCTL_CLOCK_SRAM0, + SYSCTL_CLOCK_SRAM1, + SYSCTL_CLOCK_APB0, + SYSCTL_CLOCK_APB1, + SYSCTL_CLOCK_APB2, + SYSCTL_CLOCK_ROM, + SYSCTL_CLOCK_DMA, + SYSCTL_CLOCK_AI, + SYSCTL_CLOCK_DVP, + SYSCTL_CLOCK_FFT, + SYSCTL_CLOCK_GPIO, + SYSCTL_CLOCK_SPI0, + SYSCTL_CLOCK_SPI1, + SYSCTL_CLOCK_SPI2, + SYSCTL_CLOCK_SPI3, + SYSCTL_CLOCK_I2S0, + SYSCTL_CLOCK_I2S1, + SYSCTL_CLOCK_I2S2, + SYSCTL_CLOCK_I2C0, + SYSCTL_CLOCK_I2C1, + SYSCTL_CLOCK_I2C2, + SYSCTL_CLOCK_UART1, + SYSCTL_CLOCK_UART2, + SYSCTL_CLOCK_UART3, + SYSCTL_CLOCK_AES, + SYSCTL_CLOCK_FPIOA, + SYSCTL_CLOCK_TIMER0, + SYSCTL_CLOCK_TIMER1, + SYSCTL_CLOCK_TIMER2, + SYSCTL_CLOCK_WDT0, + SYSCTL_CLOCK_WDT1, + SYSCTL_CLOCK_SHA, + SYSCTL_CLOCK_OTP, + SYSCTL_CLOCK_RTC, + SYSCTL_CLOCK_ACLK = 40, + SYSCTL_CLOCK_HCLK, + SYSCTL_CLOCK_IN0, + SYSCTL_CLOCK_MAX +} sysctl_clock_t; + +/** + * @brief System controller clock select id + */ +typedef enum _sysctl_clock_select_t +{ + SYSCTL_CLOCK_SELECT_PLL0_BYPASS, + SYSCTL_CLOCK_SELECT_PLL1_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2, + SYSCTL_CLOCK_SELECT_ACLK, + SYSCTL_CLOCK_SELECT_SPI3, + SYSCTL_CLOCK_SELECT_TIMER0, + SYSCTL_CLOCK_SELECT_TIMER1, + SYSCTL_CLOCK_SELECT_TIMER2, + SYSCTL_CLOCK_SELECT_SPI3_SAMPLE, + SYSCTL_CLOCK_SELECT_MAX = 11 +} sysctl_clock_select_t; + +/** + * @brief System controller clock threshold id + */ +typedef enum _sysctl_threshold_t +{ + SYSCTL_THRESHOLD_ACLK, + SYSCTL_THRESHOLD_APB0, + SYSCTL_THRESHOLD_APB1, + SYSCTL_THRESHOLD_APB2, + SYSCTL_THRESHOLD_SRAM0, + SYSCTL_THRESHOLD_SRAM1, + SYSCTL_THRESHOLD_AI, + SYSCTL_THRESHOLD_DVP, + SYSCTL_THRESHOLD_ROM, + SYSCTL_THRESHOLD_SPI0, + SYSCTL_THRESHOLD_SPI1, + SYSCTL_THRESHOLD_SPI2, + SYSCTL_THRESHOLD_SPI3, + SYSCTL_THRESHOLD_TIMER0, + SYSCTL_THRESHOLD_TIMER1, + SYSCTL_THRESHOLD_TIMER2, + SYSCTL_THRESHOLD_I2S0, + SYSCTL_THRESHOLD_I2S1, + SYSCTL_THRESHOLD_I2S2, + SYSCTL_THRESHOLD_I2S0_M, + SYSCTL_THRESHOLD_I2S1_M, + SYSCTL_THRESHOLD_I2S2_M, + SYSCTL_THRESHOLD_I2C0, + SYSCTL_THRESHOLD_I2C1, + SYSCTL_THRESHOLD_I2C2, + SYSCTL_THRESHOLD_WDT0, + SYSCTL_THRESHOLD_WDT1, + SYSCTL_THRESHOLD_MAX = 28 +} sysctl_threshold_t; + +/** + * @brief System controller reset control id + */ +typedef enum _sysctl_reset_t +{ + SYSCTL_RESET_SOC, + SYSCTL_RESET_ROM, + SYSCTL_RESET_DMA, + SYSCTL_RESET_AI, + SYSCTL_RESET_DVP, + SYSCTL_RESET_FFT, + SYSCTL_RESET_GPIO, + SYSCTL_RESET_SPI0, + SYSCTL_RESET_SPI1, + SYSCTL_RESET_SPI2, + SYSCTL_RESET_SPI3, + SYSCTL_RESET_I2S0, + SYSCTL_RESET_I2S1, + SYSCTL_RESET_I2S2, + SYSCTL_RESET_I2C0, + SYSCTL_RESET_I2C1, + SYSCTL_RESET_I2C2, + SYSCTL_RESET_UART1, + SYSCTL_RESET_UART2, + SYSCTL_RESET_UART3, + SYSCTL_RESET_AES, + SYSCTL_RESET_FPIOA, + SYSCTL_RESET_TIMER0, + SYSCTL_RESET_TIMER1, + SYSCTL_RESET_TIMER2, + SYSCTL_RESET_WDT0, + SYSCTL_RESET_WDT1, + SYSCTL_RESET_SHA, + SYSCTL_RESET_RTC, + SYSCTL_RESET_MAX = 31 +} sysctl_reset_t; + +/** + * @brief System controller power bank id + */ +typedef enum _sysctl_power_bank +{ + SYSCTL_POWER_BANK0, + SYSCTL_POWER_BANK1, + SYSCTL_POWER_BANK2, + SYSCTL_POWER_BANK3, + SYSCTL_POWER_BANK4, + SYSCTL_POWER_BANK5, + SYSCTL_POWER_BANK6, + SYSCTL_POWER_BANK7, + SYSCTL_POWER_BANK_MAX, +} sysctl_power_bank_t; + +/** + * @brief System controller reset control id + */ +typedef enum _sysctl_io_power_mode +{ + SYSCTL_POWER_V33, + SYSCTL_POWER_V18 +} sysctl_io_power_mode_t; + +/** + * @brief System reset status + */ +typedef enum _sysctl_reset_enum_status +{ + SYSCTL_RESET_STATUS_HARD, + SYSCTL_RESET_STATUS_SOFT, + SYSCTL_RESET_STATUS_WDT0, + SYSCTL_RESET_STATUS_WDT1, + SYSCTL_RESET_STATUS_MAX, +} sysctl_reset_enum_status_t; + +/** + * @brief Git short commit id + * + * No. 0 Register (0x00) + */ +typedef struct _sysctl_git_id +{ + uint32_t git_id : 32; +} __attribute__((packed, aligned(4))) sysctl_git_id_t; + +/** + * @brief System clock base frequency + * + * No. 1 Register (0x04) + */ +typedef struct _sysctl_clk_freq +{ + uint32_t clk_freq : 32; +} __attribute__((packed, aligned(4))) sysctl_clk_freq_t; + +/** + * @brief PLL0 controller + * + * No. 2 Register (0x08) + */ +typedef struct _sysctl_pll0 +{ + uint32_t clkr0 : 4; + uint32_t clkf0 : 6; + uint32_t clkod0 : 4; + uint32_t bwadj0 : 6; + uint32_t pll_reset0 : 1; + uint32_t pll_pwrd0 : 1; + uint32_t pll_intfb0 : 1; + uint32_t pll_bypass0 : 1; + uint32_t pll_test0 : 1; + uint32_t pll_out_en0 : 1; + uint32_t pll_test_en : 1; + uint32_t reserved : 5; +} __attribute__((packed, aligned(4))) sysctl_pll0_t; + +/** + * @brief PLL1 controller + * + * No. 3 Register (0x0c) + */ +typedef struct _sysctl_pll1 +{ + uint32_t clkr1 : 4; + uint32_t clkf1 : 6; + uint32_t clkod1 : 4; + uint32_t bwadj1 : 6; + uint32_t pll_reset1 : 1; + uint32_t pll_pwrd1 : 1; + uint32_t pll_intfb1 : 1; + uint32_t pll_bypass1 : 1; + uint32_t pll_test1 : 1; + uint32_t pll_out_en1 : 1; + uint32_t reserved : 6; +} __attribute__((packed, aligned(4))) sysctl_pll1_t; + +/** + * @brief PLL2 controller + * + * No. 4 Register (0x10) + */ +typedef struct _sysctl_pll2 +{ + uint32_t clkr2 : 4; + uint32_t clkf2 : 6; + uint32_t clkod2 : 4; + uint32_t bwadj2 : 6; + uint32_t pll_reset2 : 1; + uint32_t pll_pwrd2 : 1; + uint32_t pll_intfb2 : 1; + uint32_t pll_bypass2 : 1; + uint32_t pll_test2 : 1; + uint32_t pll_out_en2 : 1; + uint32_t pll_ckin_sel2 : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))) sysctl_pll2_t; + +/** + * @brief PLL lock tester + * + * No. 6 Register (0x18) + */ +typedef struct _sysctl_pll_lock +{ + uint32_t pll_lock0 : 2; + uint32_t pll_slip_clear0 : 1; + uint32_t test_clk_out0 : 1; + uint32_t reserved0 : 4; + uint32_t pll_lock1 : 2; + uint32_t pll_slip_clear1 : 1; + uint32_t test_clk_out1 : 1; + uint32_t reserved1 : 4; + uint32_t pll_lock2 : 2; + uint32_t pll_slip_clear2 : 1; + uint32_t test_clk_out2 : 1; + uint32_t reserved2 : 12; +} __attribute__((packed, aligned(4))) sysctl_pll_lock_t; + +/** + * @brief AXI ROM detector + * + * No. 7 Register (0x1c) + */ +typedef struct _sysctl_rom_error +{ + uint32_t rom_mul_error : 1; + uint32_t rom_one_error : 1; + uint32_t reserved : 30; +} __attribute__((packed, aligned(4))) sysctl_rom_error_t; + +/** + * @brief Clock select controller0 + * + * No. 8 Register (0x20) + */ +typedef struct _sysctl_clk_sel0 +{ + uint32_t aclk_sel : 1; + uint32_t aclk_divider_sel : 2; + uint32_t apb0_clk_sel : 3; + uint32_t apb1_clk_sel : 3; + uint32_t apb2_clk_sel : 3; + uint32_t spi3_clk_sel : 1; + uint32_t timer0_clk_sel : 1; + uint32_t timer1_clk_sel : 1; + uint32_t timer2_clk_sel : 1; + uint32_t reserved : 16; +} __attribute__((packed, aligned(4))) sysctl_clk_sel0_t; + +/** + * @brief Clock select controller1 + * + * No. 9 Register (0x24) + */ +typedef struct _sysctl_clk_sel1 +{ + uint32_t spi3_sample_clk_sel : 1; + uint32_t reserved0 : 30; + uint32_t reserved1 : 1; +} __attribute__((packed, aligned(4))) sysctl_clk_sel1_t; + +/** + * @brief Central clock enable + * + * No. 10 Register (0x28) + */ +typedef struct _sysctl_clk_en_cent +{ + uint32_t cpu_clk_en : 1; + uint32_t sram0_clk_en : 1; + uint32_t sram1_clk_en : 1; + uint32_t apb0_clk_en : 1; + uint32_t apb1_clk_en : 1; + uint32_t apb2_clk_en : 1; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))) sysctl_clk_en_cent_t; + +/** + * @brief Peripheral clock enable + * + * No. 11 Register (0x2c) + */ +typedef struct _sysctl_clk_en_peri +{ + uint32_t rom_clk_en : 1; + uint32_t dma_clk_en : 1; + uint32_t ai_clk_en : 1; + uint32_t dvp_clk_en : 1; + uint32_t fft_clk_en : 1; + uint32_t gpio_clk_en : 1; + uint32_t spi0_clk_en : 1; + uint32_t spi1_clk_en : 1; + uint32_t spi2_clk_en : 1; + uint32_t spi3_clk_en : 1; + uint32_t i2s0_clk_en : 1; + uint32_t i2s1_clk_en : 1; + uint32_t i2s2_clk_en : 1; + uint32_t i2c0_clk_en : 1; + uint32_t i2c1_clk_en : 1; + uint32_t i2c2_clk_en : 1; + uint32_t uart1_clk_en : 1; + uint32_t uart2_clk_en : 1; + uint32_t uart3_clk_en : 1; + uint32_t aes_clk_en : 1; + uint32_t fpioa_clk_en : 1; + uint32_t timer0_clk_en : 1; + uint32_t timer1_clk_en : 1; + uint32_t timer2_clk_en : 1; + uint32_t wdt0_clk_en : 1; + uint32_t wdt1_clk_en : 1; + uint32_t sha_clk_en : 1; + uint32_t otp_clk_en : 1; + uint32_t reserved : 1; + uint32_t rtc_clk_en : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))) sysctl_clk_en_peri_t; + +/** + * @brief Soft reset ctrl + * + * No. 12 Register (0x30) + */ +typedef struct _sysctl_soft_reset +{ + uint32_t soft_reset : 1; + uint32_t reserved : 31; +} __attribute__((packed, aligned(4))) sysctl_soft_reset_t; + +/** + * @brief Peripheral reset controller + * + * No. 13 Register (0x34) + */ +typedef struct _sysctl_peri_reset +{ + uint32_t rom_reset : 1; + uint32_t dma_reset : 1; + uint32_t ai_reset : 1; + uint32_t dvp_reset : 1; + uint32_t fft_reset : 1; + uint32_t gpio_reset : 1; + uint32_t spi0_reset : 1; + uint32_t spi1_reset : 1; + uint32_t spi2_reset : 1; + uint32_t spi3_reset : 1; + uint32_t i2s0_reset : 1; + uint32_t i2s1_reset : 1; + uint32_t i2s2_reset : 1; + uint32_t i2c0_reset : 1; + uint32_t i2c1_reset : 1; + uint32_t i2c2_reset : 1; + uint32_t uart1_reset : 1; + uint32_t uart2_reset : 1; + uint32_t uart3_reset : 1; + uint32_t aes_reset : 1; + uint32_t fpioa_reset : 1; + uint32_t timer0_reset : 1; + uint32_t timer1_reset : 1; + uint32_t timer2_reset : 1; + uint32_t wdt0_reset : 1; + uint32_t wdt1_reset : 1; + uint32_t sha_reset : 1; + uint32_t reserved : 2; + uint32_t rtc_reset : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))) sysctl_peri_reset_t; + +/** + * @brief Clock threshold controller 0 + * + * No. 14 Register (0x38) + */ +typedef struct _sysctl_clk_th0 +{ + uint32_t sram0_gclk_threshold : 4; + uint32_t sram1_gclk_threshold : 4; + uint32_t ai_gclk_threshold : 4; + uint32_t dvp_gclk_threshold : 4; + uint32_t rom_gclk_threshold : 4; + uint32_t reserved : 12; +} __attribute__((packed, aligned(4))) sysctl_clk_th0_t; + +/** + * @brief Clock threshold controller 1 + * + * No. 15 Register (0x3c) + */ +typedef struct _sysctl_clk_th1 +{ + uint32_t spi0_clk_threshold : 8; + uint32_t spi1_clk_threshold : 8; + uint32_t spi2_clk_threshold : 8; + uint32_t spi3_clk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th1_t; + +/** + * @brief Clock threshold controller 2 + * + * No. 16 Register (0x40) + */ +typedef struct _sysctl_clk_th2 +{ + uint32_t timer0_clk_threshold : 8; + uint32_t timer1_clk_threshold : 8; + uint32_t timer2_clk_threshold : 8; + uint32_t reserved : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th2_t; + +/** + * @brief Clock threshold controller 3 + * + * No. 17 Register (0x44) + */ +typedef struct _sysctl_clk_th3 +{ + uint32_t i2s0_clk_threshold : 16; + uint32_t i2s1_clk_threshold : 16; +} __attribute__((packed, aligned(4))) sysctl_clk_th3_t; + +/** + * @brief Clock threshold controller 4 + * + * No. 18 Register (0x48) + */ +typedef struct _sysctl_clk_th4 +{ + uint32_t i2s2_clk_threshold : 16; + uint32_t i2s0_mclk_threshold : 8; + uint32_t i2s1_mclk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th4_t; + +/** + * @brief Clock threshold controller 5 + * + * No. 19 Register (0x4c) + */ +typedef struct _sysctl_clk_th5 +{ + uint32_t i2s2_mclk_threshold : 8; + uint32_t i2c0_clk_threshold : 8; + uint32_t i2c1_clk_threshold : 8; + uint32_t i2c2_clk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th5_t; + +/** + * @brief Clock threshold controller 6 + * + * No. 20 Register (0x50) + */ +typedef struct _sysctl_clk_th6 +{ + uint32_t wdt0_clk_threshold : 8; + uint32_t wdt1_clk_threshold : 8; + uint32_t reserved0 : 8; + uint32_t reserved1 : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th6_t; + +/** + * @brief Miscellaneous controller + * + * No. 21 Register (0x54) + */ +typedef struct _sysctl_misc +{ + uint32_t debug_sel : 6; + uint32_t reserved0 : 4; + uint32_t spi_dvp_data_enable: 1; + uint32_t reserved1 : 21; +} __attribute__((packed, aligned(4))) sysctl_misc_t; + +/** + * @brief Peripheral controller + * + * No. 22 Register (0x58) + */ +typedef struct _sysctl_peri +{ + uint32_t timer0_pause : 1; + uint32_t timer1_pause : 1; + uint32_t timer2_pause : 1; + uint32_t timer3_pause : 1; + uint32_t timer4_pause : 1; + uint32_t timer5_pause : 1; + uint32_t timer6_pause : 1; + uint32_t timer7_pause : 1; + uint32_t timer8_pause : 1; + uint32_t timer9_pause : 1; + uint32_t timer10_pause : 1; + uint32_t timer11_pause : 1; + uint32_t spi0_xip_en : 1; + uint32_t spi1_xip_en : 1; + uint32_t spi2_xip_en : 1; + uint32_t spi3_xip_en : 1; + uint32_t spi0_clk_bypass : 1; + uint32_t spi1_clk_bypass : 1; + uint32_t spi2_clk_bypass : 1; + uint32_t i2s0_clk_bypass : 1; + uint32_t i2s1_clk_bypass : 1; + uint32_t i2s2_clk_bypass : 1; + uint32_t jtag_clk_bypass : 1; + uint32_t dvp_clk_bypass : 1; + uint32_t debug_clk_bypass : 1; + uint32_t reserved0 : 1; + uint32_t reserved1 : 6; +} __attribute__((packed, aligned(4))) sysctl_peri_t; + +/** + * @brief SPI sleep controller + * + * No. 23 Register (0x5c) + */ +typedef struct _sysctl_spi_sleep +{ + uint32_t ssi0_sleep : 1; + uint32_t ssi1_sleep : 1; + uint32_t ssi2_sleep : 1; + uint32_t ssi3_sleep : 1; + uint32_t reserved : 28; +} __attribute__((packed, aligned(4))) sysctl_spi_sleep_t; + +/** + * @brief Reset source status + * + * No. 24 Register (0x60) + */ +typedef struct _sysctl_reset_status +{ + uint32_t reset_sts_clr : 1; + uint32_t pin_reset_sts : 1; + uint32_t wdt0_reset_sts : 1; + uint32_t wdt1_reset_sts : 1; + uint32_t soft_reset_sts : 1; + uint32_t reserved : 27; +} __attribute__((packed, aligned(4))) sysctl_reset_status_t; + +/** + * @brief DMA handshake selector + * + * No. 25 Register (0x64) + */ +typedef struct _sysctl_dma_sel0 +{ + uint32_t dma_sel0 : 6; + uint32_t dma_sel1 : 6; + uint32_t dma_sel2 : 6; + uint32_t dma_sel3 : 6; + uint32_t dma_sel4 : 6; + uint32_t reserved : 2; +} __attribute__((packed, aligned(4))) sysctl_dma_sel0_t; + +/** + * @brief DMA handshake selector + * + * No. 26 Register (0x68) + */ +typedef struct _sysctl_dma_sel1 +{ + uint32_t dma_sel5 : 6; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))) sysctl_dma_sel1_t; + +/** + * @brief IO Power Mode Select controller + * + * No. 27 Register (0x6c) + */ +typedef struct _sysctl_power_sel +{ + uint32_t power_mode_sel0 : 1; + uint32_t power_mode_sel1 : 1; + uint32_t power_mode_sel2 : 1; + uint32_t power_mode_sel3 : 1; + uint32_t power_mode_sel4 : 1; + uint32_t power_mode_sel5 : 1; + uint32_t power_mode_sel6 : 1; + uint32_t power_mode_sel7 : 1; + uint32_t reserved : 24; +} __attribute__((packed, aligned(4))) sysctl_power_sel_t; + +/** + * @brief System controller object + * + * The System controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of all system + * related peripheral device. It contain PLL controller, clock + * controller, reset controller, DMA handshake controller, SPI + * controller, timer controller, WDT controller and sleep + * controller. + */ +typedef struct _sysctl +{ + /* No. 0 (0x00): Git short commit id */ + sysctl_git_id_t git_id; + /* No. 1 (0x04): System clock base frequency */ + sysctl_clk_freq_t clk_freq; + /* No. 2 (0x08): PLL0 controller */ + sysctl_pll0_t pll0; + /* No. 3 (0x0c): PLL1 controller */ + sysctl_pll1_t pll1; + /* No. 4 (0x10): PLL2 controller */ + sysctl_pll2_t pll2; + /* No. 5 (0x14): Reserved */ + uint32_t resv5; + /* No. 6 (0x18): PLL lock tester */ + sysctl_pll_lock_t pll_lock; + /* No. 7 (0x1c): AXI ROM detector */ + sysctl_rom_error_t rom_error; + /* No. 8 (0x20): Clock select controller0 */ + sysctl_clk_sel0_t clk_sel0; + /* No. 9 (0x24): Clock select controller1 */ + sysctl_clk_sel1_t clk_sel1; + /* No. 10 (0x28): Central clock enable */ + sysctl_clk_en_cent_t clk_en_cent; + /* No. 11 (0x2c): Peripheral clock enable */ + sysctl_clk_en_peri_t clk_en_peri; + /* No. 12 (0x30): Soft reset ctrl */ + sysctl_soft_reset_t soft_reset; + /* No. 13 (0x34): Peripheral reset controller */ + sysctl_peri_reset_t peri_reset; + /* No. 14 (0x38): Clock threshold controller 0 */ + sysctl_clk_th0_t clk_th0; + /* No. 15 (0x3c): Clock threshold controller 1 */ + sysctl_clk_th1_t clk_th1; + /* No. 16 (0x40): Clock threshold controller 2 */ + sysctl_clk_th2_t clk_th2; + /* No. 17 (0x44): Clock threshold controller 3 */ + sysctl_clk_th3_t clk_th3; + /* No. 18 (0x48): Clock threshold controller 4 */ + sysctl_clk_th4_t clk_th4; + /* No. 19 (0x4c): Clock threshold controller 5 */ + sysctl_clk_th5_t clk_th5; + /* No. 20 (0x50): Clock threshold controller 6 */ + sysctl_clk_th6_t clk_th6; + /* No. 21 (0x54): Miscellaneous controller */ + sysctl_misc_t misc; + /* No. 22 (0x58): Peripheral controller */ + sysctl_peri_t peri; + /* No. 23 (0x5c): SPI sleep controller */ + sysctl_spi_sleep_t spi_sleep; + /* No. 24 (0x60): Reset source status */ + sysctl_reset_status_t reset_status; + /* No. 25 (0x64): DMA handshake selector */ + sysctl_dma_sel0_t dma_sel0; + /* No. 26 (0x68): DMA handshake selector */ + sysctl_dma_sel1_t dma_sel1; + /* No. 27 (0x6c): IO Power Mode Select controller */ + sysctl_power_sel_t power_sel; + /* No. 28 (0x70): Reserved */ + uint32_t resv28; + /* No. 29 (0x74): Reserved */ + uint32_t resv29; + /* No. 30 (0x78): Reserved */ + uint32_t resv30; + /* No. 31 (0x7c): Reserved */ + uint32_t resv31; +} __attribute__((packed, aligned(4))) sysctl_t; + +/** + * @brief Abstruct PLL struct + */ +typedef struct _sysctl_general_pll +{ + uint32_t clkr : 4; + uint32_t clkf : 6; + uint32_t clkod : 4; + uint32_t bwadj : 6; + uint32_t pll_reset : 1; + uint32_t pll_pwrd : 1; + uint32_t pll_intfb : 1; + uint32_t pll_bypass : 1; + uint32_t pll_test : 1; + uint32_t pll_out_en : 1; + uint32_t pll_ckin_sel : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))) sysctl_general_pll_t; + +/** + * @brief System controller object instanse + */ +extern volatile sysctl_t *const sysctl; + +/** + * @brief Enable clock for peripheral + * + * @param[in] clock The clock to be enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_enable(sysctl_clock_t clock); + +/** + * @brief Enable clock for peripheral + * + * @param[in] clock The clock to be disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_disable(sysctl_clock_t clock); + +/** + * @brief Sysctl clock set threshold + * + * @param[in] which Which threshold to set + * @param[in] threshold The threshold value + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_set_threshold(sysctl_threshold_t which, int threshold); + +/** + * @brief Sysctl clock get threshold + * + * @param[in] which Which threshold to get + * + * @return The threshold value + * - Other Value of threshold + * - -1 Fail + */ +int sysctl_clock_get_threshold(sysctl_threshold_t which); + +/** + * @brief Sysctl clock set clock select + * + * @param[in] which Which clock select to set + * @param[in] select The clock select value + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_set_clock_select(sysctl_clock_select_t which, int select); + +/** + * @brief Sysctl clock get clock select + * + * @param[in] which Which clock select to get + * + * @return The clock select value + * - Other Value of clock select + * - -1 Fail + */ +int sysctl_clock_get_clock_select(sysctl_clock_select_t which); + +/** + * @brief Get PLL frequency + * + * @param[in] pll The PLL id + * + * @return The frequency of PLL + */ +uint32_t sysctl_pll_get_freq(sysctl_pll_t pll); + +/** + * @brief Get base clock frequency by clock id + * + * @param[in] clock The clock id + * + * @return The clock frequency + */ +uint32_t SysctlClockGetFreq(sysctl_clock_t clock); + +/** + * @brief Reset device by reset controller + * + * @param[in] reset The reset signal + */ +void sysctl_reset(sysctl_reset_t reset); + +/** + * @brief Enable the PLL and power on with reset + * + * @param[in] pll The pll id + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_pll_enable(sysctl_pll_t pll); + +/** + * @brief Disable the PLL and power off + * + * @param[in] pll The pll id + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_pll_disable(sysctl_pll_t pll); + +/** + * @brief Select DMA channel handshake peripheral signal + * + * @param[in] channel The DMA channel + * @param[in] select The peripheral select + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_dma_select(sysctl_dma_channel_t channel, sysctl_dma_select_t select); + +/** + * @brief Set SPI0_D0-D7 DVP_D0-D7 as spi and dvp data pin + * + * @param[in] en Enable or not + * + * @return Result + * - 0 Success + * - Other Fail + */ +uint32_t sysctl_set_spi0_dvp_data(uint8_t en); + +/** + * @brief Set io power mode + * + * @param[in] power_bank IO power bank + * @param[in] io_power_mode Set power mode 3.3v or 1.8 + * + * @return Result + * - 0 Success + * - Other Fail + */ +void sysctl_set_power_mode(sysctl_power_bank_t power_bank, sysctl_io_power_mode_t io_power_mode); + +/** + * @brief get the frequency of CPU + * + * @return The frequency of CPU + */ +uint32_t sysctl_cpu_get_freq(void); + +/** + * @brief Set frequency of CPU + * @param[in] freq The desired frequency in Hz + * + * @return The actual frequency of CPU after set + */ +uint32_t sysctl_cpu_set_freq(uint32_t freq); + +/** + * @brief Init PLL freqency + * @param[in] pll The PLL id + * @param[in] pll_freq The desired frequency in Hz + + */ +uint32_t SysctlPllSetFreq(sysctl_pll_t pll, uint32_t pll_freq); + +/** + * @brief Enable interrupt + */ +void sysctl_enable_irq(void); + +/** + * @brief Disable interrupt + */ +void sysctl_disable_irq(void); + +/** + * @brief Get the time start up to now + * + * @return The time of microsecond + */ +uint64_t sysctl_get_time_us(void); + +/** + * @brief Get reset status + * + * @return The status of reset + */ +sysctl_reset_enum_status_t sysctl_get_reset_status(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSCTL_H__ */ diff --git a/board/k210-emulator/third_party_driver/include/utils.h b/board/k210-emulator/third_party_driver/include/utils.h new file mode 100644 index 00000000..a8d2f8dc --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/utils.h @@ -0,0 +1,357 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 utils.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __UTILS_H__ +#define __UTILS_H__ + +#ifdef __cplusplus +#include +#include +#include +#else /* __cplusplus */ +#include +#include +#include +#include +#endif /* __cplusplus */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define KENDRYTE_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define KENDRYTE_MAX(a, b) ((a) > (b) ? (a) : (b)) + +#ifdef __ASSEMBLY__ +#define KENDRYTE_CAST(type, ptr) ptr +#else /* __ASSEMBLY__ */ +/** + * @brief Cast the pointer to specified pointer type. + * + * @param[in] type The pointer type to cast to + * @param[in] ptr The pointer to apply the type cast to + */ +#define KENDRYTE_CAST(type, ptr) ((type)(ptr)) +#endif /* __ASSEMBLY__ */ + +/** + * @addtogroup UTIL_RW_FUNC Memory Read/Write Utilities + * + * This section implements read and write functionality for various + * memory untis. The memory unit terms used for these functions are + * consistent with those used in the ARM Architecture Reference Manual + * ARMv7-A and ARMv7-R edition manual. The terms used for units of memory are: + * + * Unit of Memory | Abbreviation | Size in Bits + * :---------------|:-------------|:------------: + * Byte | byte | 8 + * Half Word | hword | 16 + * Word | word | 32 + * Double Word | dword | 64 + * + */ + +/** + * @brief Write the 8 bit byte to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 8 bit data byte to write to memory + */ +#define kendryte_write_byte(dest, src) \ + (*KENDRYTE_CAST(volatile uint8_t*, (dest)) = (src)) + +/** + * @brief Read and return the 8 bit byte from the source address in device memory. + * + * @param[in] src Read source pointer address + * + * @return 8 bit data byte value + */ +#define kendryte_read_byte(src) (*KENDRYTE_CAST(volatile uint8_t*, (src))) + +/** + * @brief Write the 16 bit half word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 16 bit data half word to write to memory + */ +#define kendryte_write_hword(dest, src) \ + (*KENDRYTE_CAST(volatile uint16_t*, (dest)) = (src)) + +/** + * @brief Read and return the 16 bit half word from the source address in device + * + * @param[in] src Read source pointer address + * + * @return 16 bit data half word value + */ +#define kendryte_read_hword(src) (*KENDRYTE_CAST(volatile uint16_t*, (src))) + +/** + * @brief Write the 32 bit word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 32 bit data word to write to memory + */ +#define kendryte_write_word(dest, src) \ + (*KENDRYTE_CAST(volatile uint32_t*, (dest)) = (src)) + +/** + * @brief Read and return the 32 bit word from the source address in device memory. + * + * @param[in] src Read source pointer address + * + * @return 32 bit data half word value + */ +#define kendryte_read_word(src) (*KENDRYTE_CAST(volatile uint32_t*, (src))) + +/** + * @brief Write the 64 bit double word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 64 bit data word to write to memory + */ +#define kendryte_write_dword(dest, src) \ + (*KENDRYTE_CAST(volatile uint64_t*, (dest)) = (src)) + +/** + * @brief Read and return the 64 bit double word from the source address in device + * + * @param[in] src Read source pointer address + * + * @return 64 bit data half word value + */ +#define kendryte_read_dword(src) (*KENDRYTE_CAST(volatile uint64_t*, (src))) + +/** + * @brief Set selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination byte + */ +#define kendryte_setbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) | (bits))) + +/** + * @brief Clear selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination byte + */ +#define kendryte_clrbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 8 bit byte at the destination address + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination byte + */ +#define kendryte_xorbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination byte + * @param[in] src Source bits to write to cleared bits in destination byte + */ +#define kendryte_replbits_byte(dest, msk, src) \ + (kendryte_write_byte(dest, (kendryte_read_byte(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination halfword + */ +#define kendryte_setbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) | (bits))) + +/** + * @brief Clear selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination halfword + */ +#define kendryte_clrbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 16 bit halfword at the destination + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination halfword + */ +#define kendryte_xorbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination byte + * @param[in] src Source bits to write to cleared bits in destination halfword + */ +#define kendryte_replbits_hword(dest, msk, src) \ + (kendryte_write_hword(dest, (kendryte_read_hword(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 32 bit word at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination word + */ +#define kendryte_setbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) | (bits))) + +/** + * @brief Clear selected bits in the 32 bit word at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination word + */ +#define kendryte_clrbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 32 bit word at the destination address + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination word + */ +#define kendryte_xorbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 32 bit word at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination word + * @param[in] src Source bits to write to cleared bits in destination word + */ +#define kendryte_replbits_word(dest, msk, src) \ + (kendryte_write_word(dest, (kendryte_read_word(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination doubleword + */ +#define kendryte_setbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) | (bits))) + +/** + * @brief Clear selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination doubleword + */ +#define kendryte_clrbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 64 bit doubleword at the destination + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination doubleword + */ +#define kendryte_xorbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk its to replace in destination doubleword + * @param[in] src Source bits to write to cleared bits in destination word + */ +#define kendryte_replbits_dword(dest, msk, src) \ + (kendryte_write_dword(dest, (kendryte_read_dword(dest) & ~(msk)) | ((src) & (msk)))) + +#define configASSERT(x) \ + if ((x) == 0) \ + { \ + printf("(%s:%d) %s\r\n", __FILE__, __LINE__, #x); \ + for (;;) \ + ; \ + } + +/** + * @brief Set value by mask + * + * @param[in] bits The one be set + * @param[in] mask mask value + * @param[in] value The value to set + */ +void set_bit(volatile uint32_t *bits, uint32_t mask, uint32_t value); + +/** + * @brief Set value by mask + * + * @param[in] bits The one be set + * @param[in] mask Mask value + * @param[in] offset Mask's offset + * @param[in] value The value to set + */ +void set_bit_offset(volatile uint32_t *bits, uint32_t mask, size_t offset, uint32_t value); + +/** + * @brief Set bit for gpio, only set one bit + * + * @param[in] bits The one be set + * @param[in] idx Offset value + * @param[in] value The value to set + */ +void set_gpio_bit(volatile uint32_t *bits, size_t idx, uint32_t value); + +/** + * @brief Get bits value of mask + * + * @param[in] bits The source data + * @param[in] mask Mask value + * @param[in] offset Mask's offset + * + * @return The bits value of mask + */ +uint32_t get_bit(volatile uint32_t *bits, uint32_t mask, size_t offset); + +/** + * @brief Get a bit value by offset + * + * @param[in] bits The source data + * @param[in] offset Bit's offset + * + * + * @return The bit value + */ +uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _DRIVER_COMMON_H */ + diff --git a/board/k210-emulator/third_party_driver/include/wdt.h b/board/k210-emulator/third_party_driver/include/wdt.h new file mode 100644 index 00000000..cd7fc49e --- /dev/null +++ b/board/k210-emulator/third_party_driver/include/wdt.h @@ -0,0 +1,180 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 wdt.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __WDT_H__ +#define __WDT_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _wdt +{ + /* WDT Control Register (0x00) */ + volatile uint32_t cr; + /* WDT Timeout Range Register (0x04) */ + volatile uint32_t torr; + /* WDT Current Counter Value Register (0x08) */ + volatile uint32_t ccvr; + /* WDT Counter Restart Register (0x0c) */ + volatile uint32_t crr; + /* WDT Interrupt Status Register (0x10) */ + volatile uint32_t stat; + /* WDT Interrupt Clear Register (0x14) */ + volatile uint32_t eoi; + /* reserverd (0x18) */ + volatile uint32_t resv1; + /* WDT Protection level Register (0x1c) */ + volatile uint32_t prot_level; + /* reserved (0x20-0xe0) */ + volatile uint32_t resv4[49]; + /* WDT Component Parameters Register 5 (0xe4) */ + volatile uint32_t comp_param_5; + /* WDT Component Parameters Register 4 (0xe8) */ + volatile uint32_t comp_param_4; + /* WDT Component Parameters Register 3 (0xec) */ + volatile uint32_t comp_param_3; + /* WDT Component Parameters Register 2 (0xf0) */ + volatile uint32_t comp_param_2; + /* WDT Component Parameters Register 1 (0xf4) */ + volatile uint32_t comp_param_1; + /* WDT Component Version Register (0xf8) */ + volatile uint32_t comp_version; + /* WDT Component Type Register (0xfc) */ + volatile uint32_t comp_type; +} __attribute__((packed, aligned(4))) wdt_t; + +typedef enum _wdt_device_number +{ + WDT_DEVICE_0, + WDT_DEVICE_1, + WDT_DEVICE_MAX, +} wdt_device_number_t; + + +#define WDT_RESET_ALL 0x00000000U +#define WDT_RESET_CPU 0x00000001U + +/* WDT Control Register */ +#define WDT_CR_ENABLE 0x00000001U +#define WDT_CR_RMOD_MASK 0x00000002U +#define WDT_CR_RMOD_RESET 0x00000000U +#define WDT_CR_RMOD_INTERRUPT 0x00000002U +#define WDT_CR_RPL_MASK 0x0000001CU +#define WDT_CR_RPL(x) ((x) << 2) +/* WDT Timeout Range Register */ +#define WDT_TORR_TOP_MASK 0x000000FFU +#define WDT_TORR_TOP(x) ((x) << 4 | (x) << 0) +/* WDT Current Counter Value Register */ +#define WDT_CCVR_MASK 0xFFFFFFFFU +/* WDT Counter Restart Register */ +#define WDT_CRR_MASK 0x00000076U +/* WDT Interrupt Status Register */ +#define WDT_STAT_MASK 0x00000001U +/* WDT Interrupt Clear Register */ +#define WDT_EOI_MASK 0x00000001U +/* WDT Protection level Register */ +#define WDT_PROT_LEVEL_MASK 0x00000007U +/* WDT Component Parameter Register 5 */ +#define WDT_COMP_PARAM_5_CP_WDT_USER_TOP_MAX_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 4 */ +#define WDT_COMP_PARAM_4_CP_WDT_USER_TOP_INIT_MAX_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 3 */ +#define WDT_COMP_PARAM_3_CD_WDT_TOP_RST_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 2 */ +#define WDT_COMP_PARAM_3_CP_WDT_CNT_RST_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 1 */ +#define WDT_COMP_PARAM_1_WDT_ALWAYS_EN_MASK 0x00000001U +#define WDT_COMP_PARAM_1_WDT_DFLT_RMOD_MASK 0x00000002U +#define WDT_COMP_PARAM_1_WDT_DUAL_TOP_MASK 0x00000004U +#define WDT_COMP_PARAM_1_WDT_HC_RMOD_MASK 0x00000008U +#define WDT_COMP_PARAM_1_WDT_HC_RPL_MASK 0x00000010U +#define WDT_COMP_PARAM_1_WDT_HC_TOP_MASK 0x00000020U +#define WDT_COMP_PARAM_1_WDT_USE_FIX_TOP_MASK 0x00000040U +#define WDT_COMP_PARAM_1_WDT_PAUSE_MASK 0x00000080U +#define WDT_COMP_PARAM_1_APB_DATA_WIDTH_MASK 0x00000300U +#define WDT_COMP_PARAM_1_WDT_DFLT_RPL_MASK 0x00001C00U +#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_MASK 0x000F0000U +#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_INIT_MASK 0x00F00000U +#define WDT_COMP_PARAM_1_WDT_CNT_WIDTH_MASK 0x1F000000U +/* WDT Component Version Register */ +#define WDT_COMP_VERSION_MASK 0xFFFFFFFFU +/* WDT Component Type Register */ +#define WDT_COMP_TYPE_MASK 0xFFFFFFFFU +/* clang-format on */ + +/** + * @brief Feed wdt + */ +void wdt_feed(wdt_device_number_t id); + +/** + * @brief Start wdt + * + * @param[in] id Wdt id 0 or 1 + * @param[in] time_out_ms Wdt trigger time + * @param[in] on_irq Wdt interrupt callback + * + */ +void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq); + +/** + * @brief Start wdt + * + * @param[in] id Wdt id 0 or 1 + * @param[in] time_out_ms Wdt trigger time + * @param[in] on_irq Wdt interrupt callback + * @param[in] ctx Param of callback + * + * @return Wdt time + * + */ +uint32_t wdt_init(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq, void *ctx); + +/** + * @brief Stop wdt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_stop(wdt_device_number_t id); + +/** + * @brief Clear wdt interrupt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_clear_interrupt(wdt_device_number_t id); + +#ifdef __cplusplus +} +#endif + +#endif /* __WDT_H__ */ diff --git a/board/k210-emulator/third_party_driver/plic/Kconfig b/board/k210-emulator/third_party_driver/plic/Kconfig new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/board/k210-emulator/third_party_driver/plic/Kconfig @@ -0,0 +1 @@ + diff --git a/board/k210-emulator/third_party_driver/plic/Makefile b/board/k210-emulator/third_party_driver/plic/Makefile new file mode 100644 index 00000000..b72b2085 --- /dev/null +++ b/board/k210-emulator/third_party_driver/plic/Makefile @@ -0,0 +1,5 @@ +SRC_FILES := drv_interrupt.c plic.c clint.c + + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/plic/clint.c b/board/k210-emulator/third_party_driver/plic/clint.c new file mode 100644 index 00000000..cdd4fd75 --- /dev/null +++ b/board/k210-emulator/third_party_driver/plic/clint.c @@ -0,0 +1,229 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 clint.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include "encoding.h" +#include "clint.h" +#include "sysctl.h" + +volatile clint_t* const clint = (volatile clint_t*)CLINT_BASE_ADDR; +static clint_timer_instance_t clint_timer_instance[CLINT_NUM_CORES]; +static clint_ipi_instance_t clint_ipi_instance[CLINT_NUM_CORES]; + +uint64_t clint_get_time(void) +{ + /* No difference on cores */ + return clint->mtime; +} + +int clint_timer_init(void) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Clear the Machine-Timer bit in MIE */ + CLEAR_CSR(mie, MIP_MTIP); + /* Fill core's instance with original data */ + + /* clang-format off */ + clint_timer_instance[core_id] = (const clint_timer_instance_t) + { + .interval = 0, + .cycles = 0, + .single_shot = 0, + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + + return 0; +} + +int clint_timer_stop(void) +{ + /* Clear the Machine-Timer bit in MIE */ + CLEAR_CSR(mie, MIP_MTIP); + return 0; +} + +uint64_t clint_timer_get_freq(void) +{ + /* The clock is divided by CLINT_CLOCK_DIV */ + return SysctlClockGetFreq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV; +} + +int clint_timer_start(uint64_t interval, int single_shot) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set timer interval */ + if (clint_timer_set_interval(interval) != 0) + return -1; + /* Set timer single shot */ + if (clint_timer_set_single_shot(single_shot) != 0) + return -1; + /* Check settings to prevent interval is 0 */ + if (clint_timer_instance[core_id].interval == 0) + return -1; + /* Check settings to prevent cycles is 0 */ + if (clint_timer_instance[core_id].cycles == 0) + return -1; + /* Add cycle interval to mtimecmp */ + uint64_t now = clint->mtime; + uint64_t then = now + clint_timer_instance[core_id].cycles; + /* Set mtimecmp by core id */ + clint->mtimecmp[core_id] = then; + /* Enable interrupts in general */ + SET_CSR(mstatus, MSTATUS_MIE); + /* Enable the Machine-Timer bit in MIE */ + SET_CSR(mie, MIP_MTIP); + return 0; +} + +uint64_t clint_timer_get_interval(void) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + return clint_timer_instance[core_id].interval; +} + +int clint_timer_set_interval(uint64_t interval) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Check parameter */ + if (interval == 0) + return -1; + + /* Assign user interval with Millisecond(ms) */ + clint_timer_instance[core_id].interval = interval; + /* Convert interval to cycles */ + clint_timer_instance[core_id].cycles = interval * clint_timer_get_freq() / 1000ULL; + return 0; +} + +int clint_timer_get_single_shot(void) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Get single shot mode by core id */ + return clint_timer_instance[core_id].single_shot; +} + +int clint_timer_set_single_shot(int single_shot) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set single shot mode by core id */ + clint_timer_instance[core_id].single_shot = single_shot; + return 0; +} + +int clint_timer_register(clint_timer_callback_t callback, void *ctx) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set user callback function */ + clint_timer_instance[core_id].callback = callback; + /* Assign user context */ + clint_timer_instance[core_id].ctx = ctx; + return 0; +} + +int clint_timer_unregister(void) +{ + /* Just assign NULL to user callback function and context */ + return clint_timer_register(NULL, NULL); +} + +int clint_ipi_init(void) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Clear the Machine-Software bit in MIE */ + CLEAR_CSR(mie, MIP_MSIP); + /* Fill core's instance with original data */ + /* clang-format off */ + clint_ipi_instance[core_id] = (const clint_ipi_instance_t){ + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + + return 0; +} + +int clint_ipi_enable(void) +{ + /* Enable interrupts in general */ + SET_CSR(mstatus, MSTATUS_MIE); + /* Set the Machine-Software bit in MIE */ + SET_CSR(mie, MIP_MSIP); + return 0; +} + +int clint_ipi_disable(void) +{ + /* Clear the Machine-Software bit in MIE */ + CLEAR_CSR(mie, MIP_MSIP); + return 0; +} + +int clint_ipi_send(size_t core_id) +{ + if (core_id >= CLINT_NUM_CORES) + return -1; + clint->msip[core_id].msip = 1; + return 0; +} + +int clint_ipi_clear(size_t core_id) +{ + if (core_id >= CLINT_NUM_CORES) + return -1; + if (clint->msip[core_id].msip) + { + clint->msip[core_id].msip = 0; + return 1; + } + return 0; +} + +int clint_ipi_register(clint_ipi_callback_t callback, void *ctx) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set user callback function */ + clint_ipi_instance[core_id].callback = callback; + /* Assign user context */ + clint_ipi_instance[core_id].ctx = ctx; + return 0; +} + +int clint_ipi_unregister(void) +{ + /* Just assign NULL to user callback function and context */ + return clint_ipi_register(NULL, NULL); +} + diff --git a/board/k210-emulator/third_party_driver/plic/drv_interrupt.c b/board/k210-emulator/third_party_driver/plic/drv_interrupt.c new file mode 100644 index 00000000..36ef6fd3 --- /dev/null +++ b/board/k210-emulator/third_party_driver/plic/drv_interrupt.c @@ -0,0 +1,41 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 drv_interrupt.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include + +void PlicIrqHandle(plic_irq_t irq) +{ + plic_instance_t (*plic_instance)[IRQN_MAX] = plic_get_instance(); + if (plic_instance[0][irq].callback) + { + plic_instance[0][irq].callback( + plic_instance[0][irq].ctx); + } + else if (plic_instance[1][irq].callback) + { + plic_instance[1][irq].callback( + plic_instance[1][irq].ctx); + } +} + diff --git a/board/k210-emulator/third_party_driver/plic/plic.c b/board/k210-emulator/third_party_driver/plic/plic.c new file mode 100644 index 00000000..19503026 --- /dev/null +++ b/board/k210-emulator/third_party_driver/plic/plic.c @@ -0,0 +1,219 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 plic.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include "encoding.h" +#include "plic.h" +#include "syscalls.h" +#include "syslog.h" + +volatile plic_t* const plic = (volatile plic_t*)PLIC_BASE_ADDR; + +static plic_instance_t plic_instance[PLIC_NUM_CORES][IRQN_MAX]; + +void plic_init(void) +{ + int i = 0; + + /* Get current core id */ + unsigned long core_id = current_coreid(); + + /* Disable all interrupts for the current core. */ + for (i = 0; i < ((PLIC_NUM_SOURCES + 32u) / 32u); i++) + plic->target_enables.target[core_id].enable[i] = 0; + + static uint8_t s_plic_priorities_init_flag = 0; + /* Set priorities to zero. */ + if(s_plic_priorities_init_flag == 0) + { + for (i = 0; i < PLIC_NUM_SOURCES; i++) + plic->source_priorities.priority[i] = 0; + s_plic_priorities_init_flag = 1; + } + + /* Set the threshold to zero. */ + plic->targets.target[core_id].priority_threshold = 0; + + /* Clear PLIC instance for every cores */ + for (i = 0; i < IRQN_MAX; i++) + { + /* clang-format off */ + plic_instance[core_id][i] = (const plic_instance_t){ + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + } + + /* + * A successful claim will also atomically clear the corresponding + * pending bit on the interrupt source. A target can perform a claim + * at any time, even if the EIP is not set. + */ + i = 0; + while (plic->targets.target[core_id].claim_complete > 0 && i < 100) + { + /* This loop will clear pending bit on the interrupt source */ + i++; + } + + /* Enable machine external interrupts. */ + SET_CSR(mie, MIP_MEIP); +} + +int plic_irq_enable(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + unsigned long core_id = current_coreid(); + /* Get current enable bit array by IRQ number */ + uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32]; + /* Set enable bit in enable bit array */ + current |= (uint32_t)1 << (irq_number % 32); + /* Write back the enable bit array */ + plic->target_enables.target[core_id].enable[irq_number / 32] = current; + return 0; +} + +int plic_irq_disable(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + unsigned long core_id = current_coreid(); + /* Get current enable bit array by IRQ number */ + uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32]; + /* Clear enable bit in enable bit array */ + current &= ~((uint32_t)1 << (irq_number % 32)); + /* Write back the enable bit array */ + plic->target_enables.target[core_id].enable[irq_number / 32] = current; + return 0; +} + +int plic_set_priority(plic_irq_t irq_number, uint32_t priority) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + /* Set interrupt priority by IRQ number */ + plic->source_priorities.priority[irq_number] = priority; + return 0; +} + +uint32_t plic_get_priority(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return 0; + /* Get interrupt priority by IRQ number */ + return plic->source_priorities.priority[irq_number]; +} + +uint32_t plic_irq_claim(void) +{ + unsigned long core_id = current_coreid(); + /* Perform IRQ claim */ + return plic->targets.target[core_id].claim_complete; +} + +int plic_irq_complete(uint32_t source) +{ + unsigned long core_id = current_coreid(); + /* Perform IRQ complete */ + plic->targets.target[core_id].claim_complete = source; + return 0; +} + +void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set user callback function */ + plic_instance[core_id][irq].callback = callback; + /* Assign user context */ + plic_instance[core_id][irq].ctx = ctx; +} + +void plic_irq_unregister(plic_irq_t irq) +{ + /* Just assign NULL to user callback function and context */ + plic_irq_register(irq, NULL, NULL); +} + +void __attribute__((weak, alias("plic_irq_unregister"))) plic_irq_deregister(plic_irq_t irq); + +plic_instance_t (*plic_get_instance(void))[IRQN_MAX] +{ + return plic_instance; +} + +/*Entry Point for PLIC Interrupt Handler*/ +uintptr_t __attribute__((weak)) +HandleIrqMExt(uintptr_t cause, uintptr_t epc) +{ + /* + * After the highest-priority pending interrupt is claimed by a target + * and the corresponding IP bit is cleared, other lower-priority + * pending interrupts might then become visible to the target, and so + * the PLIC EIP bit might not be cleared after a claim. The interrupt + * handler can check the local meip/heip/seip/ueip bits before exiting + * the handler, to allow more efficient service of other interrupts + * without first restoring the interrupted context and taking another + * interrupt trap. + */ + if (READ_CSR(mip) & MIP_MEIP) + { + /* Get current core id */ + uint64_t core_id = current_coreid(); + /* Get primitive interrupt enable flag */ + uint64_t ie_flag = READ_CSR(mie); + /* Get current IRQ num */ + uint32_t int_num = plic->targets.target[core_id].claim_complete; + /* Get primitive IRQ threshold */ + uint32_t int_threshold = plic->targets.target[core_id].priority_threshold; + /* Set new IRQ threshold = current IRQ threshold */ + plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num]; + /* Disable software interrupt and timer interrupt */ + CLEAR_CSR(mie, MIP_MTIP | MIP_MSIP); + /* Enable global interrupt */ + SET_CSR(mstatus, MSTATUS_MIE); + if (plic_instance[core_id][int_num].callback) + plic_instance[core_id][int_num].callback( + plic_instance[core_id][int_num].ctx); + /* Perform IRQ complete */ + plic->targets.target[core_id].claim_complete = int_num; + /* Disable global interrupt */ + CLEAR_CSR(mstatus, MSTATUS_MIE); + /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */ + SET_CSR(mstatus, MSTATUS_MPIE | MSTATUS_MPP); + /* Restore primitive interrupt enable flag */ + WRITE_CSR(mie, ie_flag); + /* Restore primitive IRQ threshold */ + plic->targets.target[core_id].priority_threshold = int_threshold; + } + + return epc; +} diff --git a/board/k210-emulator/third_party_driver/rtc/Kconfig b/board/k210-emulator/third_party_driver/rtc/Kconfig new file mode 100644 index 00000000..e853dd40 --- /dev/null +++ b/board/k210-emulator/third_party_driver/rtc/Kconfig @@ -0,0 +1,11 @@ +if BSP_USING_RTC + config RTC_BUS_NAME + string "rtc bus name" + default "rtc" + config RTC_DRV_NAME + string "rtc bus driver name" + default "rtc_drv" + config RTC_DEVICE_NAME + string "rtc bus device name" + default "rtc_dev" +endif diff --git a/board/k210-emulator/third_party_driver/rtc/Makefile b/board/k210-emulator/third_party_driver/rtc/Makefile new file mode 100644 index 00000000..23575e62 --- /dev/null +++ b/board/k210-emulator/third_party_driver/rtc/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := connect_rtc.c hardware_rtc.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/rtc/connect_rtc.c b/board/k210-emulator/third_party_driver/rtc/connect_rtc.c new file mode 100644 index 00000000..36721c7a --- /dev/null +++ b/board/k210-emulator/third_party_driver/rtc/connect_rtc.c @@ -0,0 +1,184 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_rtc.c +* @brief support kd233-board rtc function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include "sysctl.h" +#include "connect_rtc.h" +#include "hardware_rtc.h" + +static int GetWeekDay(int year, int month, int day) +{ + /* Magic method to get weekday */ + int weekday = (day += month < 3 ? year-- : year - 2, + 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7; + return weekday; +} + +static uint32 RtcConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + + struct RtcDriver *rtc_drv = (struct RtcDriver *)drv; + struct RtcDrvConfigureParam *drv_param = (struct RtcDrvConfigureParam *)configure_info->private_data; + + int cmd = drv_param->rtc_operation_cmd; + time_t *time = drv_param->time; + + switch (cmd) + { + case OPER_RTC_GET_TIME: + { + struct tm ct; + int year,month,day,hour,minute,second; + memset(&ct,0,sizeof(struct tm)); + + rtc_timer_get(&year, &month, &day, &hour, &minute, &second); + + ct.tm_year = year - 1900; + ct.tm_mon = month - 1; + ct.tm_mday = day; + ct.tm_wday = GetWeekDay(year, month, day); + + ct.tm_hour = hour; + ct.tm_min = minute; + ct.tm_sec = second; + + *time = mktime(&ct); + } + break; + case OPER_RTC_SET_TIME: + { + struct tm *ct; + struct tm tm_new; + x_base lock; + + lock = CriticalAreaLock(); + ct = localtime(time); + memcpy(&tm_new, ct, sizeof(struct tm)); + CriticalAreaUnLock(lock); + + sysctl_reset(SYSCTL_RESET_RTC); + sysctl_clock_enable(SYSCTL_CLOCK_RTC); + rtc_protect_set(0); + rtc_timer_set_clock_frequency(SysctlClockGetFreq(SYSCTL_CLOCK_IN0)); + rtc_timer_set_clock_count_value(1); + rtc_timer_set_mode(RTC_TIMER_RUNNING); + + if (rtc_timer_set(tm_new.tm_year+1900,tm_new.tm_mon+1,tm_new.tm_mday, + tm_new.tm_hour,tm_new.tm_min,tm_new.tm_sec)==-1) + return ERROR; + } + break; + } + return EOK; +} + +/*manage the rtc device operations*/ +static const struct RtcDevDone dev_done = +{ + .open = NONE, + .close = NONE, + .write = NONE, + .read = NONE, +}; + +static int BoardRtcBusInit(struct RtcBus *rtc_bus, struct RtcDriver *rtc_driver) +{ + x_err_t ret = EOK; + + /*Init the rtc bus */ + ret = RtcBusInit(rtc_bus, RTC_BUS_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcBusInit error %d\n", ret); + return ERROR; + } + + /*Init the rtc driver*/ + ret = RtcDriverInit(rtc_driver, RTC_DRV_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the rtc driver to the rtc bus*/ + ret = RtcDriverAttachToBus(RTC_DRV_NAME, RTC_BUS_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the rtc device to the rtc bus*/ +static int BoardRtcDevBend(void) +{ + x_err_t ret = EOK; + + static struct RtcHardwareDevice rtc_device; + memset(&rtc_device, 0, sizeof(struct RtcHardwareDevice)); + + rtc_device.dev_done = &(dev_done); + + ret = RtcDeviceRegister(&rtc_device, NONE, RTC_DEVICE_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcDeviceInit device %s error %d\n", RTC_DEVICE_NAME, ret); + return ERROR; + } + + ret = RtcDeviceAttachToBus(RTC_DEVICE_NAME, RTC_BUS_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcDeviceAttachToBus device %s error %d\n", RTC_DEVICE_NAME, ret); + return ERROR; + } + + return ret; +} + +int HwRtcInit(void) +{ + x_err_t ret = EOK; + + static struct RtcBus rtc_bus; + memset(&rtc_bus, 0, sizeof(struct RtcBus)); + + static struct RtcDriver rtc_driver; + memset(&rtc_driver, 0, sizeof(struct RtcDriver)); + + rtc_driver.configure = &(RtcConfigure); + + ret = BoardRtcBusInit(&rtc_bus, &rtc_driver); + if (EOK != ret) { + KPrintf("HwRtcInit error ret %u\n", ret); + return ERROR; + } + + ret = BoardRtcDevBend(); + if (EOK != ret) { + KPrintf("HwRtcInit error ret %u\n", ret); + return ERROR; + } + + rtc_init(); + + return ret; +} diff --git a/board/k210-emulator/third_party_driver/rtc/hardware_rtc.c b/board/k210-emulator/third_party_driver/rtc/hardware_rtc.c new file mode 100644 index 00000000..3bdb558c --- /dev/null +++ b/board/k210-emulator/third_party_driver/rtc/hardware_rtc.c @@ -0,0 +1,597 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_rtc.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include "encoding.h" +#include "sysctl.h" +#include "hardware_rtc.h" + +volatile rtc_t *const rtc = (volatile rtc_t *)RTC_BASE_ADDR; + +struct tm rtc_date_time; + +void rtc_timer_set_mode(rtc_timer_mode_t timer_mode) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + + switch (timer_mode) + { + case RTC_TIMER_PAUSE: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 0; + break; + case RTC_TIMER_RUNNING: + register_ctrl.read_enable = 1; + register_ctrl.write_enable = 0; + break; + case RTC_TIMER_SETTING: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 1; + break; + default: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 0; + break; + } + rtc->register_ctrl = register_ctrl; +} + +rtc_timer_mode_t rtc_timer_get_mode(void) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + rtc_timer_mode_t timer_mode = RTC_TIMER_PAUSE; + + if ((!register_ctrl.read_enable) && (!register_ctrl.write_enable)) + { + /* RTC_TIMER_PAUSE */ + timer_mode = RTC_TIMER_PAUSE; + } + else if ((register_ctrl.read_enable) && (!register_ctrl.write_enable)) + { + /* RTC_TIMER_RUNNING */ + timer_mode = RTC_TIMER_RUNNING; + } + else if ((!register_ctrl.read_enable) && (register_ctrl.write_enable)) { + /* RTC_TIMER_SETTING */ + timer_mode = RTC_TIMER_SETTING; + } + else + { + /* Something is error, reset timer mode */ + rtc_timer_set_mode(timer_mode); + } + + return timer_mode; +} + +static inline int rtc_in_range(int value, int min, int max) +{ + return ((value >= min) && (value <= max)); +} + +int rtc_timer_set_tm(const struct tm *tm) +{ + rtc_date_t timer_date; + rtc_time_t timer_time; + rtc_extended_t timer_extended; + + if (tm) + { + /* + * Range of tm->tm_sec could be [0,61] + * + * Range of tm->tm_sec allows for a positive leap second. Two + * leap seconds in the same minute are not allowed (the C90 + * range 0..61 was a defect) + */ + if (rtc_in_range(tm->tm_sec, 0, 59)) + timer_time.second = tm->tm_sec; + else + return -1; + + /* Range of tm->tm_min could be [0,59] */ + if (rtc_in_range(tm->tm_min, 0, 59)) + timer_time.minute = tm->tm_min; + else + return -1; + + /* Range of tm->tm_hour could be [0, 23] */ + if (rtc_in_range(tm->tm_hour, 0, 23)) + timer_time.hour = tm->tm_hour; + else + return -1; + + /* Range of tm->tm_mday could be [1, 31] */ + if (rtc_in_range(tm->tm_mday, 1, 31)) + timer_date.day = tm->tm_mday; + else + return -1; + + /* + * Range of tm->tm_mon could be [0, 11] + * But in this RTC, date.month should be [1, 12] + */ + if (rtc_in_range(tm->tm_mon, 0, 11)) + timer_date.month = tm->tm_mon + 1; + else + return -1; + + /* + * Range of tm->tm_year is the years since 1900 + * But in this RTC, year is split into year and century + * In this RTC, century range is [0,31], year range is [0,99] + */ + int human_year = tm->tm_year + 1900; + int rtc_year = human_year % 100; + int rtc_century = human_year / 100; + + if (rtc_in_range(rtc_year, 0, 99) && + rtc_in_range(rtc_century, 0, 31)) + { + timer_date.year = rtc_year; + timer_extended.century = rtc_century; + } + else + return -1; + + /* Range of tm->tm_wday could be [0, 6] */ + if (rtc_in_range(tm->tm_wday, 0, 6)) + timer_date.week = tm->tm_wday; + else + return -1; + + /* Set RTC mode to timer setting mode */ + rtc_timer_set_mode(RTC_TIMER_SETTING); + /* Write value to RTC */ + rtc->date = timer_date; + rtc->time = timer_time; + rtc->extended = timer_extended; + /* Get CPU current freq */ + unsigned long freq = SysctlClockGetFreq(SYSCTL_CLOCK_CPU); + /* Set threshold to 1/26000000 s */ + freq = freq / 26000000; + /* Get current CPU cycle */ + unsigned long start_cycle = read_cycle(); + /* Wait for 1/26000000 s to sync data */ + while (read_cycle() - start_cycle < freq) + continue; + /* Set RTC mode to timer running mode */ + rtc_timer_set_mode(RTC_TIMER_RUNNING); + } + + return 0; +} + +int rtc_timer_set_alarm_tm(const struct tm *tm) +{ + rtc_alarm_date_t alarm_date; + rtc_alarm_time_t alarm_time; + + if (tm) { + /* + * Range of tm->tm_sec could be [0,61] + * + * Range of tm->tm_sec allows for a positive leap second. Two + * leap seconds in the same minute are not allowed (the C90 + * range 0..61 was a defect) + */ + if (rtc_in_range(tm->tm_sec, 0, 59)) + alarm_time.second = tm->tm_sec; + else + return -1; + + /* Range of tm->tm_min could be [0,59] */ + if (rtc_in_range(tm->tm_min, 0, 59)) + alarm_time.minute = tm->tm_min; + else + return -1; + + /* Range of tm->tm_hour could be [0, 23] */ + if (rtc_in_range(tm->tm_hour, 0, 23)) + alarm_time.hour = tm->tm_hour; + else + return -1; + + /* Range of tm->tm_mday could be [1, 31] */ + if (rtc_in_range(tm->tm_mday, 1, 31)) + alarm_date.day = tm->tm_mday; + else + return -1; + + /* + * Range of tm->tm_mon could be [0, 11] + * But in this RTC, date.month should be [1, 12] + */ + if (rtc_in_range(tm->tm_mon, 0, 11)) + alarm_date.month = tm->tm_mon + 1; + else + return -1; + + /* + * Range of tm->tm_year is the years since 1900 + * But in this RTC, year is split into year and century + * In this RTC, century range is [0,31], year range is [0,99] + */ + int human_year = tm->tm_year + 1900; + int rtc_year = human_year % 100; + int rtc_century = human_year / 100; + + if (rtc_in_range(rtc_year, 0, 99) && + rtc_in_range(rtc_century, 0, 31)) + { + alarm_date.year = rtc_year; + } else + return -1; + + /* Range of tm->tm_wday could be [0, 6] */ + if (rtc_in_range(tm->tm_wday, 0, 6)) + alarm_date.week = tm->tm_wday; + else + return -1; + + /* Write value to RTC */ + rtc->alarm_date = alarm_date; + rtc->alarm_time = alarm_time; + } + + return 0; +} + +static int rtc_year_is_leap(int year) +{ + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +static int rtc_get_yday(int year, int month, int day) +{ + static const int days[2][13] = + { + {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} + }; + int leap = rtc_year_is_leap(year); + + return days[leap][month] + day; +} + +static int rtc_get_wday(int year, int month, int day) +{ + /* Magic method to get weekday */ + int weekday = (day += month < 3 ? year-- : year - 2, 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7; + return weekday; +} + +struct tm *rtc_timer_get_tm(void) +{ + if (rtc_timer_get_mode() != RTC_TIMER_RUNNING) + return NULL; + + rtc_date_t timer_date = rtc->date; + rtc_time_t timer_time = rtc->time; + rtc_extended_t timer_extended = rtc->extended; + + struct tm *tm = &rtc_date_time; + + tm->tm_sec = timer_time.second % 60; + tm->tm_min = timer_time.minute % 60; + tm->tm_hour = timer_time.hour % 24; + tm->tm_mday = (timer_date.day - 1) % 31 + 1; + tm->tm_mon = (timer_date.month - 1)% 12; + tm->tm_year = (timer_date.year % 100) + (timer_extended.century * 100) - 1900; + tm->tm_wday = timer_date.week; + tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + tm->tm_isdst = -1; + + return tm; +} + +struct tm *rtc_timer_get_alarm_tm(void) +{ + if (rtc_timer_get_mode() != RTC_TIMER_RUNNING) + return NULL; + + rtc_alarm_date_t alarm_date = rtc->alarm_date; + rtc_alarm_time_t alarm_time = rtc->alarm_time; + rtc_extended_t timer_extended = rtc->extended; + + struct tm *tm = &rtc_date_time; + + tm->tm_sec = alarm_time.second % 60; + tm->tm_min = alarm_time.minute % 60; + tm->tm_hour = alarm_time.hour % 24; + tm->tm_mday = alarm_date.day % 31; + tm->tm_mon = (alarm_date.month % 12) - 1; + /* Alarm and Timer use same timer_extended.century */ + tm->tm_year = (alarm_date.year % 100) + (timer_extended.century * 100) - 1900; + tm->tm_wday = alarm_date.week; + tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + tm->tm_isdst = -1; + + return tm; +} + +int rtc_timer_set(int year, int month, int day, int hour, int minute, int second) +{ + struct tm date_time = + { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + .tm_wday = rtc_get_wday(year, month, day), + .tm_yday = rtc_get_yday(year, month, day), + .tm_isdst = -1, + }; + return rtc_timer_set_tm(&date_time); +} + +int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second) +{ + struct tm *tm = rtc_timer_get_tm(); + + if (tm) + { + if (year) + *year = tm->tm_year + 1900; + if (month) + *month = tm->tm_mon + 1; + if (day) + *day = tm->tm_mday; + if (hour) + *hour = tm->tm_hour; + if (minute) + *minute = tm->tm_min; + if (second) + *second = tm->tm_sec; + } else + return -1; + + return 0; +} + +int rtc_timer_set_alarm(int year, int month, int day, int hour, int minute, int second) +{ + struct tm date_time = { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + .tm_wday = rtc_get_wday(year, month, day), + .tm_yday = rtc_get_yday(year, month, day), + .tm_isdst = -1, + }; + + return rtc_timer_set_alarm_tm(&date_time); +} + +int rtc_timer_get_alarm(int *year, int *month, int *day, int *hour, int *minute, int *second) +{ + struct tm *tm = rtc_timer_get_alarm_tm(); + + if (tm) { + if (year) + *year = tm->tm_year + 1900; + if (month) + *month = tm->tm_mon + 1; + if (day) + *day = tm->tm_mday; + if (hour) + *hour = tm->tm_hour; + if (minute) + *minute = tm->tm_min; + if (second) + *second = tm->tm_sec; + } else + return -1; + + return 0; +} + +int rtc_timer_set_clock_frequency(unsigned int frequency) +{ + + rtc_initial_count_t initial_count; + + initial_count.count = frequency; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->initial_count = initial_count; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +unsigned int rtc_timer_get_clock_frequency(void) +{ + return rtc->initial_count.count; +} + +int rtc_timer_set_clock_count_value(unsigned int count) +{ + + rtc_current_count_t current_count; + + current_count.count = count; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->current_count = current_count; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +unsigned int rtc_timer_get_clock_count_value(void) +{ + return rtc->current_count.count; +} + +int rtc_tick_interrupt_set(int enable) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + interrupt_ctrl.tick_enable = enable; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->interrupt_ctrl = interrupt_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +int rtc_tick_interrupt_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.tick_enable; +} + +int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_t mode) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.tick_int_mode = mode; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->interrupt_ctrl = interrupt_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +rtc_tick_interrupt_mode_t rtc_tick_interrupt_mode_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.tick_int_mode; +} + +int rtc_alarm_interrupt_set(int enable) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.alarm_enable = enable; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +int rtc_alarm_interrupt_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.alarm_enable; +} + +int rtc_alarm_interrupt_mask_set(rtc_mask_t mask) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.alarm_compare_mask = *(uint8_t *)&mask; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +rtc_mask_t rtc_alarm_interrupt_mask_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + uint8_t compare_mask = interrupt_ctrl.alarm_compare_mask; + + return *(rtc_mask_t *)&compare_mask; +} + +int rtc_protect_set(int enable) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + + rtc_mask_t mask = + { + .second = 1, + /* Second mask */ + .minute = 1, + /* Minute mask */ + .hour = 1, + /* Hour mask */ + .week = 1, + /* Week mask */ + .day = 1, + /* Day mask */ + .month = 1, + /* Month mask */ + .year = 1, + }; + + rtc_mask_t unmask = + { + .second = 0, + /* Second mask */ + .minute = 0, + /* Minute mask */ + .hour = 0, + /* Hour mask */ + .week = 0, + /* Week mask */ + .day = 0, + /* Day mask */ + .month = 0, + /* Month mask */ + .year = 0, + }; + + if (enable) + { + /* Turn RTC in protect mode, no one can write time */ + register_ctrl.TimerMask = *(uint8_t *)&unmask; + register_ctrl.alarm_mask = *(uint8_t *)&unmask; + register_ctrl.initial_count_mask = 0; + register_ctrl.interrupt_register_mask = 0; + } + else + { + /* Turn RTC in unprotect mode, everyone can write time */ + register_ctrl.TimerMask = *(uint8_t *)&mask; + register_ctrl.alarm_mask = *(uint8_t *)&mask; + register_ctrl.initial_count_mask = 1; + register_ctrl.interrupt_register_mask = 1; + } + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->register_ctrl = register_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +int rtc_init(void) +{ + /* Reset RTC */ + sysctl_reset(SYSCTL_RESET_RTC); + /* Enable RTC */ + sysctl_clock_enable(SYSCTL_CLOCK_RTC); + /* Unprotect RTC */ + rtc_protect_set(0); + /* Set RTC clock frequency */ + rtc_timer_set_clock_frequency( + SysctlClockGetFreq(SYSCTL_CLOCK_IN0) + ); + rtc_timer_set_clock_count_value(1); + + /* Set RTC mode to timer running mode */ + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} diff --git a/board/k210-emulator/third_party_driver/sleep.c b/board/k210-emulator/third_party_driver/sleep.c new file mode 100644 index 00000000..9f49c2df --- /dev/null +++ b/board/k210-emulator/third_party_driver/sleep.c @@ -0,0 +1,49 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 sleep.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include "sleep.h" +#include "sysctl.h" + +int usleep(uint64_t usec) +{ + uint64_t cycle = read_cycle(); + uint64_t nop_all = usec * SysctlClockGetFreq(SYSCTL_CLOCK_CPU) / 1000000UL; + while (1) + { + if(read_cycle() - cycle >= nop_all) + break; + } + return 0; +} + +int msleep(uint64_t msec) +{ + return (unsigned int)usleep(msec * 1000); +} + +unsigned int sleep(unsigned int seconds) +{ + return (unsigned int)msleep(seconds * 1000); +} + diff --git a/board/k210-emulator/third_party_driver/spi/Kconfig b/board/k210-emulator/third_party_driver/spi/Kconfig new file mode 100644 index 00000000..4ccf9f31 --- /dev/null +++ b/board/k210-emulator/third_party_driver/spi/Kconfig @@ -0,0 +1,67 @@ +config BSP_USING_SPI1 +bool "Using spi1 " +default y + + +if BSP_USING_SPI1 + config SPI_BUS_NAME_1 + string "spi bus 1 name" + default "spi1" + config SPI_1_DRV_NAME + string "spi bus 1 driver name" + default "spi1_drv" + config BSP_SPI1_CLK_PIN + int "spi1 clk pin number" + default 29 + config BSP_SPI1_D0_PIN + int "spi1 d0 pin number" + default 30 + config BSP_SPI1_D1_PIN + int "spi1 d1 pin number" + default 31 + menuconfig BSP_SPI1_USING_SS0 + bool "SPI1 Enable SS0" + default y + if BSP_SPI1_USING_SS0 + config SPI_1_DEVICE_NAME_0 + string "spi bus 1 device 0 name" + default "spi1_dev0" + config BSP_SPI1_SS0_PIN + int "spi1 ss0 pin number" + default 32 + endif + menuconfig BSP_SPI1_USING_SS1 + bool "SPI1 Enable SS1" + default y + if BSP_SPI1_USING_SS1 + config SPI_1_DEVICE_NAME_1 + string "spi bus 1 device 1 name" + default "spi1_dev1" + config BSP_SPI1_SS1_PIN + int "spi1 ss1 pin number" + default 33 + endif + menuconfig BSP_SPI1_USING_SS2 + bool "SPI1 Enable SS2" + default n + if BSP_SPI1_USING_SS2 + config SPI_1_DEVICE_NAME_2 + string "spi bus 1 device 2 name" + default "spi1_dev2" + config BSP_SPI1_SS2_PIN + int "spi1 ss2 pin number" + default 26 + endif + menuconfig BSP_SPI1_USING_SS3 + bool "SPI1 Enable SS3" + default n + if BSP_SPI1_USING_SS3 + config SPI_1_DEVICE_NAME_3 + string "spi bus 1 device 3 name" + default "spi1_dev3" + config BSP_SPI1_SS3_PIN + int "spi1 ss3 pin number" + default 27 + endif +endif + diff --git a/board/k210-emulator/third_party_driver/spi/Makefile b/board/k210-emulator/third_party_driver/spi/Makefile new file mode 100644 index 00000000..010350e8 --- /dev/null +++ b/board/k210-emulator/third_party_driver/spi/Makefile @@ -0,0 +1,6 @@ +SRC_FILES := connect_spi.c hardware_spi.c + + + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/spi/connect_spi.c b/board/k210-emulator/third_party_driver/spi/connect_spi.c new file mode 100644 index 00000000..05dfabe0 --- /dev/null +++ b/board/k210-emulator/third_party_driver/spi/connect_spi.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-03-18 ZYH first version + */ + +/** +* @file connect_spi.c +* @brief support kd233-board spi function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: connect_spi.c +Description: support kd233-board spi configure and spi bus register function +Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_spi.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. support kd233-board spi configure, write and read +2. support kd233-board spi bus device and driver register +*************************************************/ + +#include +#include +#include +#include +#include "connect_spi.h" +#include "hardware_spi.h" + +#include +#include "utils.h" + +#ifdef BSP_SPI1_USING_SS0 +#define SPI_DEVICE_SLAVE_ID_0 0 +#endif + +#ifdef BSP_SPI1_USING_SS1 +#define SPI_DEVICE_SLAVE_ID_1 1 +#endif + +#ifdef BSP_SPI1_USING_SS2 +#define SPI_DEVICE_SLAVE_ID_2 2 +#endif + +#ifdef BSP_SPI1_USING_SS3 +#define SPI_DEVICE_SLAVE_ID_3 3 +#endif + +static volatile spi_t *const spi_instance[4] = +{ + (volatile spi_t *)SPI0_BASE_ADDR, + (volatile spi_t *)SPI1_BASE_ADDR, + (volatile spi_t *)SPI_SLAVE_BASE_ADDR, + (volatile spi_t *)SPI3_BASE_ADDR +}; + +void __spi_set_tmod(uint8_t spi_num, uint32_t tmod) +{ + CHECK(spi_num < SPI_DEVICE_MAX); + volatile spi_t *spi_handle = spi[spi_num]; + uint8_t tmod_offset = 0; + switch (spi_num) + { + case 0: + case 1: + case 2: + tmod_offset = 8; + break; + case 3: + default: + tmod_offset = 10; + break; + } + set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset); +} + +/*Init the spi sdk intetface */ +static uint32 SpiSdkInit(struct SpiDriver *spi_drv) +{ + NULL_PARAM_CHECK(spi_drv); + uint8 cs_gpio_pin, cs_select_id; + uint32 max_frequency; + + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_drv->driver.private_data); + + cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin; + cs_select_id = dev_param->spi_slave_param->spi_cs_select_id; + + gpiohs_set_drive_mode(cs_select_id, GPIO_DM_OUTPUT);//Set the cs pin as output + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_HIGH);//set the cs gpio high + + spi_init(dev_param->spi_dma_param->spi_master_id, + dev_param->spi_master_param->spi_work_mode & SPI_MODE_3, + dev_param->spi_master_param->spi_frame_format, + dev_param->spi_master_param->spi_data_bit_width, + dev_param->spi_master_param->spi_data_endian); + + max_frequency = (dev_param->spi_master_param->spi_maxfrequency < SPI_MAX_CLOCK) ? dev_param->spi_master_param->spi_maxfrequency : SPI_MAX_CLOCK; + + uint32 real_freq = spi_set_clk_rate(dev_param->spi_dma_param->spi_master_id, max_frequency); + + return EOK; +} + +static uint32 SpiSdkCfg(struct SpiDriver *spi_drv, struct SpiMasterParam *spi_param) +{ + NULL_PARAM_CHECK(spi_drv); + NULL_PARAM_CHECK(spi_param); + + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_drv->driver.private_data); + + dev_param->spi_master_param = spi_param; + dev_param->spi_master_param->spi_work_mode = dev_param->spi_master_param->spi_work_mode & SPI_MODE_MASK; + dev_param->spi_master_param->spi_frame_format = SPI_FF_STANDARD; + + return EOK; +} + +/*Configure the spi device param, make sure struct (configure_info->private_data) = (SpiMasterParam)*/ +static uint32 SpiDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + struct SpiDriver *spi_drv = (struct SpiDriver *)drv; + struct SpiMasterParam *spi_param; + + switch (configure_info->configure_cmd) + { + case OPE_INT: + ret = SpiSdkInit(spi_drv); + break; + case OPE_CFG: + spi_param = (struct SpiMasterParam *)configure_info->private_data; + ret = SpiSdkCfg(spi_drv, spi_param); + break; + default: + break; + } + + return ret; +} + +static uint32 SpiWriteData(struct SpiHardwareDevice *spi_dev, struct SpiDataStandard *spi_datacfg) +{ + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data); + + uint8 device_id = dev_param->spi_slave_param->spi_slave_id; + uint8 device_master_id = dev_param->spi_dma_param->spi_master_id; + uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin; + + while (NONE != spi_datacfg) { + uint32_t * tx_buff = NONE; + int i; + x_ubase dummy = 0xFFFFFFFFU; + + __spi_set_tmod(device_master_id, SPI_TMOD_TRANS_RECV); + + if (spi_datacfg->spi_chip_select) { + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_LOW); + } + + if (spi_datacfg->length) { + spi_instance[device_master_id]->dmacr = 0x3; + spi_instance[device_master_id]->ssienr = 0x01; + + sysctl_dma_select(dev_param->spi_dma_param->spi_dmac_txchannel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + device_master_id * 2); + sysctl_dma_select(dev_param->spi_dma_param->spi_dmac_rxchannel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + device_master_id* 2); + + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_rxchannel, (void *)(&spi_instance[device_master_id]->dr[0]), &dummy, DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, spi_datacfg->length); + + if (!spi_datacfg->tx_buff) { + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_txchannel, &dummy, (void *)(&spi_instance[device_master_id]->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, spi_datacfg->length); + } else { + tx_buff = x_malloc(spi_datacfg->length * 4); + if (!tx_buff) { + goto transfer_done; + } + + for (i = 0; i < spi_datacfg->length; i++) { + tx_buff[i] = ((uint8_t *)spi_datacfg->tx_buff)[i]; + } + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_txchannel, tx_buff, (void *)(&spi_instance[device_master_id]->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, spi_datacfg->length); + } + + spi_instance[device_master_id]->ser = 1U << dev_param->spi_slave_param->spi_cs_select_id; + dmac_wait_done(dev_param->spi_dma_param->spi_dmac_txchannel); + dmac_wait_done(dev_param->spi_dma_param->spi_dmac_rxchannel); + spi_instance[device_master_id]->ser = 0x00; + spi_instance[device_master_id]->ssienr = 0x00; + + transfer_done: + if (tx_buff) { + x_free(tx_buff); + } + } + + if (spi_datacfg->spi_cs_release) { + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_HIGH); + } + + spi_datacfg = spi_datacfg->next; + } + + return spi_datacfg->length; +} + +static uint32 SpiReadData(struct SpiHardwareDevice *spi_dev, struct SpiDataStandard *spi_datacfg) +{ + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data); + + uint8 device_id = dev_param->spi_slave_param->spi_slave_id; + uint8 device_master_id = dev_param->spi_dma_param->spi_master_id; + uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin; + + while (NONE != spi_datacfg) { + uint32_t * rx_buff = NONE; + int i; + x_ubase dummy = 0xFFFFFFFFU; + + __spi_set_tmod(device_master_id, SPI_TMOD_TRANS_RECV); + + if (spi_datacfg->spi_chip_select) { + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_LOW); + } + if (spi_datacfg->length) { + spi_instance[device_master_id]->dmacr = 0x3; + spi_instance[device_master_id]->ssienr = 0x01; + + sysctl_dma_select(dev_param->spi_dma_param->spi_dmac_txchannel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + device_master_id * 2); + sysctl_dma_select(dev_param->spi_dma_param->spi_dmac_rxchannel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + device_master_id* 2); + + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_txchannel, &dummy, (void *)(&spi_instance[device_master_id]->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, spi_datacfg->length); + + if (!spi_datacfg->rx_buff) { + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_rxchannel, (void *)(&spi_instance[device_master_id]->dr[0]), &dummy, DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, spi_datacfg->length); + } else { + rx_buff = x_calloc(spi_datacfg->length * 4, 1); + if (!rx_buff) { + goto transfer_done; + } + + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_rxchannel, (void *)(&spi_instance[device_master_id]->dr[0]), rx_buff, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, spi_datacfg->length); + } + + spi_instance[device_master_id]->ser = 1U << dev_param->spi_slave_param->spi_cs_select_id; + dmac_wait_done(dev_param->spi_dma_param->spi_dmac_txchannel); + dmac_wait_done(dev_param->spi_dma_param->spi_dmac_rxchannel); + spi_instance[device_master_id]->ser = 0x00; + spi_instance[device_master_id]->ssienr = 0x00; + + if (spi_datacfg->rx_buff) { + for (i = 0; i < spi_datacfg->length; i++) { + ((uint8_t *)spi_datacfg->rx_buff)[i] = (uint8_t)rx_buff[i]; + } + } + + transfer_done: + if (rx_buff) { + x_free(rx_buff); + } + } + + if (spi_datacfg->spi_cs_release) { + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_HIGH); + } + + spi_datacfg = spi_datacfg->next; + } + + return spi_datacfg->length; +} + +/*manage the spi device operations*/ +static const struct SpiDevDone spi_dev_done = +{ + .open = NONE, + .close = NONE, + .write = SpiWriteData, + .read = SpiReadData, +}; + +static int BoardSpiBusInit(struct SpiBus *spi_bus, struct SpiDriver *spi_driver) +{ + x_err_t ret = EOK; + + /*Init the spi bus */ + ret = SpiBusInit(spi_bus, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiBusInit error %d\n", ret); + return ERROR; + } + + /*Init the spi driver*/ + ret = SpiDriverInit(spi_driver, SPI_1_DRV_NAME); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the spi driver to the spi bus*/ + ret = SpiDriverAttachToBus(SPI_1_DRV_NAME, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the spi device to the spi bus*/ +static int BoardSpiDevBend(struct SpiDmaParam *spi_initparam) +{ + x_err_t ret = EOK; + +#ifdef BSP_SPI1_USING_SS0 + static struct SpiHardwareDevice spi_device0; + memset(&spi_device0, 0, sizeof(struct SpiHardwareDevice)); + + static struct SpiSlaveParam spi_slaveparam0; + memset(&spi_slaveparam0, 0, sizeof(struct SpiSlaveParam)); + + spi_slaveparam0.spi_slave_id = SPI_DEVICE_SLAVE_ID_0; + spi_slaveparam0.spi_cs_gpio_pin = SPI1_CS0_PIN; + spi_slaveparam0.spi_cs_select_id = SPI_CHIP_SELECT_0; + + spi_device0.spi_param.spi_dma_param = spi_initparam; + spi_device0.spi_param.spi_slave_param = &spi_slaveparam0; + + spi_device0.spi_dev_done = &(spi_dev_done); + + ret = SpiDeviceRegister(&spi_device0, (void *)(&spi_device0.spi_param), SPI_1_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", SPI_1_DEVICE_NAME_0, ret); + return ERROR; + } + + ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_0, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", SPI_1_DEVICE_NAME_0, ret); + return ERROR; + } +#endif + +#ifdef BSP_SPI1_USING_SS1 + static struct SpiHardwareDevice spi_device1; + memset(&spi_device1, 0, sizeof(struct SpiHardwareDevice)); + + static struct SpiSlaveParam spi_slaveparam1; + memset(&spi_slaveparam1, 0, sizeof(struct SpiSlaveParam)); + + spi_slaveparam1.spi_slave_id = SPI_DEVICE_SLAVE_ID_1; + spi_slaveparam1.spi_cs_gpio_pin = SPI1_CS1_PIN; + spi_slaveparam1.spi_cs_select_id = SPI_CHIP_SELECT_1; + + spi_device1.spi_param.spi_dma_param = spi_initparam; + spi_device1.spi_param.spi_slave_param = &spi_slaveparam1; + + spi_device1.spi_dev_done = &(spi_dev_done); + + ret = SpiDeviceRegister(&spi_device1, (void *)(&spi_device1.spi_param), SPI_1_DEVICE_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", SPI_1_DEVICE_NAME_1, ret); + return ERROR; + } + + ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_1, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", SPI_1_DEVICE_NAME_1, ret); + return ERROR; + } +#endif + +#ifdef BSP_SPI1_USING_SS2 + static struct SpiHardwareDevice spi_device2; + memset(&spi_device2, 0, sizeof(struct SpiHardwareDevice)); + + spi_initparam->spi_slave_id[SPI_DEVICE_SLAVE_ID_2] = SPI_DEVICE_SLAVE_ID_2; + spi_initparam->spi_cs_gpio_pin[SPI_DEVICE_SLAVE_ID_2] = SPI1_CS2_PIN; + spi_initparam->spi_cs_select_id[SPI_DEVICE_SLAVE_ID_2] = SPI_CHIP_SELECT_2; + + spi_device2.spi_dev_done = &(spi_dev_done); + + ret = SpiDeviceRegister(&spi_device2, (void *)(&spi_device2.spi_param), SPI_1_DEVICE_NAME_2); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", SPI_1_DEVICE_NAME_2, ret); + return ERROR; + } + + ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_2, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", SPI_1_DEVICE_NAME_2, ret); + return ERROR; + } +#endif + +#ifdef BSP_SPI1_USING_SS3 + static struct SpiHardwareDevice spi_device3; + memset(&spi_device3, 0, sizeof(struct SpiHardwareDevice)); + + spi_initparam->spi_slave_id[SPI_DEVICE_SLAVE_ID_3] = SPI_DEVICE_SLAVE_ID_3; + spi_initparam->spi_cs_gpio_pin[SPI_DEVICE_SLAVE_ID_3] = SPI1_CS3_PIN; + spi_initparam->spi_cs_select_id[SPI_DEVICE_SLAVE_ID_3] = SPI_CHIP_SELECT_3; + + spi_device3.spi_dev_done = &(spi_dev_done); + + ret = SpiDeviceRegister(&spi_device3, (void *)(&spi_device3.spi_param), SPI_1_DEVICE_NAME_3); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", SPI_1_DEVICE_NAME_3, ret); + return ERROR; + } + + ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_3, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", SPI_1_DEVICE_NAME_3, ret); + return ERROR; + } +#endif + return ret; +} + +/*RISC-V 64 BOARD SPI INIT*/ +int HwSpiInit(void) +{ + x_err_t ret = EOK; + static struct SpiDmaParam spi_initparam; + memset(&spi_initparam, 0, sizeof(struct SpiDmaParam)); + +#ifdef BSP_USING_SPI1 + + static struct SpiBus spi_bus; + memset(&spi_bus, 0, sizeof(struct SpiBus)); + + static struct SpiDriver spi_driver; + memset(&spi_driver, 0, sizeof(struct SpiDriver)); + + spi_initparam.spi_master_id = SPI_DEVICE_1; + spi_initparam.spi_dmac_txchannel = DMAC_CHANNEL1; + spi_initparam.spi_dmac_rxchannel = DMAC_CHANNEL2; + + spi_driver.configure = &(SpiDrvConfigure); + + ret = BoardSpiBusInit(&spi_bus, &spi_driver); + if (EOK != ret) { + KPrintf("Board_Spi_Init error ret %u\n", ret); + return ERROR; + } + + ret = BoardSpiDevBend(&spi_initparam); + if (EOK != ret) { + KPrintf("Board_Spi_Init error ret %u\n", ret); + return ERROR; + } +#endif + return ret; +} diff --git a/board/k210-emulator/third_party_driver/spi/hardware_spi.c b/board/k210-emulator/third_party_driver/spi/hardware_spi.c new file mode 100644 index 00000000..45e45e72 --- /dev/null +++ b/board/k210-emulator/third_party_driver/spi/hardware_spi.c @@ -0,0 +1,1523 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_spi.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include "platform.h" +#include "hardware_spi.h" +#include "fpioa.h" +#include "utils.h" +#include "gpiohs.h" +#include "sysctl.h" +#include +#include +#include +#include + +volatile spi_t *const spi[4] = +{ + (volatile spi_t *)SPI0_BASE_ADDR, + (volatile spi_t *)SPI1_BASE_ADDR, + (volatile spi_t *)SPI_SLAVE_BASE_ADDR, + (volatile spi_t *)SPI3_BASE_ADDR +}; + +typedef struct _spi_dma_context +{ + uint8_t *buffer; + size_t BufLen; + uint32_t *MallocBuffer; + spi_transfer_mode_t IntMode; + dmac_channel_number_t dmac_channel; + spi_device_num_t spi_num; + plic_instance_t spi_int_instance; +} spi_dma_context_t; + +spi_dma_context_t spi_dma_context[4]; + +typedef struct _spi_instance_t +{ + spi_device_num_t spi_num; + spi_transfer_mode_t TransferMode; + dmac_channel_number_t dmac_channel; + plic_instance_t spi_int_instance; + spinlock_t lock; +} spi_instance_t; + +static spi_instance_t g_spi_instance[4]; + +static spi_slave_instance_t g_instance; + +static spi_frame_format_t spi_get_frame_format(spi_device_num_t spi_num) +{ + uint8_t frf_offset; + switch(spi_num) + { + case 0: + case 1: + frf_offset = 21; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + frf_offset = 22; + break; + } + volatile spi_t *spi_adapter = spi[spi_num]; + return ((spi_adapter->ctrlr0 >> frf_offset) & 0x3); +} + +static spi_transfer_width_t spi_get_frame_size(size_t data_bit_length) +{ + if (data_bit_length < 8) + return SPI_TRANS_CHAR; + else if (data_bit_length < 16) + return SPI_TRANS_SHORT; + return SPI_TRANS_INT; +} + +static int spi_dma_irq(void *ctx) +{ + spi_instance_t *v_instance = (spi_instance_t *)ctx; + volatile spi_t *spi_handle = spi[v_instance->spi_num]; + dmac_irq_unregister(v_instance->dmac_channel); + while ((spi_handle->sr & 0x05) != 0x04); + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + spinlock_unlock(&v_instance->lock); + if(v_instance->spi_int_instance.callback) + { + v_instance->spi_int_instance.callback(v_instance->spi_int_instance.ctx); + } + return 0; +} + +static int spi_clk_init(uint8_t spi_num) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + if(spi_num == 3) + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_SPI3, 1); + sysctl_clock_enable(SYSCTL_CLOCK_SPI0 + spi_num); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI0 + spi_num, 0); + return 0; +} + +static void spi_set_tmod(uint8_t spi_num, uint32_t tmod) +{ + configASSERT(spi_num < SPI_DEVICE_MAX); + volatile spi_t *spi_handle = spi[spi_num]; + uint8_t tmod_offset = 0; + switch(spi_num) + { + case 0: + case 1: + case 2: + tmod_offset = 8; + break; + case 3: + default: + tmod_offset = 10; + break; + } + set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset); +} + +void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format, + size_t data_bit_length, uint32_t endian) +{ + configASSERT(data_bit_length >= 4 && data_bit_length <= 32); + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + spi_clk_init(spi_num); + + uint8_t dfs_offset, frf_offset, work_mode_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + frf_offset = 21; + work_mode_offset = 6; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + frf_offset = 22; + work_mode_offset = 8; + break; + } + + switch (frame_format) + { + case SPI_FF_DUAL: + configASSERT(data_bit_length % 2 == 0); + break; + case SPI_FF_QUAD: + configASSERT(data_bit_length % 4 == 0); + break; + case SPI_FF_OCTAL: + configASSERT(data_bit_length % 8 == 0); + break; + default: + break; + } + volatile spi_t *spi_adapter = spi[spi_num]; + if(spi_adapter->baudr == 0) + spi_adapter->baudr = 0x14; + spi_adapter->imr = 0x00; + spi_adapter->dmacr = 0x00; + spi_adapter->dmatdlr = 0x10; + spi_adapter->dmardlr = 0x00; + spi_adapter->ser = 0x00; + spi_adapter->ssienr = 0x00; + spi_adapter->ctrlr0 = (work_mode << work_mode_offset) | (frame_format << frf_offset) | ((data_bit_length - 1) << dfs_offset); + spi_adapter->spi_ctrlr0 = 0; + spi_adapter->endian = endian; +} + +void spi_init_non_standard(spi_device_num_t spi_num, uint32_t instruction_length, uint32_t address_length, + uint32_t wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode) +{ + configASSERT(wait_cycles < (1 << 5)); + configASSERT(instruction_address_trans_mode < 3); + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + uint32_t inst_l = 0; + switch (instruction_length) + { + case 0: + inst_l = 0; + break; + case 4: + inst_l = 1; + break; + case 8: + inst_l = 2; + break; + case 16: + inst_l = 3; + break; + default: + configASSERT(!"Invalid instruction length"); + break; + } + + configASSERT(address_length % 4 == 0 && address_length <= 60); + uint32_t addr_l = address_length / 4; + + spi_handle->spi_ctrlr0 = (wait_cycles << 11) | (inst_l << 8) | (addr_l << 2) | instruction_address_trans_mode; +} + +uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk) +{ + uint32_t spi_baudr = SysctlClockGetFreq(SYSCTL_CLOCK_SPI0 + spi_num) / spi_clk; + if(spi_baudr < 2 ) + { + spi_baudr = 2; + } + else if(spi_baudr > 65534) + { + spi_baudr = 65534; + } + volatile spi_t *spi_adapter = spi[spi_num]; + spi_adapter->baudr = spi_baudr; + return SysctlClockGetFreq(SYSCTL_CLOCK_SPI0 + spi_num) / spi_baudr; +} + +void spi_send_data_normal(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint8_t v_misalign_flag = 0; + uint32_t v_send_data; + if((uintptr_t)tx_buff % frame_width) + v_misalign_flag = 1; + + spi_handle->ssienr = 0x01; + spi_handle->ser = 1U << chip_select; + uint32_t i = 0; + while (tx_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + fifo_len = fifo_len / 4 * 4; + if(v_misalign_flag) + { + for(index = 0; index < fifo_len; index +=4) + { + memcpy(&v_send_data, tx_buff + i , 4); + spi_handle->dr[0] = v_send_data; + i += 4; + } + } + else + { + for (index = 0; index < fifo_len / 4; index++) + spi_handle->dr[0] = ((uint32_t *)tx_buff)[i++]; + } + break; + case SPI_TRANS_SHORT: + fifo_len = fifo_len / 2 * 2; + if(v_misalign_flag) + { + for(index = 0; index < fifo_len; index +=2) + { + memcpy(&v_send_data, tx_buff + i, 2); + spi_handle->dr[0] = v_send_data; + i += 2; + } + } + else + { + for (index = 0; index < fifo_len / 2; index++) + spi_handle->dr[0] = ((uint16_t *)tx_buff)[i++]; + } + break; + default: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = tx_buff[i++]; + break; + } + tx_len -= fifo_len; + } + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + +} + +void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + uint8_t *v_buf = malloc(CmdLen + tx_len); + size_t i; + for(i = 0; i < CmdLen; i++) + v_buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len; i++) + v_buf[CmdLen + i] = tx_buff[i]; + + spi_send_data_normal(spi_num, chip_select, v_buf, CmdLen + tx_len); + free((void *)v_buf); +} + +void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint8_t *CmdBuff, size_t CmdLen, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint32_t *buf; + size_t v_send_len; + int i; + switch(frame_width) + { + case SPI_TRANS_INT: + buf = malloc(CmdLen + tx_len); + for(i = 0; i < CmdLen / 4; i++) + buf[i] = ((uint32_t *)CmdBuff)[i]; + for(i = 0; i < tx_len / 4; i++) + buf[CmdLen / 4 + i] = ((uint32_t *)tx_buff)[i]; + v_send_len = (CmdLen + tx_len) / 4; + break; + case SPI_TRANS_SHORT: + buf = malloc((CmdLen + tx_len) / 2 * sizeof(uint32_t)); + for(i = 0; i < CmdLen / 2; i++) + buf[i] = ((uint16_t *)CmdBuff)[i]; + for(i = 0; i < tx_len / 2; i++) + buf[CmdLen / 2 + i] = ((uint16_t *)tx_buff)[i]; + v_send_len = (CmdLen + tx_len) / 2; + break; + default: + buf = malloc((CmdLen + tx_len) * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len; i++) + buf[CmdLen + i] = tx_buff[i]; + v_send_len = CmdLen + tx_len; + break; + } + + spi_send_data_normal_dma(channel_num, spi_num, chip_select, buf, v_send_len, SPI_TRANS_INT); + + free((void *)buf); +} + +void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const void *tx_buff, size_t tx_len, spi_transfer_width_t spi_transfer_width) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + uint32_t *buf; + int i; + switch(spi_transfer_width) + { + case SPI_TRANS_SHORT: + buf = malloc((tx_len) * sizeof(uint32_t)); + for(i = 0; i < tx_len; i++) + buf[i] = ((uint16_t *)tx_buff)[i]; + break; + case SPI_TRANS_INT: + buf = (uint32_t *)tx_buff; + break; + case SPI_TRANS_CHAR: + default: + buf = malloc((tx_len) * sizeof(uint32_t)); + for(i = 0; i < tx_len; i++) + buf[i] = ((uint8_t *)tx_buff)[i]; + break; + } + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select((sysctl_dma_channel_t) channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, tx_len); + spi_handle->ser = 1U << chip_select; + dmac_wait_done(channel_num); + if(spi_transfer_width != SPI_TRANS_INT) + free((void *)buf); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + +void spi_dup_send_receive_data_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint8_t *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) +{ + spi_set_tmod(spi_num, SPI_TMOD_TRANS_RECV); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + size_t v_tx_len = tx_len / frame_width; + size_t v_rx_len = rx_len / frame_width; + + size_t v_max_len = v_tx_len > v_rx_len ? v_tx_len : v_rx_len; + + uint32_t *v_tx_buf = malloc(v_max_len * 4); + uint32_t *v_rx_buf = malloc(v_max_len * 4); + uint32_t i = 0; + switch(frame_width) + { + case SPI_TRANS_INT: + for(i = 0; i < v_tx_len; i++) + { + v_tx_buf[i] = ((uint32_t *)tx_buf)[i]; + } + if(v_max_len > v_tx_len) + { + while(i < v_max_len) + { + v_tx_buf[i++] = 0xFFFFFFFF; + } + } + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_tx_len; i++) + { + v_tx_buf[i] = ((uint16_t *)tx_buf)[i]; + } + if(v_max_len > v_tx_len) + { + while(i < v_max_len) + { + v_tx_buf[i++] = 0xFFFFFFFF; + } + } + break; + default: + for(i = 0; i < v_tx_len; i++) + { + v_tx_buf[i] = tx_buf[i]; + } + if(v_max_len > v_tx_len) + { + while(i < v_max_len) + { + v_tx_buf[i++] = 0xFFFFFFFF; + } + } + break; + } + + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + + sysctl_dma_select((sysctl_dma_channel_t)dma_send_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + sysctl_dma_select((sysctl_dma_channel_t)dma_receive_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + + dmac_set_single_mode(dma_receive_channel_num, (void *)(&spi_handle->dr[0]), v_rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, v_max_len); + + dmac_set_single_mode(dma_send_channel_num, v_tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, v_max_len); + + spi_handle->ser = 1U << chip_select; + dmac_wait_done(dma_send_channel_num); + dmac_wait_done(dma_receive_channel_num); + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + + switch(frame_width) + { + case SPI_TRANS_INT: + for(i = 0; i < v_rx_len; i++) + ((uint32_t *)rx_buf)[i] = v_rx_buf[i]; + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_rx_len; i++) + ((uint16_t *)rx_buf)[i] = v_rx_buf[i]; + break; + default: + for(i = 0; i < v_rx_len; i++) + rx_buf[i] = v_rx_buf[i]; + break; + } + free(v_tx_buf); + free(v_rx_buf); +} + +void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + size_t index, fifo_len; + if(CmdLen == 0) + spi_set_tmod(spi_num, SPI_TMOD_RECV); + else + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint32_t i = 0; + size_t v_cmd_len = CmdLen / frame_width; + uint32_t v_rx_len = rx_len / frame_width; + + spi_handle->ctrlr1 = (uint32_t)(v_rx_len - 1); + spi_handle->ssienr = 0x01; + + while (v_cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len; + switch(frame_width) + { + case SPI_TRANS_INT: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = ((uint32_t *)CmdBuff)[i++]; + break; + case SPI_TRANS_SHORT: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = ((uint16_t *)CmdBuff)[i++]; + break; + default: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = CmdBuff[i++]; + break; + } + spi_handle->ser = 1U << chip_select; + v_cmd_len -= fifo_len; + } + + if(CmdLen == 0) + { + spi_handle->dr[0] = 0xffffffff; + spi_handle->ser = 1U << chip_select; + } + + i = 0; + while (v_rx_len) + { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < v_rx_len ? fifo_len : v_rx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + for (index = 0; index < fifo_len; index++) + ((uint32_t *)rx_buff)[i++] = spi_handle->dr[0]; + break; + case SPI_TRANS_SHORT: + for (index = 0; index < fifo_len; index++) + ((uint16_t *)rx_buff)[i++] = (uint16_t)spi_handle->dr[0]; + break; + default: + for (index = 0; index < fifo_len; index++) + rx_buff[i++] = (uint8_t)spi_handle->dr[0]; + break; + } + + v_rx_len -= fifo_len; + } + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + +void spi_receive_data_normal_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const void *CmdBuff, + size_t CmdLen, void *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + if(CmdLen == 0) + spi_set_tmod(spi_num, SPI_TMOD_RECV); + else + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + + volatile spi_t *spi_handle = spi[spi_num]; + + spi_handle->ctrlr1 = (uint32_t)(rx_len - 1); + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + if(CmdLen) + sysctl_dma_select((sysctl_dma_channel_t)dma_send_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + sysctl_dma_select((sysctl_dma_channel_t)dma_receive_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + + dmac_set_single_mode(dma_receive_channel_num, (void *)(&spi_handle->dr[0]), rx_buff, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, rx_len); + if(CmdLen) + dmac_set_single_mode(dma_send_channel_num, CmdBuff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, CmdLen); + if(CmdLen == 0 && spi_get_frame_format(spi_num) == SPI_FF_STANDARD) + spi[spi_num]->dr[0] = 0xffffffff; + spi_handle->ser = 1U << chip_select; + if(CmdLen) + dmac_wait_done(dma_send_channel_num); + dmac_wait_done(dma_receive_channel_num); + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + + +void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + size_t i; + + uint32_t *write_cmd; + uint32_t *ReadBuf; + size_t v_recv_len; + size_t v_cmd_len; + switch(frame_width) + { + case SPI_TRANS_INT: + write_cmd = malloc(CmdLen + rx_len); + for(i = 0; i < CmdLen / 4; i++) + write_cmd[i] = ((uint32_t *)CmdBuff)[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len / 4; + v_cmd_len = CmdLen / 4; + break; + case SPI_TRANS_SHORT: + write_cmd = malloc((CmdLen + rx_len) /2 * sizeof(uint32_t)); + for(i = 0; i < CmdLen / 2; i++) + write_cmd[i] = ((uint16_t *)CmdBuff)[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len / 2; + v_cmd_len = CmdLen / 2; + break; + default: + write_cmd = malloc((CmdLen + rx_len) * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + write_cmd[i] = CmdBuff[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len; + v_cmd_len = CmdLen; + break; + } + + spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, write_cmd, v_cmd_len, ReadBuf, v_recv_len); + + switch(frame_width) + { + case SPI_TRANS_INT: + for(i = 0; i < v_recv_len; i++) + ((uint32_t *)rx_buff)[i] = ReadBuf[i]; + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_recv_len; i++) + ((uint16_t *)rx_buff)[i] = ReadBuf[i]; + break; + default: + for(i = 0; i < v_recv_len; i++) + rx_buff[i] = ReadBuf[i]; + break; + } + + free(write_cmd); +} + +void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + if(CmdLen == 0) + spi_set_tmod(spi_num, SPI_TMOD_RECV); + else + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint32_t v_cmd_len = CmdLen; + uint32_t i = 0; + + uint32_t v_rx_len = rx_len / frame_width; + + spi_handle->ctrlr1 = (uint32_t)(v_rx_len - 1); + spi_handle->ssienr = 0x01; + + while (v_cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len; + + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *CmdBuff++; + + spi_handle->ser = 1U << chip_select; + v_cmd_len -= fifo_len; + } + + if(CmdLen == 0) + { + spi_handle->ser = 1U << chip_select; + } + + while (v_rx_len) + { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < v_rx_len ? fifo_len : v_rx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + for (index = 0; index < fifo_len; index++) + ((uint32_t *)rx_buff)[i++] = spi_handle->dr[0]; + break; + case SPI_TRANS_SHORT: + for (index = 0; index < fifo_len; index++) + ((uint16_t *)rx_buff)[i++] = (uint16_t)spi_handle->dr[0]; + break; + default: + for (index = 0; index < fifo_len; index++) + rx_buff[i++] = (uint8_t)spi_handle->dr[0]; + break; + } + + v_rx_len -= fifo_len; + } + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + +} + +void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + size_t i; + + uint32_t *write_cmd = NULL; + uint32_t *ReadBuf; + size_t v_recv_len; + switch(frame_width) + { + case SPI_TRANS_INT: + v_recv_len = rx_len / 4; + break; + case SPI_TRANS_SHORT: + write_cmd = malloc(CmdLen + rx_len /2 * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + write_cmd[i] = CmdBuff[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len / 2; + break; + default: + write_cmd = malloc(CmdLen + rx_len * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + write_cmd[i] = CmdBuff[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len; + break; + } + if(frame_width == SPI_TRANS_INT) + spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, CmdBuff, CmdLen, rx_buff, v_recv_len); + else + spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, write_cmd, CmdLen, ReadBuf, v_recv_len); + + switch(frame_width) + { + case SPI_TRANS_INT: + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_recv_len; i++) + ((uint16_t *)rx_buff)[i] = ReadBuf[i]; + break; + default: + for(i = 0; i < v_recv_len; i++) + rx_buff[i] = ReadBuf[i]; + break; + } + + if(frame_width != SPI_TRANS_INT) + free(write_cmd); +} + +void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + spi_handle->ssienr = 0x01; + spi_handle->ser = 1U << chip_select; + + size_t v_cmd_len = CmdLen * 4; + while(v_cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len; + fifo_len = fifo_len / 4 * 4; + for (index = 0; index < fifo_len / 4; index++) + spi_handle->dr[0] = *CmdBuff++; + v_cmd_len -= fifo_len; + } + spi_send_data_normal(spi_num, chip_select, tx_buff, tx_len); +} + +void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint32_t *CmdBuff, size_t CmdLen, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint32_t *buf; + size_t v_send_len; + int i; + switch(frame_width) + { + case SPI_TRANS_INT: + buf = malloc(CmdLen * sizeof(uint32_t) + tx_len); + for(i = 0; i < CmdLen; i++) + buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len / 4; i++) + buf[CmdLen + i] = ((uint32_t *)tx_buff)[i]; + v_send_len = CmdLen + tx_len / 4; + break; + case SPI_TRANS_SHORT: + buf = malloc(CmdLen * sizeof(uint32_t) + tx_len / 2 * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len / 2; i++) + buf[CmdLen + i] = ((uint16_t *)tx_buff)[i]; + v_send_len = CmdLen + tx_len / 2; + break; + default: + buf = malloc((CmdLen + tx_len) * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len; i++) + buf[CmdLen + i] = tx_buff[i]; + v_send_len = CmdLen + tx_len; + break; + } + + spi_send_data_normal_dma(channel_num, spi_num, chip_select, buf, v_send_len, SPI_TRANS_INT); + + free((void *)buf); +} + +void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint32_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + dmac_set_single_mode(channel_num, tx_buff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, tx_len); + spi_handle->ser = 1U << chip_select; + dmac_wait_done(channel_num); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + +static int spi_slave_irq(void *ctx) +{ + volatile spi_t *spi_handle = spi[2]; + + spi_handle->imr = 0x00; + *(volatile uint32_t *)((uintptr_t)spi_handle->icr); + if (g_instance.status == IDLE) + g_instance.status = COMMAND; + return 0; +} + +static void spi_slave_idle_mode(void) +{ + volatile spi_t *spi_handle = spi[2]; + uint32_t DataWidth = g_instance.data_bit_length / 8; + g_instance.status = IDLE; + spi_handle->ssienr = 0x00; + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi_handle->rxftlr = 0x08 / DataWidth - 1; + + spi_handle->dmacr = 0x00; + spi_handle->imr = 0x10; + spi_handle->ssienr = 0x01; + gpiohs_set_pin(g_instance.ready_pin, GPIO_PV_HIGH); +} + +static void spi_slave_command_mode(void) +{ + volatile spi_t *spi_handle = spi[2]; + uint8_t CmdData[8], sum = 0; + + spi_transfer_width_t frame_width = spi_get_frame_size(g_instance.data_bit_length - 1); + uint32_t DataWidth = g_instance.data_bit_length / 8; + spi_device_num_t spi_num = SPI_DEVICE_2; + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < 8 / 4; i++) + ((uint32_t *)CmdData)[i] = spi_handle->dr[0]; + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < 8 / 2; i++) + ((uint16_t *)CmdData)[i] = spi_handle->dr[0]; + break; + default: + for (uint32_t i = 0; i < 8; i++) + CmdData[i] = spi_handle->dr[0]; + break; + } + + for (uint32_t i = 0; i < 7; i++) + { + sum += CmdData[i]; + } + if (CmdData[7] != sum) + { + spi_slave_idle_mode(); + return; + } + g_instance.command.cmd = CmdData[0]; + g_instance.command.addr = CmdData[1] | (CmdData[2] << 8) | (CmdData[3] << 16) | (CmdData[4] << 24); + g_instance.command.len = CmdData[5] | (CmdData[6] << 8); + if (g_instance.command.len == 0) + g_instance.command.len = 65536; + if ((g_instance.command.cmd < WRITE_DATA_BLOCK) && (g_instance.command.len > 8)) + { + spi_slave_idle_mode(); + return; + } + g_instance.status = TRANSFER; + spi_handle->ssienr = 0x00; + if (g_instance.command.cmd == WRITE_CONFIG) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi[2]->rxftlr = g_instance.command.len / DataWidth - 1; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + } + else if (g_instance.command.cmd == READ_CONFIG) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x0 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi_set_tmod(2, SPI_TMOD_TRANS); + spi_handle->txftlr = 0x00; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < g_instance.command.len / 4; i++) + { + spi_handle->dr[0] = ((uint32_t *)&g_instance.config_ptr[g_instance.command.addr])[i]; + } + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < g_instance.command.len / 2; i++) + { + spi_handle->dr[0] = ((uint16_t *)&g_instance.config_ptr[g_instance.command.addr])[i]; + } + break; + default: + for (uint32_t i = 0; i < g_instance.command.len; i++) + { + spi_handle->dr[0] = ((uint8_t *)&g_instance.config_ptr[g_instance.command.addr])[i]; + } + break; + } + } + else if (g_instance.command.cmd == WRITE_DATA_BYTE) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi[2]->rxftlr = g_instance.command.len / DataWidth - 1; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + } + else if (g_instance.command.cmd == READ_DATA_BYTE) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x0 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi_set_tmod(2, SPI_TMOD_TRANS); + spi_handle->txftlr = 0x00; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < g_instance.command.len / 4; i++) + { + spi_handle->dr[0] = ((uint32_t *)(uintptr_t)g_instance.command.addr)[i]; + } + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < g_instance.command.len / 2; i++) + { + spi_handle->dr[0] = ((uint16_t *)(uintptr_t)g_instance.command.addr)[i]; + } + break; + default: + for (uint32_t i = 0; i < g_instance.command.len; i++) + { + spi_handle->dr[0] = ((uint8_t *)(uintptr_t)g_instance.command.addr)[i]; + } + break; + } + } + else if (g_instance.command.cmd == WRITE_DATA_BLOCK) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((32 - 1) << g_instance.dfs); + + spi_handle->dmacr = 0x01; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + + sysctl_dma_select(g_instance.dmac_channel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + + dmac_set_single_mode(g_instance.dmac_channel, (void *)(&spi_handle->dr[0]), (void *)((uintptr_t)g_instance.command.addr & 0xFFFFFFF0), DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, g_instance.command.len * 4); + } + else if (g_instance.command.cmd == READ_DATA_BLOCK) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x0 << g_instance.slv_oe) | ((32 - 1) << g_instance.dfs); + spi_set_tmod(2, SPI_TMOD_TRANS); + spi_handle->dmacr = 0x02; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + + sysctl_dma_select(g_instance.dmac_channel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + dmac_set_single_mode(g_instance.dmac_channel, (void *)((uintptr_t)g_instance.command.addr & 0xFFFFFFF0), (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, g_instance.command.len * 4); + } + else + { + spi_slave_idle_mode(); + return; + } + gpiohs_set_pin(g_instance.ready_pin, GPIO_PV_LOW); +} + +static void spi_slave_transfer_mode(void) +{ + spi_transfer_width_t frame_width = spi_get_frame_size(g_instance.data_bit_length - 1); + uint32_t command_len = 0; + + switch(frame_width) + { + case SPI_TRANS_INT: + command_len = g_instance.command.len / 4; + break; + case SPI_TRANS_SHORT: + command_len = g_instance.command.len / 2; + break; + default: + command_len = g_instance.command.len; + break; + } + volatile spi_t *spi_handle = spi[2]; + g_instance.command.err = 0; + if (g_instance.command.cmd == WRITE_CONFIG || g_instance.command.cmd == WRITE_DATA_BYTE) + { + if (spi_handle->rxflr < command_len - 1) + g_instance.command.err = 1; + } + else if (g_instance.command.cmd == READ_CONFIG || g_instance.command.cmd == READ_DATA_BYTE) + { + if (spi_handle->txflr != 0) + g_instance.command.err = 2; + } else if (g_instance.command.cmd == WRITE_DATA_BLOCK || g_instance.command.cmd == READ_DATA_BLOCK) + { + if (dmac->channel[g_instance.dmac_channel].intstatus != 0x02) + g_instance.command.err = 3; + } + else + { + spi_slave_idle_mode(); + return; + } + + if (g_instance.command.err == 0) + { + if (g_instance.command.cmd == WRITE_CONFIG) + { + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint32_t *)&g_instance.config_ptr[g_instance.command.addr])[i] = spi_handle->dr[0]; + } + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint16_t *)&g_instance.config_ptr[g_instance.command.addr])[i] = spi_handle->dr[0]; + } + break; + default: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint8_t *)&g_instance.config_ptr[g_instance.command.addr])[i] = spi_handle->dr[0]; + } + break; + } + } + else if (g_instance.command.cmd == WRITE_DATA_BYTE) + { + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint32_t *)(uintptr_t)g_instance.command.addr)[i] = spi_handle->dr[0]; + } + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint16_t *)(uintptr_t)g_instance.command.addr)[i] = spi_handle->dr[0]; + } + break; + default: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint8_t *)(uintptr_t)g_instance.command.addr)[i] = spi_handle->dr[0]; + } + break; + } + } + } + if(g_instance.callback != NULL) + { + g_instance.callback((void *)&g_instance.command); + } + spi_slave_idle_mode(); +} + +static void spi_slave_cs_irq(void) +{ + if (g_instance.status == IDLE) + spi_slave_idle_mode(); + else if (g_instance.status == COMMAND) + spi_slave_command_mode(); + else if (g_instance.status == TRANSFER) + spi_slave_transfer_mode(); +} + +void spi_slave_config(uint8_t int_pin, uint8_t ready_pin, dmac_channel_number_t dmac_channel, size_t data_bit_length, uint8_t *data, uint32_t len, spi_slave_receive_callback_t callback) +{ + g_instance.status = IDLE; + g_instance.config_ptr = data; + g_instance.config_len = len; + g_instance.work_mode = 6; + g_instance.slv_oe = 10; + g_instance.dfs = 16; + g_instance.data_bit_length = data_bit_length; + g_instance.ready_pin = ready_pin; + g_instance.int_pin = int_pin; + g_instance.callback = callback; + g_instance.dmac_channel = dmac_channel; + sysctl_reset(SYSCTL_RESET_SPI2); + sysctl_clock_enable(SYSCTL_CLOCK_SPI2); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI2, 9); + + uint32_t DataWidth = data_bit_length / 8; + volatile spi_t *spi_handle = spi[2]; + spi_handle->ssienr = 0x00; + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((data_bit_length - 1) << g_instance.dfs); + spi_handle->dmatdlr = 0x04; + spi_handle->dmardlr = 0x03; + spi_handle->dmacr = 0x00; + spi_handle->txftlr = 0x00; + spi_handle->rxftlr = 0x08 / DataWidth - 1; + spi_handle->imr = 0x10; + spi_handle->ssienr = 0x01; + + gpiohs_set_drive_mode(g_instance.ready_pin, GPIO_DM_OUTPUT); + gpiohs_set_pin(g_instance.ready_pin, GPIO_PV_HIGH); + + gpiohs_set_drive_mode(g_instance.int_pin, GPIO_DM_INPUT_PULL_UP); + gpiohs_set_pin_edge(g_instance.int_pin, GPIO_PE_RISING); + gpiohs_set_irq(g_instance.int_pin, 3, spi_slave_cs_irq); + + plic_set_priority(IRQN_SPI_SLAVE_INTERRUPT, 4); + plic_irq_enable(IRQN_SPI_SLAVE_INTERRUPT); + plic_irq_register(IRQN_SPI_SLAVE_INTERRUPT, spi_slave_irq, NULL); +} + +void spi_handle_data_dma(spi_device_num_t spi_num, spi_chip_select_t chip_select, spi_data_t data, plic_interrupt_t *cb) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + configASSERT(chip_select < SPI_CHIP_SELECT_MAX); + switch(data.TransferMode) + { + case SPI_TMOD_TRANS_RECV: + case SPI_TMOD_EEROM: + configASSERT(data.tx_buf && data.tx_len && data.rx_buf && data.rx_len); + break; + case SPI_TMOD_TRANS: + configASSERT(data.tx_buf && data.tx_len); + break; + case SPI_TMOD_RECV: + configASSERT(data.rx_buf && data.rx_len); + break; + default: + configASSERT(!"Transfer Mode ERR"); + break; + } + configASSERT(data.tx_channel < DMAC_CHANNEL_MAX && data.rx_channel < DMAC_CHANNEL_MAX); + volatile spi_t *spi_handle = spi[spi_num]; + + spinlock_lock(&g_spi_instance[spi_num].lock); + if(cb) + { + g_spi_instance[spi_num].spi_int_instance.callback = cb->callback; + g_spi_instance[spi_num].spi_int_instance.ctx = cb->ctx; + } + switch(data.TransferMode) + { + case SPI_TMOD_RECV: + spi_set_tmod(spi_num, SPI_TMOD_RECV); + if(data.rx_len > 65536) + data.rx_len = 65536; + spi_handle->ctrlr1 = (uint32_t)(data.rx_len - 1); + spi_handle->dmacr = 0x03; + spi_handle->ssienr = 0x01; + if(spi_get_frame_format(spi_num) == SPI_FF_STANDARD) + spi_handle->dr[0] = 0xffffffff; + if(cb) + { + dmac_irq_register(data.rx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.rx_channel; + } + sysctl_dma_select((sysctl_dma_channel_t)data.rx_channel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + dmac_set_single_mode(data.rx_channel, (void *)(&spi_handle->dr[0]), (void *)data.rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + spi_handle->ser = 1U << chip_select; + if(!cb) + dmac_wait_idle(data.rx_channel); + break; + case SPI_TMOD_TRANS: + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + if(cb) + { + dmac_irq_register(data.tx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.tx_channel; + } + sysctl_dma_select(data.tx_channel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + if(data.fill_mode) + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + else + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + spi_handle->ser = 1U << chip_select; + if(!cb) + { + dmac_wait_idle(data.tx_channel); + while ((spi_handle->sr & 0x05) != 0x04) + ; + } + break; + case SPI_TMOD_EEROM: + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + if(data.rx_len > 65536) + data.rx_len = 65536; + spi_handle->ctrlr1 = (uint32_t)(data.rx_len - 1); + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + sysctl_dma_select(data.tx_channel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + if(data.fill_mode) + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + else + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + if(cb) + { + dmac_irq_register(data.rx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.rx_channel; + } + sysctl_dma_select(data.rx_channel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + dmac_set_single_mode(data.rx_channel, (void *)(&spi_handle->dr[0]), (void *)data.rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + spi_handle->ser = 1U << chip_select; + if(!cb) + dmac_wait_idle(data.rx_channel); + break; + case SPI_TMOD_TRANS_RECV: + spi_set_tmod(spi_num, SPI_TMOD_TRANS_RECV); + if(data.rx_len > 65536) + data.rx_len = 65536; + + if(cb) + { + if(data.tx_len > data.rx_len) + { + dmac_irq_register(data.tx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.tx_channel; + } + else + { + dmac_irq_register(data.rx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.rx_channel; + } + } + spi_handle->ctrlr1 = (uint32_t)(data.rx_len - 1); + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + sysctl_dma_select(data.tx_channel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + if(data.fill_mode) + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + else + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + sysctl_dma_select(data.rx_channel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + dmac_set_single_mode(data.rx_channel, (void *)(&spi_handle->dr[0]), (void *)data.rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + spi_handle->ser = 1U << chip_select; + if(!cb) + { + dmac_wait_idle(data.tx_channel); + dmac_wait_idle(data.rx_channel); + } + break; + } + if(!cb) + { + spinlock_unlock(&g_spi_instance[spi_num].lock); + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + } +} + diff --git a/board/k210-emulator/third_party_driver/sys_clock/Kconfig b/board/k210-emulator/third_party_driver/sys_clock/Kconfig new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/board/k210-emulator/third_party_driver/sys_clock/Kconfig @@ -0,0 +1 @@ + diff --git a/board/k210-emulator/third_party_driver/sys_clock/Makefile b/board/k210-emulator/third_party_driver/sys_clock/Makefile new file mode 100644 index 00000000..ef5fda17 --- /dev/null +++ b/board/k210-emulator/third_party_driver/sys_clock/Makefile @@ -0,0 +1,6 @@ +SRC_FILES := sysctl.c + + + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/sys_clock/sysctl.c b/board/k210-emulator/third_party_driver/sys_clock/sysctl.c new file mode 100644 index 00000000..6999ace8 --- /dev/null +++ b/board/k210-emulator/third_party_driver/sys_clock/sysctl.c @@ -0,0 +1,1870 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 sysctl.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include +#include "sysctl.h" +#include "string.h" +#include "encoding.h" +#include "bsp.h" + +#define SYSCTRL_CLOCK_FREQ_IN0 (26000000UL) + +const uint8_t get_select_pll2[] = +{ + [SYSCTL_SOURCE_IN0] = 0, + [SYSCTL_SOURCE_PLL0] = 1, + [SYSCTL_SOURCE_PLL1] = 2, +}; + +const uint8_t get_source_pll2[] = +{ + [0] = SYSCTL_SOURCE_IN0, + [1] = SYSCTL_SOURCE_PLL0, + [2] = SYSCTL_SOURCE_PLL1, +}; + +const uint8_t get_select_aclk[] = +{ + [SYSCTL_SOURCE_IN0] = 0, + [SYSCTL_SOURCE_PLL0] = 1, +}; + +const uint8_t get_source_aclk[] = +{ + [0] = SYSCTL_SOURCE_IN0, + [1] = SYSCTL_SOURCE_PLL0, +}; + +volatile sysctl_t *const sysctl = (volatile sysctl_t *)SYSCTL_BASE_ADDR; + +uint32_t sysctl_get_git_id(void) +{ + return sysctl->git_id.git_id; +} + +uint32_t sysctl_get_freq(void) +{ + return sysctl->clk_freq.clk_freq; +} + +static void sysctl_reset_ctl(sysctl_reset_t reset, uint8_t rst_value) +{ + switch (reset) + { + case SYSCTL_RESET_SOC: + sysctl->soft_reset.soft_reset = rst_value; + break; + case SYSCTL_RESET_ROM: + sysctl->peri_reset.rom_reset = rst_value; + break; + case SYSCTL_RESET_DMA: + sysctl->peri_reset.dma_reset = rst_value; + break; + case SYSCTL_RESET_AI: + sysctl->peri_reset.ai_reset = rst_value; + break; + case SYSCTL_RESET_DVP: + sysctl->peri_reset.dvp_reset = rst_value; + break; + case SYSCTL_RESET_FFT: + sysctl->peri_reset.fft_reset = rst_value; + break; + case SYSCTL_RESET_GPIO: + sysctl->peri_reset.gpio_reset = rst_value; + break; + case SYSCTL_RESET_SPI0: + sysctl->peri_reset.spi0_reset = rst_value; + break; + case SYSCTL_RESET_SPI1: + sysctl->peri_reset.spi1_reset = rst_value; + break; + case SYSCTL_RESET_SPI2: + sysctl->peri_reset.spi2_reset = rst_value; + break; + case SYSCTL_RESET_SPI3: + sysctl->peri_reset.spi3_reset = rst_value; + break; + case SYSCTL_RESET_I2S0: + sysctl->peri_reset.i2s0_reset = rst_value; + break; + case SYSCTL_RESET_I2S1: + sysctl->peri_reset.i2s1_reset = rst_value; + break; + case SYSCTL_RESET_I2S2: + sysctl->peri_reset.i2s2_reset = rst_value; + break; + case SYSCTL_RESET_I2C0: + sysctl->peri_reset.i2c0_reset = rst_value; + break; + case SYSCTL_RESET_I2C1: + sysctl->peri_reset.i2c1_reset = rst_value; + break; + case SYSCTL_RESET_I2C2: + sysctl->peri_reset.i2c2_reset = rst_value; + break; + case SYSCTL_RESET_UART1: + sysctl->peri_reset.uart1_reset = rst_value; + break; + case SYSCTL_RESET_UART2: + sysctl->peri_reset.uart2_reset = rst_value; + break; + case SYSCTL_RESET_UART3: + sysctl->peri_reset.uart3_reset = rst_value; + break; + case SYSCTL_RESET_AES: + sysctl->peri_reset.aes_reset = rst_value; + break; + case SYSCTL_RESET_FPIOA: + sysctl->peri_reset.fpioa_reset = rst_value; + break; + case SYSCTL_RESET_TIMER0: + sysctl->peri_reset.timer0_reset = rst_value; + break; + case SYSCTL_RESET_TIMER1: + sysctl->peri_reset.timer1_reset = rst_value; + break; + case SYSCTL_RESET_TIMER2: + sysctl->peri_reset.timer2_reset = rst_value; + break; + case SYSCTL_RESET_WDT0: + sysctl->peri_reset.wdt0_reset = rst_value; + break; + case SYSCTL_RESET_WDT1: + sysctl->peri_reset.wdt1_reset = rst_value; + break; + case SYSCTL_RESET_SHA: + sysctl->peri_reset.sha_reset = rst_value; + break; + case SYSCTL_RESET_RTC: + sysctl->peri_reset.rtc_reset = rst_value; + break; + + default: + break; + } +} + +void sysctl_reset(sysctl_reset_t reset) +{ + sysctl_reset_ctl(reset, 1); + usleep(10); + sysctl_reset_ctl(reset, 0); +} + +static int sysctl_clock_bus_en(sysctl_clock_t clock, uint8_t en) +{ + /* + * The timer is under APB0, to prevent apb0_clk_en1 and apb0_clk_en0 + * on same register, we split it to peripheral and central two + * registers, to protect CPU close apb0 clock accidentally. + * + * The apb0_clk_en0 and apb0_clk_en1 have same function, + * one of them set, the APB0 clock enable. + */ + + /* The APB clock should carefully disable */ + if (en) + { + switch (clock) + { + /* + * These peripheral devices are under APB0 + * GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1, + * I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0, + * TIMER1, TIMER2 + */ + case SYSCTL_CLOCK_GPIO: + case SYSCTL_CLOCK_SPI2: + case SYSCTL_CLOCK_I2S0: + case SYSCTL_CLOCK_I2S1: + case SYSCTL_CLOCK_I2S2: + case SYSCTL_CLOCK_I2C0: + case SYSCTL_CLOCK_I2C1: + case SYSCTL_CLOCK_I2C2: + case SYSCTL_CLOCK_UART1: + case SYSCTL_CLOCK_UART2: + case SYSCTL_CLOCK_UART3: + case SYSCTL_CLOCK_FPIOA: + case SYSCTL_CLOCK_TIMER0: + case SYSCTL_CLOCK_TIMER1: + case SYSCTL_CLOCK_TIMER2: + case SYSCTL_CLOCK_SHA: + sysctl->clk_en_cent.apb0_clk_en = en; + break; + + /* + * These peripheral devices are under APB1 + * WDT, AES, OTP, DVP, SYSCTL + */ + case SYSCTL_CLOCK_AES: + case SYSCTL_CLOCK_WDT0: + case SYSCTL_CLOCK_WDT1: + case SYSCTL_CLOCK_OTP: + case SYSCTL_CLOCK_RTC: + sysctl->clk_en_cent.apb1_clk_en = en; + break; + + /* + * These peripheral devices are under APB2 + * SPI0, SPI1 + */ + case SYSCTL_CLOCK_SPI0: + case SYSCTL_CLOCK_SPI1: + sysctl->clk_en_cent.apb2_clk_en = en; + break; + + default: + break; + } + } + + return 0; +} + +static int sysctl_clock_device_en(sysctl_clock_t clock, uint8_t en) +{ + switch (clock) + { + /* + * These devices are PLL + */ + case SYSCTL_CLOCK_PLL0: + sysctl->pll0.pll_out_en0 = en; + break; + case SYSCTL_CLOCK_PLL1: + sysctl->pll1.pll_out_en1 = en; + break; + case SYSCTL_CLOCK_PLL2: + sysctl->pll2.pll_out_en2 = en; + break; + + /* + * These devices are CPU, SRAM, APB bus, ROM, DMA, AI + */ + case SYSCTL_CLOCK_CPU: + sysctl->clk_en_cent.cpu_clk_en = en; + break; + case SYSCTL_CLOCK_SRAM0: + sysctl->clk_en_cent.sram0_clk_en = en; + break; + case SYSCTL_CLOCK_SRAM1: + sysctl->clk_en_cent.sram1_clk_en = en; + break; + case SYSCTL_CLOCK_APB0: + sysctl->clk_en_cent.apb0_clk_en = en; + break; + case SYSCTL_CLOCK_APB1: + sysctl->clk_en_cent.apb1_clk_en = en; + break; + case SYSCTL_CLOCK_APB2: + sysctl->clk_en_cent.apb2_clk_en = en; + break; + case SYSCTL_CLOCK_ROM: + sysctl->clk_en_peri.rom_clk_en = en; + break; + case SYSCTL_CLOCK_DMA: + sysctl->clk_en_peri.dma_clk_en = en; + break; + case SYSCTL_CLOCK_AI: + sysctl->clk_en_peri.ai_clk_en = en; + break; + case SYSCTL_CLOCK_DVP: + sysctl->clk_en_peri.dvp_clk_en = en; + break; + case SYSCTL_CLOCK_FFT: + sysctl->clk_en_peri.fft_clk_en = en; + break; + case SYSCTL_CLOCK_SPI3: + sysctl->clk_en_peri.spi3_clk_en = en; + break; + + /* + * These peripheral devices are under APB0 + * GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1, + * I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0, + * TIMER1, TIMER2 + */ + case SYSCTL_CLOCK_GPIO: + sysctl->clk_en_peri.gpio_clk_en = en; + break; + case SYSCTL_CLOCK_SPI2: + sysctl->clk_en_peri.spi2_clk_en = en; + break; + case SYSCTL_CLOCK_I2S0: + sysctl->clk_en_peri.i2s0_clk_en = en; + break; + case SYSCTL_CLOCK_I2S1: + sysctl->clk_en_peri.i2s1_clk_en = en; + break; + case SYSCTL_CLOCK_I2S2: + sysctl->clk_en_peri.i2s2_clk_en = en; + break; + case SYSCTL_CLOCK_I2C0: + sysctl->clk_en_peri.i2c0_clk_en = en; + break; + case SYSCTL_CLOCK_I2C1: + sysctl->clk_en_peri.i2c1_clk_en = en; + break; + case SYSCTL_CLOCK_I2C2: + sysctl->clk_en_peri.i2c2_clk_en = en; + break; + case SYSCTL_CLOCK_UART1: + sysctl->clk_en_peri.uart1_clk_en = en; + break; + case SYSCTL_CLOCK_UART2: + sysctl->clk_en_peri.uart2_clk_en = en; + break; + case SYSCTL_CLOCK_UART3: + sysctl->clk_en_peri.uart3_clk_en = en; + break; + case SYSCTL_CLOCK_FPIOA: + sysctl->clk_en_peri.fpioa_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER0: + sysctl->clk_en_peri.timer0_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER1: + sysctl->clk_en_peri.timer1_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER2: + sysctl->clk_en_peri.timer2_clk_en = en; + break; + case SYSCTL_CLOCK_SHA: + sysctl->clk_en_peri.sha_clk_en = en; + break; + + /* + * These peripheral devices are under APB1 + * WDT, AES, OTP, DVP, SYSCTL + */ + case SYSCTL_CLOCK_AES: + sysctl->clk_en_peri.aes_clk_en = en; + break; + case SYSCTL_CLOCK_WDT0: + sysctl->clk_en_peri.wdt0_clk_en = en; + break; + case SYSCTL_CLOCK_WDT1: + sysctl->clk_en_peri.wdt1_clk_en = en; + break; + case SYSCTL_CLOCK_OTP: + sysctl->clk_en_peri.otp_clk_en = en; + break; + case SYSCTL_CLOCK_RTC: + sysctl->clk_en_peri.rtc_clk_en = en; + break; + + /* + * These peripheral devices are under APB2 + * SPI0, SPI1 + */ + case SYSCTL_CLOCK_SPI0: + sysctl->clk_en_peri.spi0_clk_en = en; + break; + case SYSCTL_CLOCK_SPI1: + sysctl->clk_en_peri.spi1_clk_en = en; + break; + + default: + break; + } + + return 0; +} + +int sysctl_clock_enable(sysctl_clock_t clock) +{ + if (clock >= SYSCTL_CLOCK_MAX) + return -1; + //sysctl_clock_bus_en(clock, 1); + //sysctl_clock_device_en(clock, 1); + return 0; +} + +int sysctl_clock_disable(sysctl_clock_t clock) +{ + if (clock >= SYSCTL_CLOCK_MAX) + return -1; + sysctl_clock_device_en(clock, 0); + return 0; +} + +int sysctl_clock_set_threshold(sysctl_threshold_t which, int threshold) +{ + int result = 0; + switch (which) + { + /* + * These threshold is 2 bit width + */ + case SYSCTL_THRESHOLD_ACLK: + sysctl->clk_sel0.aclk_divider_sel = (uint8_t)threshold & 0x03; + break; + + /* + * These threshold is 3 bit width + */ + case SYSCTL_THRESHOLD_APB0: + sysctl->clk_sel0.apb0_clk_sel = (uint8_t)threshold & 0x07; + break; + case SYSCTL_THRESHOLD_APB1: + sysctl->clk_sel0.apb1_clk_sel = (uint8_t)threshold & 0x07; + break; + case SYSCTL_THRESHOLD_APB2: + sysctl->clk_sel0.apb2_clk_sel = (uint8_t)threshold & 0x07; + break; + + /* + * These threshold is 4 bit width + */ + case SYSCTL_THRESHOLD_SRAM0: + sysctl->clk_th0.sram0_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_SRAM1: + sysctl->clk_th0.sram1_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_AI: + sysctl->clk_th0.ai_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_DVP: + sysctl->clk_th0.dvp_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_ROM: + sysctl->clk_th0.rom_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + + /* + * These threshold is 8 bit width + */ + case SYSCTL_THRESHOLD_SPI0: + sysctl->clk_th1.spi0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI1: + sysctl->clk_th1.spi1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI2: + sysctl->clk_th1.spi2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI3: + sysctl->clk_th1.spi3_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER0: + sysctl->clk_th2.timer0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER1: + sysctl->clk_th2.timer1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER2: + sysctl->clk_th2.timer2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S0_M: + sysctl->clk_th4.i2s0_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S1_M: + sysctl->clk_th4.i2s1_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S2_M: + sysctl->clk_th5.i2s2_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C0: + sysctl->clk_th5.i2c0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C1: + sysctl->clk_th5.i2c1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C2: + sysctl->clk_th5.i2c2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_WDT0: + sysctl->clk_th6.wdt0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_WDT1: + sysctl->clk_th6.wdt1_clk_threshold = (uint8_t)threshold; + break; + + /* + * These threshold is 16 bit width + */ + case SYSCTL_THRESHOLD_I2S0: + sysctl->clk_th3.i2s0_clk_threshold = (uint16_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S1: + sysctl->clk_th3.i2s1_clk_threshold = (uint16_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S2: + sysctl->clk_th4.i2s2_clk_threshold = (uint16_t)threshold; + break; + + default: + result = -1; + break; + } + return result; +} + +int sysctl_clock_get_threshold(sysctl_threshold_t which) +{ + int threshold = 0; + + switch (which) + { + /* + * Select and get threshold value + */ + case SYSCTL_THRESHOLD_ACLK: + threshold = (int)sysctl->clk_sel0.aclk_divider_sel; + break; + case SYSCTL_THRESHOLD_APB0: + threshold = (int)sysctl->clk_sel0.apb0_clk_sel; + break; + case SYSCTL_THRESHOLD_APB1: + threshold = (int)sysctl->clk_sel0.apb1_clk_sel; + break; + case SYSCTL_THRESHOLD_APB2: + threshold = (int)sysctl->clk_sel0.apb2_clk_sel; + break; + case SYSCTL_THRESHOLD_SRAM0: + threshold = (int)sysctl->clk_th0.sram0_gclk_threshold; + break; + case SYSCTL_THRESHOLD_SRAM1: + threshold = (int)sysctl->clk_th0.sram1_gclk_threshold; + break; + case SYSCTL_THRESHOLD_AI: + threshold = (int)sysctl->clk_th0.ai_gclk_threshold; + break; + case SYSCTL_THRESHOLD_DVP: + threshold = (int)sysctl->clk_th0.dvp_gclk_threshold; + break; + case SYSCTL_THRESHOLD_ROM: + threshold = (int)sysctl->clk_th0.rom_gclk_threshold; + break; + case SYSCTL_THRESHOLD_SPI0: + threshold = (int)sysctl->clk_th1.spi0_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI1: + threshold = (int)sysctl->clk_th1.spi1_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI2: + threshold = (int)sysctl->clk_th1.spi2_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI3: + threshold = (int)sysctl->clk_th1.spi3_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER0: + threshold = (int)sysctl->clk_th2.timer0_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER1: + threshold = (int)sysctl->clk_th2.timer1_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER2: + threshold = (int)sysctl->clk_th2.timer2_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S0: + threshold = (int)sysctl->clk_th3.i2s0_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S1: + threshold = (int)sysctl->clk_th3.i2s1_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S2: + threshold = (int)sysctl->clk_th4.i2s2_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S0_M: + threshold = (int)sysctl->clk_th4.i2s0_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2S1_M: + threshold = (int)sysctl->clk_th4.i2s1_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2S2_M: + threshold = (int)sysctl->clk_th5.i2s2_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2C0: + threshold = (int)sysctl->clk_th5.i2c0_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2C1: + threshold = (int)sysctl->clk_th5.i2c1_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2C2: + threshold = (int)sysctl->clk_th5.i2c2_clk_threshold; + break; + case SYSCTL_THRESHOLD_WDT0: + threshold = (int)sysctl->clk_th6.wdt0_clk_threshold; + break; + case SYSCTL_THRESHOLD_WDT1: + threshold = (int)sysctl->clk_th6.wdt1_clk_threshold; + break; + + default: + break; + } + + return threshold; +} + +int sysctl_clock_set_clock_select(sysctl_clock_select_t which, int select) +{ + int result = 0; + switch (which) + { + /* + * These clock select is 1 bit width + */ + case SYSCTL_CLOCK_SELECT_PLL0_BYPASS: + sysctl->pll0.pll_bypass0 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_PLL1_BYPASS: + sysctl->pll1.pll_bypass1 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_PLL2_BYPASS: + sysctl->pll2.pll_bypass2 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_ACLK: + sysctl->clk_sel0.aclk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_SPI3: + sysctl->clk_sel0.spi3_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER0: + sysctl->clk_sel0.timer0_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER1: + sysctl->clk_sel0.timer1_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER2: + sysctl->clk_sel0.timer2_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_SPI3_SAMPLE: + sysctl->clk_sel1.spi3_sample_clk_sel = select & 0x01; + break; + + /* + * These clock select is 2 bit width + */ + case SYSCTL_CLOCK_SELECT_PLL2: + sysctl->pll2.pll_ckin_sel2 = select & 0x03; + break; + + default: + result = -1; + break; + } + + return result; +} + +int sysctl_clock_get_clock_select(sysctl_clock_select_t which) +{ + int clock_select = 0; + + switch (which) + { + /* + * Select and get clock select value + */ + case SYSCTL_CLOCK_SELECT_PLL0_BYPASS: + clock_select = (int)sysctl->pll0.pll_bypass0; + break; + case SYSCTL_CLOCK_SELECT_PLL1_BYPASS: + clock_select = (int)sysctl->pll1.pll_bypass1; + break; + case SYSCTL_CLOCK_SELECT_PLL2_BYPASS: + clock_select = (int)sysctl->pll2.pll_bypass2; + break; + case SYSCTL_CLOCK_SELECT_PLL2: + clock_select = (int)sysctl->pll2.pll_ckin_sel2; + break; + case SYSCTL_CLOCK_SELECT_ACLK: + clock_select = (int)sysctl->clk_sel0.aclk_sel; + break; + case SYSCTL_CLOCK_SELECT_SPI3: + clock_select = (int)sysctl->clk_sel0.spi3_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER0: + clock_select = (int)sysctl->clk_sel0.timer0_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER1: + clock_select = (int)sysctl->clk_sel0.timer1_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER2: + clock_select = (int)sysctl->clk_sel0.timer2_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_SPI3_SAMPLE: + clock_select = (int)sysctl->clk_sel1.spi3_sample_clk_sel; + break; + + default: + break; + } + + return clock_select; +} + +uint32_t sysctl_clock_source_get_freq(sysctl_clock_source_t input) +{ + uint32_t result; + + switch (input) + { + case SYSCTL_SOURCE_IN0: + result = SYSCTRL_CLOCK_FREQ_IN0; + break; + case SYSCTL_SOURCE_PLL0: + result = sysctl_pll_get_freq(SYSCTL_PLL0); + break; + case SYSCTL_SOURCE_PLL1: + result = sysctl_pll_get_freq(SYSCTL_PLL1); + break; + case SYSCTL_SOURCE_PLL2: + result = sysctl_pll_get_freq(SYSCTL_PLL2); + break; + case SYSCTL_SOURCE_ACLK: + result = SysctlClockGetFreq(SYSCTL_CLOCK_ACLK); + break; + default: + result = 0; + break; + } + return result; +} + +static int sysctl_pll_is_lock(sysctl_pll_t pll) +{ + /* + * All bit enable means PLL lock + * + * struct pll_lock_t + * { + * uint8_t overflow : 1; + * uint8_t rfslip : 1; + * uint8_t fbslip : 1; + * }; + * + */ + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + return sysctl->pll_lock.pll_lock0 == 3; + + case SYSCTL_PLL1: + return sysctl->pll_lock.pll_lock1 & 1; + + case SYSCTL_PLL2: + return sysctl->pll_lock.pll_lock2 & 1; + + default: + break; + } + + return 0; +} + +static int sysctl_pll_clear_slip(sysctl_pll_t pll) +{ + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + sysctl->pll_lock.pll_slip_clear0 = 1; + break; + + case SYSCTL_PLL1: + sysctl->pll_lock.pll_slip_clear1 = 1; + break; + + case SYSCTL_PLL2: + sysctl->pll_lock.pll_slip_clear2 = 1; + break; + + default: + break; + } + + return sysctl_pll_is_lock(pll) ? 0 : -1; +} + +int sysctl_pll_enable(sysctl_pll_t pll) +{ + /* + * ---+ + * PWRDN | + * +------------------------------------------------------------- + * ^ + * | + * | + * t1 + * +------------------+ + * RESET | | + * ----------+ +----------------------------------- + * ^ ^ ^ + * |<----- t_rst ---->|<---------- t_lock ---------->| + * | | | + * t2 t3 t4 + */ + + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + /* Do not bypass PLL */ + sysctl->pll0.pll_bypass0 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll0.pll_pwrd0 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll0.pll_reset0 = 0; + sysctl->pll0.pll_reset0 = 1; + asm volatile ("nop"); + asm volatile ("nop"); + sysctl->pll0.pll_reset0 = 0; + break; + + case SYSCTL_PLL1: + /* Do not bypass PLL */ + sysctl->pll1.pll_bypass1 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll1.pll_pwrd1 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll1.pll_reset1 = 0; + sysctl->pll1.pll_reset1 = 1; + asm volatile ("nop"); + asm volatile ("nop"); + sysctl->pll1.pll_reset1 = 0; + break; + + case SYSCTL_PLL2: + /* Do not bypass PLL */ + sysctl->pll2.pll_bypass2 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll2.pll_pwrd2 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll2.pll_reset2 = 0; + sysctl->pll2.pll_reset2 = 1; + asm volatile ("nop"); + asm volatile ("nop"); + sysctl->pll2.pll_reset2 = 0; + break; + + default: + break; + } + + return 0; +} + +int sysctl_pll_disable(sysctl_pll_t pll) +{ + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + /* Bypass PLL */ + sysctl->pll0.pll_bypass0 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll0.pll_pwrd0 = 0; + break; + + case SYSCTL_PLL1: + /* Bypass PLL */ + sysctl->pll1.pll_bypass1 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll1.pll_pwrd1 = 0; + break; + + case SYSCTL_PLL2: + /* Bypass PLL */ + sysctl->pll2.pll_bypass2 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll2.pll_pwrd2 = 0; + break; + + default: + break; + } + + return 0; +} + +uint32_t sysctl_pll_get_freq(sysctl_pll_t pll) +{ + uint32_t freq_in = 0, freq_out = 0; + uint32_t nr = 0, nf = 0, od = 0; + uint8_t select = 0; + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + nr = sysctl->pll0.clkr0 + 1; + nf = sysctl->pll0.clkf0 + 1; + od = sysctl->pll0.clkod0 + 1; + break; + + case SYSCTL_PLL1: + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + nr = sysctl->pll1.clkr1 + 1; + nf = sysctl->pll1.clkf1 + 1; + od = sysctl->pll1.clkod1 + 1; + break; + + case SYSCTL_PLL2: + /* + * Get input freq accroding select register + */ + select = sysctl->pll2.pll_ckin_sel2; + if (select < sizeof(get_source_pll2)) + freq_in = sysctl_clock_source_get_freq(get_source_pll2[select]); + else + return 0; + + nr = sysctl->pll2.clkr2 + 1; + nf = sysctl->pll2.clkf2 + 1; + od = sysctl->pll2.clkod2 + 1; + break; + + default: + break; + } + + /* + * Get final PLL output freq + * FOUT = FIN / NR * NF / OD + */ + freq_out = (double)freq_in / (double)nr * (double)nf / (double)od; + return freq_out; +} + +static uint32_t sysctl_pll_source_set_freq(sysctl_pll_t pll, sysctl_clock_source_t source, uint32_t freq) +{ + uint32_t freq_in = 0; + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + if (source >= SYSCTL_SOURCE_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + case SYSCTL_PLL1: + /* + * Check input clock source + */ + if (source != SYSCTL_SOURCE_IN0) + return 0; + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + /* + * Check input clock freq + */ + if (freq_in == 0) + return 0; + break; + + case SYSCTL_PLL2: + /* + * Check input clock source + */ + if (source < sizeof(get_select_pll2)) + freq_in = sysctl_clock_source_get_freq(source); + /* + * Check input clock freq + */ + if (freq_in == 0) + return 0; + break; + + default: + return 0; + } + + /* + * Begin calculate PLL registers' value + */ + + /* constants */ + const double vco_min = 3.5e+08; + const double vco_max = 1.75e+09; + const double ref_min = 1.36719e+07; + const double ref_max = 1.75e+09; + const int nr_min = 1; + const int nr_max = 16; + const int nf_min = 1; + const int nf_max = 64; + const int no_min = 1; + const int no_max = 16; + const int nb_min = 1; + const int nb_max = 64; + const int max_vco = 1; + const int ref_rng = 1; + + /* variables */ + int nr = 0; + int nrx = 0; + int nf = 0; + int nfi = 0; + int no = 0; + int noe = 0; + int not = 0; + int nor = 0; + int nore = 0; + int nb = 0; + int first = 0; + int firstx = 0; + int found = 0; + + long long nfx = 0; + double fin = 0, fout = 0, fvco = 0; + double val = 0, nval = 0, err = 0, merr = 0, terr = 0; + int x_nrx = 0, x_no = 0, x_nb = 0; + long long x_nfx = 0; + double x_fvco = 0, x_err = 0; + + fin = freq_in; + fout = freq; + val = fout / fin; + terr = 0.5 / ((double)(nf_max / 2)); + first = firstx = 1; + if (terr != -2) + { + first = 0; + if (terr == 0) + terr = 1e-16; + merr = fabs(terr); + } + found = 0; + for (nfi = val; nfi < nf_max; ++nfi) + { + nr = rint(((double)nfi) / val); + if (nr == 0) + continue; + if ((ref_rng) && (nr < nr_min)) + continue; + if (fin / ((double)nr) > ref_max) + continue; + nrx = nr; + nf = nfx = nfi; + nval = ((double)nfx) / ((double)nr); + if (nf == 0) + nf = 1; + err = 1 - nval / val; + + if ((first) || (fabs(err) < merr * (1 + 1e-6)) || (fabs(err) < 1e-16)) + { + not = floor(vco_max / fout); + for (no = (not > no_max) ? no_max : not; no > no_min; --no) + { + if ((ref_rng) && ((nr / no) < nr_min)) + continue; + if ((nr % no) == 0) + break; + } + if ((nr % no) != 0) + continue; + nor = ((not > no_max) ? no_max : not) / no; + nore = nf_max / nf; + if (nor > nore) + nor = nore; + noe = ceil(vco_min / fout); + if (!max_vco) + { + nore = (noe - 1) / no + 1; + nor = nore; + not = 0; /* force next if to fail */ + } + if ((((no * nor) < (not >> 1)) || ((no * nor) < noe)) && ((no * nor) < (nf_max / nf))) + { + no = nf_max / nf; + if (no > no_max) + no = no_max; + if (no > not) + no = not; + nfx *= no; + nf *= no; + if ((no > 1) && (!firstx)) + continue; + /* wait for larger nf in later iterations */ + } + else + { + nrx /= no; + nfx *= nor; + nf *= nor; + no *= nor; + if (no > no_max) + continue; + if ((nor > 1) && (!firstx)) + continue; + /* wait for larger nf in later iterations */ + } + + nb = nfx; + if (nb < nb_min) + nb = nb_min; + if (nb > nb_max) + continue; + + fvco = fin / ((double)nrx) * ((double)nfx); + if (fvco < vco_min) + continue; + if (fvco > vco_max) + continue; + if (nf < nf_min) + continue; + if ((ref_rng) && (fin / ((double)nrx) < ref_min)) + continue; + if ((ref_rng) && (nrx > nr_max)) + continue; + if (!(((firstx) && (terr < 0)) || (fabs(err) < merr * (1 - 1e-6)) || ((max_vco) && (no > x_no)))) + continue; + if ((!firstx) && (terr >= 0) && (nrx > x_nrx)) + continue; + + found = 1; + x_no = no; + x_nrx = nrx; + x_nfx = nfx; + x_nb = nb; + x_fvco = fvco; + x_err = err; + first = firstx = 0; + merr = fabs(err); + if (terr != -1) + continue; + } + } + if (!found) + { + return 0; + } + + nrx = x_nrx; + nfx = x_nfx; + no = x_no; + nb = x_nb; + fvco = x_fvco; + err = x_err; + if ((terr != -2) && (fabs(err) >= terr * (1 - 1e-6))) + { + return 0; + } + + /* + * Begin write PLL registers' value, + * Using atomic write method. + */ + sysctl_pll0_t pll0; + sysctl_pll1_t pll1; + sysctl_pll2_t pll2; + + switch (pll) + { + case SYSCTL_PLL0: + /* Read register from bus */ + pll0 = sysctl->pll0; + /* Set register temporary value */ + pll0.clkr0 = nrx - 1; + pll0.clkf0 = nfx - 1; + pll0.clkod0 = no - 1; + pll0.bwadj0 = nb - 1; + /* Write register back to bus */ + sysctl->pll0 = pll0; + break; + + case SYSCTL_PLL1: + /* Read register from bus */ + pll1 = sysctl->pll1; + /* Set register temporary value */ + pll1.clkr1 = nrx - 1; + pll1.clkf1 = nfx - 1; + pll1.clkod1 = no - 1; + pll1.bwadj1 = nb - 1; + /* Write register back to bus */ + sysctl->pll1 = pll1; + break; + + case SYSCTL_PLL2: + /* Read register from bus */ + pll2 = sysctl->pll2; + /* Set register temporary value */ + if (source < sizeof(get_select_pll2)) + pll2.pll_ckin_sel2 = get_select_pll2[source]; + + pll2.clkr2 = nrx - 1; + pll2.clkf2 = nfx - 1; + pll2.clkod2 = no - 1; + pll2.bwadj2 = nb - 1; + /* Write register back to bus */ + sysctl->pll2 = pll2; + break; + + default: + return 0; + } + + return sysctl_pll_get_freq(pll); +} + +uint32_t SysctlClockGetFreq(sysctl_clock_t clock) +{ + uint32_t source = 0; + uint32_t result = 0; + + switch (clock) + { + /* + * The clock IN0 + */ + case SYSCTL_CLOCK_IN0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source; + break; + + /* + * These clock directly under PLL clock domain + * They are using gated divider. + */ + case SYSCTL_CLOCK_PLL0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source; + break; + case SYSCTL_CLOCK_PLL1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL1); + result = source; + break; + case SYSCTL_CLOCK_PLL2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source; + break; + + /* + * These clock directly under ACLK clock domain + */ + case SYSCTL_CLOCK_CPU: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_DMA: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_FFT: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_ACLK: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_HCLK: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + + /* + * These clock under ACLK clock domain. + * They are using gated divider. + */ + case SYSCTL_CLOCK_SRAM0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SRAM0) + 1); + break; + case SYSCTL_CLOCK_SRAM1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SRAM1) + 1); + break; + case SYSCTL_CLOCK_ROM: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ROM) + 1); + break; + case SYSCTL_CLOCK_DVP: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_DVP) + 1); + break; + + /* + * These clock under ACLK clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_APB0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB0) + 1); + break; + case SYSCTL_CLOCK_APB1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB1) + 1); + break; + case SYSCTL_CLOCK_APB2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB2) + 1); + break; + + /* + * These clock under AI clock domain. + * They are using gated divider. + */ + case SYSCTL_CLOCK_AI: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL1); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_AI) + 1); + break; + + /* + * These clock under I2S clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_I2S0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S0) + 1) * 2); + break; + case SYSCTL_CLOCK_I2S1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S1) + 1) * 2); + break; + case SYSCTL_CLOCK_I2S2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S2) + 1) * 2); + break; + + /* + * These clock under WDT clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_WDT0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_WDT0) + 1) * 2); + break; + case SYSCTL_CLOCK_WDT1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_WDT1) + 1) * 2); + break; + + /* + * These clock under PLL0 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_SPI0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI0) + 1) * 2); + break; + case SYSCTL_CLOCK_SPI1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI1) + 1) * 2); + break; + case SYSCTL_CLOCK_SPI2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI2) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C0) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C1) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C2) + 1) * 2); + break; + + /* + * These clock under PLL0_SEL clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_SPI3: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_SPI3)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI3) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER0: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER0)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER0) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER1: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER1)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER1) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER2: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER2)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER2) + 1) * 2); + break; + + /* + * These clock under MISC clock domain. + * They are using even divider. + */ + + /* + * These clock under APB0 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_GPIO: + source = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART1: + source = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART2: + source = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART3: + source = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_FPIOA: + source = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_SHA: + source = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + result = source; + break; + + /* + * These clock under APB1 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_AES: + source = SysctlClockGetFreq(SYSCTL_CLOCK_APB1); + result = source; + break; + case SYSCTL_CLOCK_OTP: + source = SysctlClockGetFreq(SYSCTL_CLOCK_APB1); + result = source; + break; + case SYSCTL_CLOCK_RTC: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source; + break; + + /* + * These clock under APB2 clock domain. + * They are using even divider. + */ + /* + * Do nothing. + */ + default: + break; + } + return result; +} + +int sysctl_dma_select(sysctl_dma_channel_t channel, sysctl_dma_select_t select) +{ + sysctl_dma_sel0_t dma_sel0; + sysctl_dma_sel1_t dma_sel1; + + /* Read register from bus */ + dma_sel0 = sysctl->dma_sel0; + dma_sel1 = sysctl->dma_sel1; + switch (channel) + { + case SYSCTL_DMA_CHANNEL_0: + dma_sel0.dma_sel0 = select; + break; + + case SYSCTL_DMA_CHANNEL_1: + dma_sel0.dma_sel1 = select; + break; + + case SYSCTL_DMA_CHANNEL_2: + dma_sel0.dma_sel2 = select; + break; + + case SYSCTL_DMA_CHANNEL_3: + dma_sel0.dma_sel3 = select; + break; + + case SYSCTL_DMA_CHANNEL_4: + dma_sel0.dma_sel4 = select; + break; + + case SYSCTL_DMA_CHANNEL_5: + dma_sel1.dma_sel5 = select; + break; + + default: + return -1; + } + + /* Write register back to bus */ + sysctl->dma_sel0 = dma_sel0; + sysctl->dma_sel1 = dma_sel1; + + return 0; +} + +uint32_t sysctl_pll_fast_enable_pll(void) +{ + /* + * Begin write PLL registers' value, + * Using atomic write method. + */ + sysctl_pll0_t pll0; + sysctl_pll1_t pll1; + sysctl_pll2_t pll2; + + /* Read register from bus */ + pll0 = sysctl->pll0; + pll1 = sysctl->pll1; + pll2 = sysctl->pll2; + + /* PLL VCO MAX freq: 1.8GHz */ + + /* PLL0: 26M reference clk get 793M output clock */ + pll0.clkr0 = 0; + pll0.clkf0 = 60; + pll0.clkod0 = 1; + pll0.bwadj0 = 60; + + /* PLL1: 26M reference clk get 390M output clock */ + pll1.clkr1 = 0; + pll1.clkf1 = 59; + pll1.clkod1 = 3; + pll1.bwadj1 = 59; + + /* PLL2: 26M reference clk get 390M output clock */ + pll2.clkr2 = 0; + pll2.clkf2 = 59; + pll2.clkod2 = 3; + pll2.bwadj2 = 59; + + /* Write register to bus */ + sysctl->pll0 = pll0; + sysctl->pll1 = pll1; + sysctl->pll2 = pll2; + + sysctl_pll_enable(SYSCTL_PLL0); + sysctl_pll_enable(SYSCTL_PLL1); + sysctl_pll_enable(SYSCTL_PLL2); + + while (sysctl_pll_is_lock(SYSCTL_PLL0) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL0); + while (sysctl_pll_is_lock(SYSCTL_PLL1) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL1); + while (sysctl_pll_is_lock(SYSCTL_PLL2) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL2); + + sysctl_clock_enable(SYSCTL_CLOCK_PLL0); + sysctl_clock_enable(SYSCTL_CLOCK_PLL1); + sysctl_clock_enable(SYSCTL_CLOCK_PLL2); + + /* Set ACLK to PLL0 */ + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0); + + return 0; +} + +uint32_t sysctl_set_spi0_dvp_data(uint8_t en) +{ + sysctl->misc.spi_dvp_data_enable = en; + return 0; +} + +void sysctl_set_power_mode(sysctl_power_bank_t power_bank, sysctl_io_power_mode_t io_power_mode) +{ + if(io_power_mode) + *((uint32_t *)(&sysctl->power_sel)) |= (1 << power_bank); + else + *((uint32_t *)(&sysctl->power_sel)) &= ~(1 << power_bank); +} + +uint32_t SysctlPllSetFreq(sysctl_pll_t pll, uint32_t pll_freq) +{ + if(pll_freq == 0) + return 0; + + volatile sysctl_general_pll_t *v_pll_t; + switch(pll) + { + case SYSCTL_PLL0: + v_pll_t = (sysctl_general_pll_t *)(&sysctl->pll0); + break; + case SYSCTL_PLL1: + v_pll_t = (sysctl_general_pll_t *)(&sysctl->pll1); + break; + case SYSCTL_PLL2: + v_pll_t = (sysctl_general_pll_t *)(&sysctl->pll2); + break; + default: + return 0; + break; + } + + /* 1. Change CPU CLK to XTAL */ + if(pll == SYSCTL_PLL0) + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_IN0); + + /* 2. Disable PLL output */ + v_pll_t->pll_out_en = 0; + + /* 3. Turn off PLL */ + v_pll_t->pll_pwrd = 0; + + /* 4. Set PLL new value */ + uint32_t result; + if(pll == SYSCTL_PLL2) + result = sysctl_pll_source_set_freq(pll, v_pll_t->pll_ckin_sel, pll_freq); + else + result = sysctl_pll_source_set_freq(pll, SYSCTL_SOURCE_IN0, pll_freq); + + /* 5. Power on PLL */ + v_pll_t->pll_pwrd = 1; + /* wait >100ns */ + usleep(1); + + /* 6. Reset PLL then Release Reset*/ + v_pll_t->pll_reset = 0; + v_pll_t->pll_reset = 1; + /* wait >100ns */ + usleep(1); + v_pll_t->pll_reset = 0; + + /* 7. Get lock status, wait PLL stable */ + while (sysctl_pll_is_lock(pll) == 0) + sysctl_pll_clear_slip(pll); + + /* 8. Enable PLL output */ + v_pll_t->pll_out_en = 1; + + /* 9. Change CPU CLK to PLL */ + if(pll == SYSCTL_PLL0) + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0); + + return result; +} + +static uint32_t cpu_freq = 390000000; + +uint32_t sysctl_cpu_get_freq(void) +{ + return cpu_freq; +} + +uint32_t sysctl_cpu_set_freq(uint32_t freq) +{ + if(freq == 0) + return 0; + + cpu_freq = SysctlPllSetFreq(SYSCTL_PLL0, (sysctl->clk_sel0.aclk_divider_sel + 1) * 2 * freq); + return cpu_freq; +} + +void sysctl_enable_irq(void) +{ + SET_CSR(mie, MIP_MEIP); + SET_CSR(mstatus, MSTATUS_MIE); +} + +void sysctl_disable_irq(void) +{ + CLEAR_CSR(mie, MIP_MEIP); + CLEAR_CSR(mstatus, MSTATUS_MIE); +} + +uint64_t sysctl_get_time_us(void) +{ + uint64_t v_cycle = read_cycle(); + return v_cycle * 1000000 / SysctlClockGetFreq(SYSCTL_CLOCK_CPU); +} + +sysctl_reset_enum_status_t sysctl_get_reset_status(void) +{ + static sysctl_reset_enum_status_t s_reset_status = 0; + if(s_reset_status != 0) + { + return s_reset_status; + } + + if(sysctl->reset_status.wdt0_reset_sts) + { + s_reset_status = SYSCTL_RESET_STATUS_WDT0; + } + else if(sysctl->reset_status.wdt1_reset_sts) + { + s_reset_status = SYSCTL_RESET_STATUS_WDT1; + } + else if(sysctl->reset_status.soft_reset_sts) + { + s_reset_status = SYSCTL_RESET_STATUS_SOFT; + } + else + { + s_reset_status = SYSCTL_RESET_STATUS_HARD; + } + sysctl->reset_status.reset_sts_clr = 1; + + return s_reset_status; +} + diff --git a/board/k210-emulator/third_party_driver/timer/Kconfig b/board/k210-emulator/third_party_driver/timer/Kconfig new file mode 100644 index 00000000..fdc67b1a --- /dev/null +++ b/board/k210-emulator/third_party_driver/timer/Kconfig @@ -0,0 +1,19 @@ +if BSP_USING_HWTIMER + config HWTIMER_BUS_NAME_1 + string "hwtimer bus name" + default "hwtim1" + + menuconfig ENABLE_TIM1 + bool "enable TIM1" + default y + + if ENABLE_TIM1 + config HWTIMER_1_DEVICE_NAME_1 + string "TIM1 dev name" + default "hwtim1_dev1" + + config HWTIMER_DRIVER_NAME_1 + string "TIM1 drv name" + default "hwtim1_drv" + endif +endif diff --git a/board/k210-emulator/third_party_driver/timer/Makefile b/board/k210-emulator/third_party_driver/timer/Makefile new file mode 100644 index 00000000..06b6e3a8 --- /dev/null +++ b/board/k210-emulator/third_party_driver/timer/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := hardware_hwtimer.c connect_hwtimer.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/timer/connect_hwtimer.c b/board/k210-emulator/third_party_driver/timer/connect_hwtimer.c new file mode 100644 index 00000000..0ad05490 --- /dev/null +++ b/board/k210-emulator/third_party_driver/timer/connect_hwtimer.c @@ -0,0 +1,155 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_hwtimer.c +* @brief support kd233-board hwtimer function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "connect_hwtimer.h" + +static struct HwtimerCallBackInfo *ptim2_cb_info = NULL; + +int timer_callback(void *ctx) +{ + if (ptim2_cb_info) { + if (ptim2_cb_info->timeout_callback) { + ptim2_cb_info->timeout_callback(ptim2_cb_info->param); + } + } + return 0; +} + +uint32 HwtimerOpen(void *dev) +{ + struct HwtimerHardwareDevice *hwtimer_dev = dev; + + ptim2_cb_info = &hwtimer_dev->hwtimer_param.cb_info; + + plic_init(); + sysctl_enable_irq(); + timer_init(TIMER_DEVICE_1); + + size_t real_time = timer_set_interval(TIMER_DEVICE_1, TIMER_CHANNEL_1, hwtimer_dev->hwtimer_param.period_millisecond *1000); + KPrintf("timer_set_interval -- real_time : %ld\n", real_time); + timer_irq_register(TIMER_DEVICE_1, TIMER_CHANNEL_1, !hwtimer_dev->hwtimer_param.repeat, 1, timer_callback, NULL); + + timer_set_enable(TIMER_DEVICE_1, TIMER_CHANNEL_1, 1); + + return EOK; +} + +uint32 HwtimerClose(void *dev) +{ + timer_set_enable(TIMER_DEVICE_1, TIMER_CHANNEL_1, 0); + + return EOK; +} + +/*manage the hwtimer device operations*/ +static const struct HwtimerDevDone dev_done = +{ + .open = HwtimerOpen, + .close = HwtimerClose, + .write = NONE, + .read = NONE, +}; + +/*Init hwtimer bus*/ +static int BoardHwtimerBusInit(struct HwtimerBus *hwtimer_bus, struct HwtimerDriver *hwtimer_driver) +{ + x_err_t ret = EOK; + + /*Init the hwtimer bus */ + ret = HwtimerBusInit(hwtimer_bus, HWTIMER_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_hwtimer_init HwtimerBusInit error %d\n", ret); + return ERROR; + } + + /*Init the hwtimer driver*/ + hwtimer_driver->configure = NONE; + ret = HwtimerDriverInit(hwtimer_driver, HWTIMER_DRIVER_NAME_1); + if (EOK != ret) { + KPrintf("board_hwtimer_init HwtimerDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the hwtimer driver to the hwtimer bus*/ + ret = HwtimerDriverAttachToBus(HWTIMER_DRIVER_NAME_1, HWTIMER_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_hwtimer_init USEDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the hwtimer device to the hwtimer bus*/ +static int BoardHwtimerDevBend(void) +{ + x_err_t ret = EOK; + static struct HwtimerHardwareDevice hwtimer_device_0; + memset(&hwtimer_device_0, 0, sizeof(struct HwtimerHardwareDevice)); + + hwtimer_device_0.dev_done = &dev_done; + + ret = HwtimerDeviceRegister(&hwtimer_device_0, NONE, HWTIMER_1_DEVICE_NAME_1); + if (EOK != ret) { + KPrintf("board_hwtimer_init HWTIMERDeviceInit device %s error %d\n", HWTIMER_1_DEVICE_NAME_1, ret); + return ERROR; + } + + ret = HwtimerDeviceAttachToBus(HWTIMER_1_DEVICE_NAME_1, HWTIMER_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_hwtimer_init HwtimerDeviceAttachToBus device %s error %d\n", HWTIMER_1_DEVICE_NAME_1, ret); + return ERROR; + } + + return ret; +} + +/*K210 BOARD HWTIMER INIT*/ +int HwTimerInit(void) +{ + x_err_t ret = EOK; + static struct HwtimerBus hwtimer_bus; + memset(&hwtimer_bus, 0, sizeof(struct HwtimerBus)); + + static struct HwtimerDriver hwtimer_driver; + memset(&hwtimer_driver, 0, sizeof(struct HwtimerDriver)); + + + ret = BoardHwtimerBusInit(&hwtimer_bus, &hwtimer_driver); + if (EOK != ret) { + KPrintf("board_hwtimer_Init error ret %u\n", ret); + return ERROR; + } + + ret = BoardHwtimerDevBend(); + if (EOK != ret) { + KPrintf("board_hwtimer_Init error ret %u\n", ret); + return ERROR; + } + + return ret; +} diff --git a/board/k210-emulator/third_party_driver/timer/hardware_hwtimer.c b/board/k210-emulator/third_party_driver/timer/hardware_hwtimer.c new file mode 100644 index 00000000..918fddb4 --- /dev/null +++ b/board/k210-emulator/third_party_driver/timer/hardware_hwtimer.c @@ -0,0 +1,406 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_hwtimer.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include "hardware_hwtimer.h" +#include "sysctl.h" +#include "stddef.h" +#include "utils.h" +#include "plic.h" +#include "io.h" +#include "xs_isr.h" +/** + * @brief Private definitions for the timer instance + */ +typedef struct timer_instance +{ + timer_callback_t callback; + void *ctx; + bool single_shot; +} timer_instance_t; + +typedef void(*irq_manager_callback_t)(int irq, void* arg); + +volatile timer_instance_t timer_instance[TIMER_DEVICE_MAX][TIMER_CHANNEL_MAX]; + +volatile kendryte_timer_t *const timer[3] = +{ + (volatile kendryte_timer_t *)TIMER0_BASE_ADDR, + (volatile kendryte_timer_t *)TIMER1_BASE_ADDR, + (volatile kendryte_timer_t *)TIMER2_BASE_ADDR +}; + +void timer_init(timer_device_number_t timer_number) +{ + for(size_t i = 0; i < TIMER_CHANNEL_MAX; i++) + timer_instance[timer_number][i] = (const timer_instance_t) { + .callback = NULL, + .ctx = NULL, + .single_shot = 0, + }; + + sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + timer_number); +} + +void timer_set_clock_div(timer_device_number_t timer_number, uint32_t div) +{ + sysctl_clock_set_threshold(timer_number == 0 ? SYSCTL_THRESHOLD_TIMER0 : + timer_number == 1 ? SYSCTL_THRESHOLD_TIMER1 : + SYSCTL_THRESHOLD_TIMER2, div); +} + +void timer_enable(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_ENABLE; +} + +void timer_disable(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_ENABLE); +} + +void timer_enable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_PWM_ENABLE; +} + +void timer_disable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_PWM_ENABLE); +} + +void timer_enable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_INTERRUPT_MASK); +} + +void timer_disable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_INTERRUPT_MASK; +} + +void timer_set_mode(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t mode) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_MODE_MASK); + timer[timer_number]->channel[channel].control |= mode; +} + +void timer_set_reload(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count) +{ + timer[timer_number]->channel[channel].load_count = count; +} + +void timer_set_reload2(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count) +{ + timer[timer_number]->load_count2[channel] = count; +} + +uint32_t timer_get_count(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].current_value; +} + +uint32_t timer_get_reload(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].load_count; +} + +uint32_t timer_get_reload2(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->load_count2[channel]; +} + +uint32_t timer_get_interrupt_status(timer_device_number_t timer_number) +{ + return timer[timer_number]->intr_stat; +} + +uint32_t timer_get_raw_interrupt_status(timer_device_number_t timer_number) +{ + return timer[timer_number]->raw_intr_stat; +} + +uint32_t timer_channel_get_interrupt_status(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].intr_stat; +} + +void timer_clear_interrupt(timer_device_number_t timer_number) +{ + timer[timer_number]->eoi = timer[timer_number]->eoi; +} + +void timer_channel_clear_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].eoi = timer[timer_number]->channel[channel].eoi; +} + +void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable) +{ + if (enable) + timer[timer_number]->channel[channel].control = TIMER_CR_USER_MODE | TIMER_CR_ENABLE; + else + timer[timer_number]->channel[channel].control = TIMER_CR_INTERRUPT_MASK; +} + +size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t useconds) +{ + uint32_t clk_freq = SysctlClockGetFreq(SYSCTL_CLOCK_TIMER0 + timer_number); + + double min_step = 1e6 / clk_freq; + size_t value = (size_t)(useconds / min_step); + configASSERT(value > 0 && value < UINT32_MAX); + timer[timer_number]->channel[channel].load_count = (uint32_t)value; + return (size_t)(min_step * value); +} + +typedef void(*timer_ontick)(); +timer_ontick time_irq[3][4] = { NULL }; + +static int timer_isr(void *parm) +{ + uint32_t timer_number; + for (timer_number = 0; timer_number < 3; timer_number++) + { + if (parm == timer[timer_number]) + break; + } + + uint32_t channel = timer[timer_number]->intr_stat; + size_t i = 0; + for (i = 0; i < 4; i++) + { + if (channel & 1) + { + if (time_irq[timer_number][i]) + (time_irq[timer_number][i])(); + break; + } + + channel >>= 1; + } + + readl(&timer[timer_number]->eoi); + return 0; +} + +void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority) +{ + time_irq[timer_number][channel] = func; + if (channel < 2) + { + plic_set_priority(IRQN_TIMER0A_INTERRUPT + timer_number * 2, priority); + plic_irq_register(IRQN_TIMER0A_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]); + plic_irq_enable(IRQN_TIMER0A_INTERRUPT + timer_number * 2); + } + else + { + plic_set_priority(IRQN_TIMER0B_INTERRUPT + timer_number * 2, priority); + plic_irq_register(IRQN_TIMER0B_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]); + plic_irq_enable(IRQN_TIMER0B_INTERRUPT + timer_number * 2); + } +} + +/** + * @brief Get the timer irqn by device and channel object + * + * @note Internal function, not public + * @param device The device + * @param channel The channel + * @return plic_irq_t IRQ number + */ +static plic_irq_t get_timer_irqn_by_device_and_channel(timer_device_number_t device, timer_channel_number_t channel) +{ + if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) { + /* + * Select timer interrupt part + * Hierarchy of Timer interrupt to PLIC + * +---------+ +-----------+ + * | 0+----+ | | + * | | +--+0A | + * | 1+----+ | | + * | TIMER0 | | | + * | 2+----+ | | + * | | +--+0B | + * | 3+----+ | | + * +---------+ | | + * | | + * +---------+ | | + * | 0+----+ | | + * | | +--+1A | + * | 1+----+ | | + * | TIMER1 | | PLIC | + * | 2+----+ | | + * | | +--+1B | + * | 3+----+ | | + * +---------+ | | + * | | + * +---------+ | | + * | 0+----+ | | + * | | +--+2A | + * | 1+----+ | | + * | TIMER2 | | | + * | 2+----+ | | + * | | +--+2B | + * | 3+----+ | | + * +---------+ +-----------+ + * + */ + if (channel < 2) { + /* It is part A interrupt, offset + 0 */ + return IRQN_TIMER0A_INTERRUPT + device * 2; + } + else { + /* It is part B interrupt, offset + 1 */ + return IRQN_TIMER0B_INTERRUPT + device * 2; + } + } + return IRQN_NO_INTERRUPT; +} + +/** + * @brief Process user callback function + * + * @note Internal function, not public + * @param device The timer device + * @param ctx The context + * @return int The callback result + */ +static int timer_interrupt_handler(timer_device_number_t device, void *ctx) +{ + uint32_t channel_int_stat = timer[device]->intr_stat; + + for (size_t i = 0; i < TIMER_CHANNEL_MAX; i++) + { + /* Check every bit for interrupt status */ + if (channel_int_stat & 1) + { + if (timer_instance[device][i].callback) { + /* Process user callback function */ + timer_instance[device][i].callback(timer_instance[device][i].ctx); + /* Check if this timer is a single shot timer */ + if (timer_instance[device][i].single_shot) { + /* Single shot timer, disable it */ + timer_set_enable(device, i, 0); + } + } + /* Clear timer interrupt flag for specific channel */ + readl(&timer[device]->channel[i].eoi); + } + channel_int_stat >>= 1; + } + + /* + * NOTE: + * Don't read timer[device]->eoi here, or you will lost some interrupt + * readl(&timer[device]->eoi); + */ + + return 0; +} + +/** + * @brief Callback function bus for timer interrupt + * + * @note Internal function, not public + * @param ctx The context + * @return int The callback result + */ +static void timer0_interrupt_callback(int irq, void *ctx) +{ + timer_interrupt_handler(TIMER_DEVICE_0, ctx); +} + +/** + * @brief Callback function bus for timer interrupt + * + * @note Internal function, not public + * @param ctx The context + * @return int The callback result + */ +static void timer1_interrupt_callback(int irq, void *ctx) +{ + timer_interrupt_handler(TIMER_DEVICE_1, ctx); +} + +/** + * @brief Callback function bus for timer interrupt + * + * @note Internal function, not public + * @param ctx The context + * @return int The callback result + */ +static void timer2_interrupt_callback(int irq, void *ctx) +{ + timer_interrupt_handler(TIMER_DEVICE_2, ctx); +} + +int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx) +{ + if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) { + plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel); + irq_manager_callback_t plic_irq_callback[TIMER_DEVICE_MAX] = { + timer0_interrupt_callback, + timer1_interrupt_callback, + timer2_interrupt_callback, + }; + + timer_instance[device][channel] = (const timer_instance_t) { + .callback = callback, + .ctx = ctx, + .single_shot = is_single_shot, + }; + + // plic_set_priority(irq_number, priority); + // plic_irq_register(irq_number, plic_irq_callback[device], (void *)&timer_instance[device]); + // plic_irq_enable(irq_number); + + isrManager.done->registerIrq(irq_number, plic_irq_callback[device], NULL); + isrManager.done->enableIrq(irq_number); + return 0; + } + return -1; +} + +int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel) +{ + if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) { + timer_instance[device][channel] = (const timer_instance_t) { + .callback = NULL, + .ctx = NULL, + .single_shot = 0, + }; + + /* Combine 0 and 1 to A interrupt, 2 and 3 to B interrupt */ + if ((!(timer_instance[device][TIMER_CHANNEL_0].callback || + timer_instance[device][TIMER_CHANNEL_1].callback)) || + (!(timer_instance[device][TIMER_CHANNEL_2].callback || + timer_instance[device][TIMER_CHANNEL_3].callback))) { + plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel); + plic_irq_unregister(irq_number); + } + return 0; + } + return -1; +} \ No newline at end of file diff --git a/board/k210-emulator/third_party_driver/uart/Kconfig b/board/k210-emulator/third_party_driver/uart/Kconfig new file mode 100644 index 00000000..08e75e06 --- /dev/null +++ b/board/k210-emulator/third_party_driver/uart/Kconfig @@ -0,0 +1,77 @@ +menuconfig BSP_USING_UART_HS + bool "Enable High Speed UART" + default y + if BSP_USING_UART_HS + config SERIAL_BUS_NAME_0 + string "serial high speed bus 0 name" + default "uart0" + config SERIAL_DRV_NAME_0 + string "serial high speed bus 0 driver name" + default "uart0_drv" + config SERIAL_0_DEVICE_NAME_0 + string "serial high speed bus 0 device 0 name" + default "uart0_dev0" + endif + +menuconfig BSP_USING_UART1 + bool "Enable UART1" + default y + if BSP_USING_UART1 + config BSP_UART1_TXD_PIN + int "uart1 TXD pin number" + default 20 + config BSP_UART1_RXD_PIN + int "uart1 RXD pin number" + default 21 + config SERIAL_BUS_NAME_1 + string "serial bus 1 name" + default "uart1" + config SERIAL_DRV_NAME_1 + string "serial bus 1 driver name" + default "uart1_drv" + config SERIAL_1_DEVICE_NAME_0 + string "serial bus 1 device 0 name" + default "uart1_dev1" + endif + +menuconfig BSP_USING_UART2 + bool "Enable UART2" + default y + if BSP_USING_UART2 + config BSP_UART2_TXD_PIN + int "uart2 TXD pin number" + default 28 + config BSP_UART2_RXD_PIN + int "uart2 RXD pin number" + default 27 + config SERIAL_BUS_NAME_2 + string "serial bus 2 name" + default "uart2" + config SERIAL_DRV_NAME_2 + string "serial bus 2 driver name" + default "uart2_drv" + config SERIAL_2_DEVICE_NAME_0 + string "serial bus 2 device 0 name" + default "uart2_dev2" + endif + +menuconfig BSP_USING_UART3 + bool "Enable UART3" + default y + if BSP_USING_UART3 + config BSP_UART3_TXD_PIN + int "uart3 TXD pin number" + default 22 + config BSP_UART3_RXD_PIN + int "uart3 RXD pin number" + default 23 + config SERIAL_BUS_NAME_3 + string "serial bus 3 name" + default "uart3" + config SERIAL_DRV_NAME_3 + string "serial bus 3 driver name" + default "uart3_drv" + config SERIAL_3_DEVICE_NAME_0 + string "serial bus 3 device 0 name" + default "uart3_dev3" + endif diff --git a/board/k210-emulator/third_party_driver/uart/Makefile b/board/k210-emulator/third_party_driver/uart/Makefile new file mode 100644 index 00000000..7696ffaa --- /dev/null +++ b/board/k210-emulator/third_party_driver/uart/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := connect_uart.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/uart/connect_uart.c b/board/k210-emulator/third_party_driver/uart/connect_uart.c new file mode 100644 index 00000000..ae5274cc --- /dev/null +++ b/board/k210-emulator/third_party_driver/uart/connect_uart.c @@ -0,0 +1,653 @@ +/* + * Copyright (c) 2020 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +/** +* @file connect_uart.c +* @brief support kd233-board uart function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: connect_uart.c +Description: support kd233-board uart configure and uart bus register function +Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_uart.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. support kd233-board uart configure, write and read +2. support kd233-board uart bus device and driver register +*************************************************/ + +#include +#include +#include "plic.h" +#include "connect_uart.h" +#include "hardware_uart.h" +#include "hardware_uarths.h" + +static volatile UarthsT *const _uarths = (volatile UarthsT *)UARTHS_BASE_ADDR; + +/* START ported from kendryte standalone sdk uart.c */ +#define __UART_BRATE_CONST 16 + +volatile UartT* const _uart_new[3] = +{ + (volatile UartT*)UART1_BASE_ADDR, + (volatile UartT*)UART2_BASE_ADDR, + (volatile UartT*)UART3_BASE_ADDR +}; + +void _uart_init_new(UartDeviceNumberT channel) +{ + sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel); + sysctl_reset(SYSCTL_RESET_UART1 + channel); +} + +/* END ported from kendryte standalone sdk uart.c */ +static inline UartDeviceNumberT GetUartChannel(uint32 addr) +{ + switch (addr) + { + case UART1_BASE_ADDR: + return UART_DEVICE_1; + case UART2_BASE_ADDR: + return UART_DEVICE_2; + case UART3_BASE_ADDR: + return UART_DEVICE_3; + default: + return UART_DEVICE_MAX; + } +} + +extern void SerialSetIsr(struct SerialHardwareDevice *serial_dev, int event); + +static void SerialCfgParamCheck(struct SerialCfgParam *serial_cfg_default, struct SerialCfgParam *serial_cfg_new) +{ + struct SerialDataCfg *data_cfg_default = &serial_cfg_default->data_cfg; + struct SerialDataCfg *data_cfg_new = &serial_cfg_new->data_cfg; + + if ((data_cfg_default->serial_baud_rate != data_cfg_new->serial_baud_rate) && (data_cfg_new->serial_baud_rate)) { + data_cfg_default->serial_baud_rate = data_cfg_new->serial_baud_rate; + } + + if ((data_cfg_default->serial_bit_order != data_cfg_new->serial_bit_order) && (data_cfg_new->serial_bit_order)) { + data_cfg_default->serial_bit_order = data_cfg_new->serial_bit_order; + } + + if ((data_cfg_default->serial_buffer_size != data_cfg_new->serial_buffer_size) && (data_cfg_new->serial_buffer_size)) { + data_cfg_default->serial_buffer_size = data_cfg_new->serial_buffer_size; + } + + if ((data_cfg_default->serial_data_bits != data_cfg_new->serial_data_bits) && (data_cfg_new->serial_data_bits)) { + data_cfg_default->serial_data_bits = data_cfg_new->serial_data_bits; + } + + if ((data_cfg_default->serial_invert_mode != data_cfg_new->serial_invert_mode) && (data_cfg_new->serial_invert_mode)) { + data_cfg_default->serial_invert_mode = data_cfg_new->serial_invert_mode; + } + + if ((data_cfg_default->serial_parity_mode != data_cfg_new->serial_parity_mode) && (data_cfg_new->serial_parity_mode)) { + data_cfg_default->serial_parity_mode = data_cfg_new->serial_parity_mode; + } + + if ((data_cfg_default->serial_stop_bits != data_cfg_new->serial_stop_bits) && (data_cfg_new->serial_stop_bits)) { + data_cfg_default->serial_stop_bits = data_cfg_new->serial_stop_bits; + } +} + +/* UARTHS ISR */ +static void UarthsIrqHandler(int irqno, void *param) +{ + struct SerialBus *serial_bus = (struct SerialBus *)param; + struct SerialDriver *serial_drv = (struct SerialDriver *)serial_bus->bus.owner_driver; + struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)serial_bus->bus.owner_haldev; + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data; + CHECK(UARTHS_BASE_ADDR == serial_cfg->hw_cfg.serial_register_base); + + /* read interrupt status and clear it */ + if(_uarths->ip.rxwm) + SerialSetIsr(serial_dev, SERIAL_EVENT_RX_IND); +} + +/* UART ISR */ +static void UartIrqHandler(int irqno, void *param) +{ + struct SerialBus *serial_bus = (struct SerialBus *)param; + struct SerialDriver *serial_drv = (struct SerialDriver *)serial_bus->bus.owner_driver; + struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)serial_bus->bus.owner_haldev; + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data; + + UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base); + CHECK(channel != UART_DEVICE_MAX); + + /* read interrupt status and clear it */ + if(_uart_new[channel]->LSR) + SerialSetIsr(serial_dev, SERIAL_EVENT_RX_IND); +} + +static uint32 SerialHsInit(struct SerialDriver *serial_drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(serial_drv); + + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data; + + if (configure_info->private_data) { + struct SerialCfgParam *serial_cfg_new = (struct SerialCfgParam *)configure_info->private_data; + SerialCfgParamCheck(serial_cfg, serial_cfg_new); + } + + //uint32 freq_hs = SysctlClockGetFreq(SYSCTL_CLOCK_CPU); + uint32 freq_hs = 26000000; + uint16 div_hs = freq_hs / serial_cfg->data_cfg.serial_baud_rate - 1; + + if (UARTHS_BASE_ADDR == serial_cfg->hw_cfg.serial_register_base) { + _uarths->div.div = div_hs; + _uarths->txctrl.txen = 1; + _uarths->rxctrl.rxen = 1; + _uarths->txctrl.txcnt = 0; + _uarths->rxctrl.rxcnt = 0; + _uarths->ip.txwm = 1; + _uarths->ip.rxwm = 1; + _uarths->ie.txwm = 0; + _uarths->ie.rxwm = 1; + } else { + KPrintf("SerialHsInit error base 0x%x\n", serial_cfg->hw_cfg.serial_register_base); + return ERROR; + } + + return EOK; +} + +static uint32 SerialHsConfigure(struct SerialDriver *serial_drv, int serial_operation_cmd) +{ + NULL_PARAM_CHECK(serial_drv); + + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data; + struct SerialBus *serial_bus = CONTAINER_OF(serial_drv->driver.owner_bus, struct SerialBus, bus); + + switch (serial_operation_cmd) + { + case OPER_CLR_INT: + isrManager.done->disableIrq(serial_cfg->hw_cfg.serial_irq_interrupt); + break; + case OPER_SET_INT: + isrManager.done->registerIrq(serial_cfg->hw_cfg.serial_irq_interrupt, UarthsIrqHandler, serial_bus); + isrManager.done->enableIrq(serial_cfg->hw_cfg.serial_irq_interrupt); + break; + } + + return EOK; +} + +static int SerialHsPutChar(struct SerialHardwareDevice *serial_dev, char c) +{ + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data; + CHECK(serial_cfg->hw_cfg.serial_register_base == UARTHS_BASE_ADDR); + + while (_uarths->txdata.full); + _uarths->txdata.data = (uint8)c; + + return EOK; +} + +static int SerialHsGetChar(struct SerialHardwareDevice *serial_dev) +{ + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data; + CHECK(serial_cfg->hw_cfg.serial_register_base == UARTHS_BASE_ADDR); + + uarths_rxdata_t recv = _uarths->rxdata; + if (recv.empty) + return -ERROR; + else + return (recv.data & 0xff); + + return -ERROR; +} + +static uint32 SerialInit(struct SerialDriver *serial_drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(serial_drv); + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data; + + if (configure_info->private_data) { + struct SerialCfgParam *serial_cfg_new = (struct SerialCfgParam *)configure_info->private_data; + SerialCfgParamCheck(serial_cfg, serial_cfg_new); + } + + UartBitwidthPointer DataWidth = (UartBitwidthPointer)serial_cfg->data_cfg.serial_data_bits; + UartStopbitT stopbit = (UartStopbitT)(serial_cfg->data_cfg.serial_stop_bits - 1); + UartParityT parity = (UartParityT)(serial_cfg->data_cfg.serial_parity_mode - 1); + + uint32 freq = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + uint32 divisor = freq / (uint32)serial_cfg->data_cfg.serial_baud_rate; + uint8 dlh = divisor >> 12; + uint8 dll = (divisor - (dlh << 12)) / __UART_BRATE_CONST; + uint8 dlf = divisor - (dlh << 12) - dll * __UART_BRATE_CONST; + + UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base); + CHECK(channel != UART_DEVICE_MAX); + + CHECK(DataWidth >= 5 && DataWidth <= 8); + if (DataWidth == 5) { + CHECK(stopbit != UART_STOP_2); + } else { + CHECK(stopbit != UART_STOP_1_5); + } + + uint32 stopbit_val = stopbit == UART_STOP_1 ? 0 : 1; + uint32 ParityVal; + switch (parity) + { + case UART_PARITY_NONE: + ParityVal = 0; + break; + case UART_PARITY_ODD: + ParityVal = 1; + break; + case UART_PARITY_EVEN: + ParityVal = 3; + break; + default: + CHECK(!"Invalid parity"); + break; + } + + _uart_new[channel]->LCR |= 1u << 7; + _uart_new[channel]->DLH = dlh; + _uart_new[channel]->DLL = dll; + _uart_new[channel]->DLF = dlf; + _uart_new[channel]->LCR = 0; + _uart_new[channel]->LCR = (DataWidth - 5) | + (stopbit_val << 2) | + (ParityVal << 3); + _uart_new[channel]->LCR &= ~(1u << 7); + _uart_new[channel]->IER |= 0x80; /* THRE */ + _uart_new[channel]->FCR = UART_RECEIVE_FIFO_1 << 6 | + UART_SEND_FIFO_8 << 4 | + 0x1 << 3 | + 0x1; + + return EOK; +} + +static uint32 SerialConfigure(struct SerialDriver *serial_drv, int serial_operation_cmd) +{ + NULL_PARAM_CHECK(serial_drv); + + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data; + struct SerialBus *serial_bus = CONTAINER_OF(serial_drv->driver.owner_bus, struct SerialBus, bus); + + UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base); + CHECK(channel != UART_DEVICE_MAX); + + switch (serial_operation_cmd) + { + case OPER_CLR_INT: + /* Disable the UART Interrupt */ + isrManager.done->disableIrq(serial_cfg->hw_cfg.serial_irq_interrupt); + _uart_new[channel]->IER &= ~0x1; + break; + case OPER_SET_INT: + /* install interrupt */ + isrManager.done->registerIrq(serial_cfg->hw_cfg.serial_irq_interrupt, UartIrqHandler, serial_bus); + isrManager.done->enableIrq(serial_cfg->hw_cfg.serial_irq_interrupt); + _uart_new[channel]->IER |= 0x1; + break; + } + + return EOK; +} + +static int SerialPutChar(struct SerialHardwareDevice *serial_dev, char c) +{ + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data; + UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base); + CHECK(channel != UART_DEVICE_MAX); + + while (_uart_new[channel]->LSR & (1u << 5)); + _uart_new[channel]->THR = c; + + return EOK; +} + +static int SerialGetChar(struct SerialHardwareDevice *serial_dev) +{ + struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data; + UartDeviceNumberT channel = GetUartChannel(serial_cfg->hw_cfg.serial_register_base); + CHECK(channel != UART_DEVICE_MAX); + + if (_uart_new[channel]->LSR & 1) + return (char)(_uart_new[channel]->RBR & 0xff); + else + return -ERROR; + + return -ERROR; +} + +static uint32 SerialHsDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + int serial_operation_cmd; + struct SerialDriver *serial_drv = (struct SerialDriver *)drv; + + switch (configure_info->configure_cmd) + { + case OPE_INT: + ret = SerialHsInit(serial_drv, configure_info); + break; + case OPE_CFG: + serial_operation_cmd = *((int *)configure_info->private_data); + ret = SerialHsConfigure(serial_drv, serial_operation_cmd); + break; + default: + break; + } + + return ret; +} + +static uint32 SerialDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + int serial_operation_cmd; + struct SerialDriver *serial_drv = (struct SerialDriver *)drv; + + switch (configure_info->configure_cmd) + { + case OPE_INT: + ret = SerialInit(serial_drv, configure_info); + break; + case OPE_CFG: + serial_operation_cmd = *(int *)configure_info->private_data; + ret = SerialConfigure(serial_drv, serial_operation_cmd); + break; + default: + break; + } + + return ret; +} + +static const struct SerialDataCfg data_cfg_init = +{ + .serial_baud_rate = BAUD_RATE_115200, + .serial_data_bits = DATA_BITS_8, + .serial_stop_bits = STOP_BITS_1, + .serial_parity_mode = PARITY_NONE, + .serial_bit_order = BIT_ORDER_LSB, + .serial_invert_mode = NRZ_NORMAL, + .serial_buffer_size = SERIAL_RB_BUFSZ, +}; + +/*manage the serial high speed device operations*/ +static const struct SerialDrvDone drv_done_hs = +{ + .init = SerialHsInit, + .configure = SerialHsConfigure, +}; + +/*manage the serial high speed device hal operations*/ +static struct SerialHwDevDone hwdev_done_hs = +{ + .put_char = SerialHsPutChar, + .get_char = SerialHsGetChar, +}; + +/*manage the serial device operations*/ +static const struct SerialDrvDone drv_done = +{ + .init = SerialInit, + .configure = SerialConfigure, +}; + +/*manage the serial device hal operations*/ +static struct SerialHwDevDone hwdev_done = +{ + .put_char = SerialPutChar, + .get_char = SerialGetChar, +}; + +static int BoardSerialBusInit(struct SerialBus *serial_bus, struct SerialDriver *serial_driver, const char *bus_name, const char *drv_name) +{ + x_err_t ret = EOK; + + /*Init the serial bus */ + ret = SerialBusInit(serial_bus, bus_name); + if (EOK != ret) { + KPrintf("hw_serial_init SerialBusInit error %d\n", ret); + return ERROR; + } + + /*Init the serial driver*/ + ret = SerialDriverInit(serial_driver, drv_name); + if (EOK != ret) { + KPrintf("hw_serial_init SerialDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the serial driver to the serial bus*/ + ret = SerialDriverAttachToBus(drv_name, bus_name); + if (EOK != ret) { + KPrintf("hw_serial_init SerialDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the serial device to the serial bus*/ +static int BoardSerialDevBend(struct SerialHardwareDevice *serial_device, void *serial_param, const char *bus_name, const char *dev_name) +{ + x_err_t ret = EOK; + + ret = SerialDeviceRegister(serial_device, serial_param, dev_name); + if (EOK != ret) { + KPrintf("hw_serial_init SerialDeviceInit device %s error %d\n", dev_name, ret); + return ERROR; + } + + ret = SerialDeviceAttachToBus(dev_name, bus_name); + if (EOK != ret) { + KPrintf("hw_serial_init SerialDeviceAttachToBus device %s error %d\n", dev_name, ret); + return ERROR; + } + + return ret; +} + +int HwUartInit(void) +{ + x_err_t ret = EOK; + +#ifdef BSP_USING_UART_HS + static struct SerialBus serial_bus_hs; + memset(&serial_bus_hs, 0, sizeof(struct SerialBus)); + + static struct SerialDriver serial_driver_hs; + memset(&serial_driver_hs, 0, sizeof(struct SerialDriver)); + + static struct SerialHardwareDevice serial_device_hs; + memset(&serial_device_hs, 0, sizeof(struct SerialHardwareDevice)); + + static struct SerialCfgParam serial_cfg_hs; + memset(&serial_cfg_hs, 0, sizeof(struct SerialCfgParam)); + + static struct SerialDevParam serial_dev_param_hs; + memset(&serial_dev_param_hs, 0, sizeof(struct SerialDevParam)); + + serial_driver_hs.drv_done = &drv_done_hs; + serial_driver_hs.configure = &SerialHsDrvConfigure; + serial_device_hs.hwdev_done = &hwdev_done_hs; + + serial_cfg_hs.data_cfg = data_cfg_init; + + serial_cfg_hs.hw_cfg.serial_register_base = UARTHS_BASE_ADDR; + serial_cfg_hs.hw_cfg.serial_irq_interrupt = IRQN_UARTHS_INTERRUPT; + serial_driver_hs.private_data = (void *)&serial_cfg_hs; + + serial_dev_param_hs.serial_work_mode = SIGN_OPER_INT_RX; + serial_device_hs.haldev.private_data = (void *)&serial_dev_param_hs; + + ret = BoardSerialBusInit(&serial_bus_hs, &serial_driver_hs, SERIAL_BUS_NAME_0, SERIAL_DRV_NAME_0); + if (EOK != ret) { + KPrintf("hw_serial_init uarths error ret %u\n", ret); + return ERROR; + } + + ret = BoardSerialDevBend(&serial_device_hs, (void *)&serial_cfg_hs, SERIAL_BUS_NAME_0, SERIAL_0_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("hw_serial_init uarths error ret %u\n", ret); + return ERROR; + } +#endif + +// #ifdef BSP_USING_UART1 +// static struct SerialBus serial_bus_1; +// memset(&serial_bus_1, 0, sizeof(struct SerialBus)); + +// static struct SerialDriver serial_driver_1; +// memset(&serial_driver_1, 0, sizeof(struct SerialDriver)); + +// static struct SerialHardwareDevice serial_device_1; +// memset(&serial_device_1, 0, sizeof(struct SerialHardwareDevice)); + +// static struct SerialCfgParam serial_cfg_1; +// memset(&serial_cfg_1, 0, sizeof(struct SerialCfgParam)); + +// static struct SerialDevParam serial_dev_param_1; +// memset(&serial_dev_param_1, 0, sizeof(struct SerialDevParam)); + +// serial_driver_1.drv_done = &drv_done; +// serial_driver_1.configure = &SerialDrvConfigure; +// serial_device_1.hwdev_done = &hwdev_done; + +// serial_cfg_1.data_cfg = data_cfg_init; + +// serial_cfg_1.hw_cfg.serial_register_base = UART1_BASE_ADDR; +// serial_cfg_1.hw_cfg.serial_irq_interrupt = IRQN_UART1_INTERRUPT; +// serial_driver_1.private_data = (void *)&serial_cfg_1; + +// serial_dev_param_1.serial_work_mode = SIGN_OPER_INT_RX; +// serial_device_1.haldev.private_data = (void *)&serial_dev_param_1; + +// _uart_init_new(UART_DEVICE_1); + +// ret = BoardSerialBusInit(&serial_bus_1, &serial_driver_1, SERIAL_BUS_NAME_1, SERIAL_DRV_NAME_1); +// if (EOK != ret) { +// KPrintf("hw_serial_init uart1 error ret %u\n", ret); +// return ERROR; +// } + +// ret = BoardSerialDevBend(&serial_device_1, (void *)&serial_cfg_1, SERIAL_BUS_NAME_1, SERIAL_1_DEVICE_NAME_0); +// if (EOK != ret) { +// KPrintf("hw_serial_init uart1 error ret %u\n", ret); +// return ERROR; +// } +// #endif + +// #ifdef BSP_USING_UART2 +// static struct SerialBus serial_bus_2; +// memset(&serial_bus_2, 0, sizeof(struct SerialBus)); + +// static struct SerialDriver serial_driver_2; +// memset(&serial_driver_2, 0, sizeof(struct SerialDriver)); + +// static struct SerialHardwareDevice serial_device_2; +// memset(&serial_device_2, 0, sizeof(struct SerialHardwareDevice)); + +// static struct SerialCfgParam serial_cfg_2; +// memset(&serial_cfg_2, 0, sizeof(struct SerialCfgParam)); + +// static struct SerialDevParam serial_dev_param_2; +// memset(&serial_dev_param_2, 0, sizeof(struct SerialDevParam)); + +// serial_driver_2.drv_done = &drv_done; +// serial_driver_2.configure = &SerialDrvConfigure; +// serial_device_2.hwdev_done = &hwdev_done; + +// serial_cfg_2.data_cfg = data_cfg_init; + +// serial_cfg_2.hw_cfg.serial_register_base = UART2_BASE_ADDR; +// serial_cfg_2.hw_cfg.serial_irq_interrupt = IRQN_UART2_INTERRUPT; +// serial_driver_2.private_data = (void *)&serial_cfg_2; + +// serial_dev_param_2.serial_work_mode = SIGN_OPER_INT_RX; +// serial_device_2.haldev.private_data = (void *)&serial_dev_param_2; + +// _uart_init_new(UART_DEVICE_2); + +// ret = BoardSerialBusInit(&serial_bus_2, &serial_driver_2, SERIAL_BUS_NAME_2, SERIAL_DRV_NAME_2); +// if (EOK != ret) { +// KPrintf("hw_serial_init uart2 error ret %u\n", ret); +// return ERROR; +// } + +// ret = BoardSerialDevBend(&serial_device_2, (void *)&serial_cfg_2, SERIAL_BUS_NAME_2, SERIAL_2_DEVICE_NAME_0); +// if (EOK != ret) { +// KPrintf("hw_serial_init uart2 error ret %u\n", ret); +// return ERROR; +// } +// #endif + +// #ifdef BSP_USING_UART3 +// static struct SerialBus serial_bus_3; +// memset(&serial_bus_3, 0, sizeof(struct SerialBus)); + +// static struct SerialDriver serial_driver_3; +// memset(&serial_driver_3, 0, sizeof(struct SerialDriver)); + +// static struct SerialHardwareDevice serial_device_3; +// memset(&serial_device_3, 0, sizeof(struct SerialHardwareDevice)); + +// static struct SerialCfgParam serial_cfg_3; +// memset(&serial_cfg_3, 0, sizeof(struct SerialCfgParam)); + +// static struct SerialDevParam serial_dev_param_3; +// memset(&serial_dev_param_3, 0, sizeof(struct SerialDevParam)); + +// serial_driver_3.drv_done = &drv_done; +// serial_driver_3.configure = &SerialDrvConfigure; +// serial_device_3.hwdev_done = &hwdev_done; + +// serial_cfg_3.data_cfg = data_cfg_init; + +// serial_cfg_3.hw_cfg.serial_register_base = UART3_BASE_ADDR; +// serial_cfg_3.hw_cfg.serial_irq_interrupt = IRQN_UART3_INTERRUPT; +// serial_driver_3.private_data = (void *)&serial_cfg_3; + +// serial_dev_param_3.serial_work_mode = SIGN_OPER_INT_RX; +// serial_device_3.haldev.private_data = (void *)&serial_dev_param_3; + +// _uart_init_new(UART_DEVICE_3); + +// ret = BoardSerialBusInit(&serial_bus_3, &serial_driver_3, SERIAL_BUS_NAME_3, SERIAL_DRV_NAME_3); +// if (EOK != ret) { +// KPrintf("hw_serial_init uart3 error ret %u\n", ret); +// return ERROR; +// } + +// ret = BoardSerialDevBend(&serial_device_3, (void *)&serial_cfg_3, SERIAL_BUS_NAME_3, SERIAL_3_DEVICE_NAME_0); +// if (EOK != ret) { +// KPrintf("hw_serial_init uart3 error ret %u\n", ret); +// return ERROR; +// } +// #endif + + return ret; +} diff --git a/board/k210-emulator/third_party_driver/uart/hardware_uart.c b/board/k210-emulator/third_party_driver/uart/hardware_uart.c new file mode 100644 index 00000000..be0103d3 --- /dev/null +++ b/board/k210-emulator/third_party_driver/uart/hardware_uart.c @@ -0,0 +1,424 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_uart.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include "plic.h" +#include "sysctl.h" +#include "hardware_uart.h" +#include "utils.h" +#include "atomic.h" + +#define __UART_BRATE_CONST 16 + +volatile UartT* const uart[3] = +{ + (volatile UartT*)UART1_BASE_ADDR, + (volatile UartT*)UART2_BASE_ADDR, + (volatile UartT*)UART3_BASE_ADDR +}; + +#define UART_INTERRUPT_SEND 0x02U +#define UART_INTERRUPT_RECEIVE 0x04U +#define UART_INTERRUPT_CHARACTER_TIMEOUT 0x0CU + +typedef struct UartInterruptInstance +{ + plic_irq_callback_t callback; + void *ctx; +} UartInterruptInstanceT; + +typedef struct UartInstance +{ + UartInterruptInstanceT UartReceiveInstance; + UartInterruptInstanceT UartSendInstance; + uint32_t UartNum; +} UartInstancePointer; + +UartInstancePointer GUartInstance[3]; + +typedef struct UartDmaInstance +{ + uint8_t *buffer; + size_t BufLen; + uint32_t *MallocBuffer; + UartInterruptModeT IntMode; + dmac_channel_number_t dmac_channel; + UartDeviceNumberT UartNum; + UartInterruptInstanceT UartIntInstance; +} UartDmaInstanceT; + +UartDmaInstanceT uart_send_dma_instance[3]; +UartDmaInstanceT UartRecvDmaInstance[3]; + +typedef struct UartInstanceDma +{ + UartDeviceNumberT UartNum; + UartInterruptModeT TransferMode; + dmac_channel_number_t dmac_channel; + plic_instance_t UartIntInstance; + spinlock_t lock; +} UartInstanceDmaT; + +static UartInstanceDmaT GUartSendInstanceDma[3]; +static UartInstanceDmaT GUartRecvInstanceDma[3]; + +volatile int GWriteCount = 0; + +static int UartIrqCallback(void *param) +{ + UartInstancePointer *uart_instance = (UartInstancePointer *)param; + uint32_t v_channel = uart_instance->UartNum; + uint8_t VIntStatus = uart[v_channel]->IIR & 0xF; + + if(VIntStatus == UART_INTERRUPT_SEND && GWriteCount != 0) + { + if(uart_instance->UartSendInstance.callback != NULL) + uart_instance->UartSendInstance.callback(uart_instance->UartSendInstance.ctx); + } + else if(VIntStatus == UART_INTERRUPT_RECEIVE || VIntStatus == UART_INTERRUPT_CHARACTER_TIMEOUT) + { + if(uart_instance->UartReceiveInstance.callback != NULL) + uart_instance->UartReceiveInstance.callback(uart_instance->UartReceiveInstance.ctx); + } + return 0; +} + +static int UartapbPutc(UartDeviceNumberT channel, char c) +{ + while (uart[channel]->LSR & (1u << 5)) + continue; + uart[channel]->THR = c; + return 0; +} + +int UartapbGetc(UartDeviceNumberT channel) +{ + while (!(uart[channel]->LSR & 1)) + continue; + + return (char)(uart[channel]->RBR & 0xff); +} + +static int UartDmaCallback(void *ctx) +{ + UartDmaInstanceT *VUartDmaInstance = (UartDmaInstanceT *)ctx; + dmac_channel_number_t dmac_channel = VUartDmaInstance->dmac_channel; + dmac_irq_unregister(dmac_channel); + + if(VUartDmaInstance->IntMode == UART_RECEIVE) + { + size_t VBufLen = VUartDmaInstance->BufLen; + uint8_t *VBuffer = VUartDmaInstance->buffer; + uint32_t *VRecvBuffer = VUartDmaInstance->MallocBuffer; + for(size_t i = 0; i < VBufLen; i++) + { + VBuffer[i] = VRecvBuffer[i]; + } + } + free(VUartDmaInstance->MallocBuffer); + if(VUartDmaInstance->UartIntInstance.callback) + VUartDmaInstance->UartIntInstance.callback(VUartDmaInstance->UartIntInstance.ctx); + return 0; +} + +int UartReceiveData(UartDeviceNumberT channel, char *buffer, size_t BufLen) +{ + size_t i = 0; + for(i = 0;i < BufLen; i++) + { + if(uart[channel]->LSR & 1) + buffer[i] = (char)(uart[channel]->RBR & 0xff); + else + break; + } + return i; +} + +void UartReceiveDataDma(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, uint8_t *buffer, size_t BufLen) +{ + uint32_t *VRecvBuf = malloc(BufLen * sizeof(uint32_t)); + configASSERT(VRecvBuf!=NULL); + + sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_RX_REQ + uart_channel * 2); + dmac_set_single_mode(dmac_channel, (void *)(&uart[uart_channel]->RBR), VRecvBuf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, BufLen); + dmac_wait_done(dmac_channel); + for(uint32_t i = 0; i < BufLen; i++) + { + buffer[i] = (uint8_t)(VRecvBuf[i] & 0xff); + } + free(VRecvBuf); +} + +void UartReceiveDataDmaIrq(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, + uint8_t *buffer, size_t BufLen, plic_irq_callback_t uart_callback, + void *ctx, uint32_t priority) +{ + uint32_t *VRecvBuf = malloc(BufLen * sizeof(uint32_t)); + configASSERT(VRecvBuf!=NULL); + + UartRecvDmaInstance[uart_channel].dmac_channel = dmac_channel; + UartRecvDmaInstance[uart_channel].UartNum = uart_channel; + UartRecvDmaInstance[uart_channel].MallocBuffer = VRecvBuf; + UartRecvDmaInstance[uart_channel].buffer = buffer; + UartRecvDmaInstance[uart_channel].BufLen = BufLen; + UartRecvDmaInstance[uart_channel].IntMode = UART_RECEIVE; + UartRecvDmaInstance[uart_channel].UartIntInstance.callback = uart_callback; + UartRecvDmaInstance[uart_channel].UartIntInstance.ctx = ctx; + + dmac_irq_register(dmac_channel, UartDmaCallback, &UartRecvDmaInstance[uart_channel], priority); + sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_RX_REQ + uart_channel * 2); + dmac_set_single_mode(dmac_channel, (void *)(&uart[uart_channel]->RBR), VRecvBuf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, BufLen); +} + +int UartSendData(UartDeviceNumberT channel, const char *buffer, size_t BufLen) +{ + GWriteCount = 0; + while (GWriteCount < BufLen) + { + UartapbPutc(channel, *buffer++); + GWriteCount++; + } + return GWriteCount; +} + +void UartSendDataDma(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, const uint8_t *buffer, size_t BufLen) +{ + uint32_t *VSendBuf = malloc(BufLen * sizeof(uint32_t)); + configASSERT(VSendBuf!=NULL); + for(uint32_t i = 0; i < BufLen; i++) + VSendBuf[i] = buffer[i]; + sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_TX_REQ + uart_channel * 2); + dmac_set_single_mode(dmac_channel, VSendBuf, (void *)(&uart[uart_channel]->THR), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, BufLen); + dmac_wait_done(dmac_channel); + free((void *)VSendBuf); +} + +void UartSendDataDmaIrq(UartDeviceNumberT uart_channel, dmac_channel_number_t dmac_channel, + const uint8_t *buffer, size_t BufLen, plic_irq_callback_t uart_callback, + void *ctx, uint32_t priority) +{ + uint32_t *VSendBuf = malloc(BufLen * sizeof(uint32_t)); + configASSERT(VSendBuf!=NULL); + + uart_send_dma_instance[uart_channel] = (UartDmaInstanceT) { + .dmac_channel = dmac_channel, + .UartNum = uart_channel, + .MallocBuffer = VSendBuf, + .buffer = (uint8_t *)buffer, + .BufLen = BufLen, + .IntMode = UART_SEND, + .UartIntInstance.callback = uart_callback, + .UartIntInstance.ctx = ctx, + }; + + for(uint32_t i = 0; i < BufLen; i++) + VSendBuf[i] = buffer[i]; + dmac_irq_register(dmac_channel, UartDmaCallback, &uart_send_dma_instance[uart_channel], priority); + sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_TX_REQ + uart_channel * 2); + dmac_set_single_mode(dmac_channel, VSendBuf, (void *)(&uart[uart_channel]->THR), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, BufLen); + +} + +void uart_configure(UartDeviceNumberT channel, uint32_t BaudRate, UartBitwidthPointer DataWidth, UartStopbitT stopbit, UartParityT parity) +{ + configASSERT(DataWidth >= 5 && DataWidth <= 8); + if (DataWidth == 5) + { + configASSERT(stopbit != UART_STOP_2); + } + else + { + configASSERT(stopbit != UART_STOP_1_5); + } + + uint32_t stopbit_val = stopbit == UART_STOP_1 ? 0 : 1; + uint32_t ParityVal; + switch (parity) + { + case UART_PARITY_NONE: + ParityVal = 0; + break; + case UART_PARITY_ODD: + ParityVal = 1; + break; + case UART_PARITY_EVEN: + ParityVal = 3; + break; + default: + configASSERT(!"Invalid parity"); + break; + } + + uint32_t freq = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + uint32_t divisor = freq / BaudRate; + uint8_t dlh = divisor >> 12; + uint8_t dll = (divisor - (dlh << 12)) / __UART_BRATE_CONST; + uint8_t dlf = divisor - (dlh << 12) - dll * __UART_BRATE_CONST; + + /* Set UART registers */ + uart[channel]->TCR &= ~(1u); + uart[channel]->TCR &= ~(1u << 3); + uart[channel]->TCR &= ~(1u << 4); + uart[channel]->TCR |= (1u << 2); + uart[channel]->TCR &= ~(1u << 1); + uart[channel]->DE_EN &= ~(1u); + + uart[channel]->LCR |= 1u << 7; + uart[channel]->DLH = dlh; + uart[channel]->DLL = dll; + uart[channel]->DLF = dlf; + uart[channel]->LCR = 0; + uart[channel]->LCR = (DataWidth - 5) | (stopbit_val << 2) | (ParityVal << 3); + uart[channel]->LCR &= ~(1u << 7); + uart[channel]->MCR &= ~3; + uart[channel]->IER |= 0x80; /* THRE */ + uart[channel]->FCR = UART_RECEIVE_FIFO_1 << 6 | UART_SEND_FIFO_8 << 4 | 0x1 << 3 | 0x1; +} + +void __attribute__((weak, alias("uart_configure"))) +uart_config(UartDeviceNumberT channel, uint32_t BaudRate, UartBitwidthPointer DataWidth, UartStopbitT stopbit, UartParityT parity); + +void UartInit(UartDeviceNumberT channel) +{ + sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel); +} + +void UartSetSendTrigger(UartDeviceNumberT channel, uart_send_trigger_t trigger) +{ + uart[channel]->STET = trigger; +} + +void uart_set_receive_trigger(UartDeviceNumberT channel, uart_receive_trigger_t trigger) +{ + uart[channel]->SRT = trigger; +} + +void uart_irq_register(UartDeviceNumberT channel, UartInterruptModeT interrupt_mode, plic_irq_callback_t uart_callback, void *ctx, uint32_t priority) +{ + if(interrupt_mode == UART_SEND) + { + uart[channel]->IER |= 0x2; + GUartInstance[channel].UartSendInstance.callback = uart_callback; + GUartInstance[channel].UartSendInstance.ctx = ctx; + } + else if(interrupt_mode == UART_RECEIVE) + { + uart[channel]->IER |= 0x1; + GUartInstance[channel].UartReceiveInstance.callback = uart_callback; + GUartInstance[channel].UartReceiveInstance.ctx = ctx; + } + GUartInstance[channel].UartNum = channel; + plic_set_priority(IRQN_UART1_INTERRUPT + channel, priority); + plic_irq_register(IRQN_UART1_INTERRUPT + channel, UartIrqCallback, &GUartInstance[channel]); + plic_irq_enable(IRQN_UART1_INTERRUPT + channel); +} + +void uart_irq_unregister(UartDeviceNumberT channel, UartInterruptModeT interrupt_mode) +{ + if(interrupt_mode == UART_SEND) + { + uart[channel]->IER &= ~(0x2); + GUartInstance[channel].UartSendInstance.callback = NULL; + GUartInstance[channel].UartSendInstance.ctx = NULL; + } + else if(interrupt_mode == UART_RECEIVE) + { + uart[channel]->IER &= ~(0x1); + GUartInstance[channel].UartReceiveInstance.callback = NULL; + GUartInstance[channel].UartReceiveInstance.ctx = NULL; + } + if(uart[channel]->IER == 0) + { + plic_irq_unregister(IRQN_UART1_INTERRUPT + channel); + } +} + +int uart_dma_irq(void *ctx) +{ + UartInstanceDmaT *v_instance = (UartInstanceDmaT *)ctx; + dmac_irq_unregister(v_instance->dmac_channel); + if(v_instance->TransferMode == UART_SEND) + { + while(!(uart[v_instance->UartNum]->LSR & (1u << 6))); + } + spinlock_unlock(&v_instance->lock); + if(v_instance->UartIntInstance.callback) + { + v_instance->UartIntInstance.callback(v_instance->UartIntInstance.ctx); + } + return 0; +} + +void uart_handle_data_dma(UartDeviceNumberT uart_channel ,uart_data_t data, plic_interrupt_t *cb) +{ + configASSERT(uart_channel < UART_DEVICE_MAX); + if(data.TransferMode == UART_SEND) + { + configASSERT(data.tx_buf && data.tx_len && data.tx_channel < DMAC_CHANNEL_MAX); + spinlock_lock(&GUartSendInstanceDma[uart_channel].lock); + if(cb) + { + GUartSendInstanceDma[uart_channel].UartIntInstance.callback = cb->callback; + GUartSendInstanceDma[uart_channel].UartIntInstance.ctx = cb->ctx; + GUartSendInstanceDma[uart_channel].dmac_channel = data.tx_channel; + GUartSendInstanceDma[uart_channel].TransferMode = UART_SEND; + dmac_irq_register(data.tx_channel, uart_dma_irq, &GUartSendInstanceDma[uart_channel], cb->priority); + } + sysctl_dma_select((sysctl_dma_channel_t)data.tx_channel, SYSCTL_DMA_SELECT_UART1_TX_REQ + uart_channel * 2); + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&uart[uart_channel]->THR), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.tx_len); + if(!cb) + { + dmac_wait_done(data.tx_channel); + while(!(uart[uart_channel]->LSR & (1u << 6))); + spinlock_unlock(&GUartSendInstanceDma[uart_channel].lock); + } + } + else + { + configASSERT(data.rx_buf && data.rx_len && data.rx_channel < DMAC_CHANNEL_MAX); + spinlock_lock(&GUartRecvInstanceDma[uart_channel].lock); + if(cb) + { + GUartRecvInstanceDma[uart_channel].UartIntInstance.callback = cb->callback; + GUartRecvInstanceDma[uart_channel].UartIntInstance.ctx = cb->ctx; + GUartRecvInstanceDma[uart_channel].dmac_channel = data.rx_channel; + GUartRecvInstanceDma[uart_channel].TransferMode = UART_RECEIVE; + dmac_irq_register(data.rx_channel, uart_dma_irq, &GUartRecvInstanceDma[uart_channel], cb->priority); + } + sysctl_dma_select((sysctl_dma_channel_t)data.rx_channel, SYSCTL_DMA_SELECT_UART1_RX_REQ + uart_channel * 2); + dmac_set_single_mode(data.rx_channel, (void *)(&uart[uart_channel]->RBR), data.rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + if(!cb) + { + dmac_wait_done(data.rx_channel); + spinlock_unlock(&GUartRecvInstanceDma[uart_channel].lock); + } + } +} diff --git a/board/k210-emulator/third_party_driver/uart/hardware_uarths.c b/board/k210-emulator/third_party_driver/uart/hardware_uarths.c new file mode 100644 index 00000000..5d3786f6 --- /dev/null +++ b/board/k210-emulator/third_party_driver/uart/hardware_uarths.c @@ -0,0 +1,184 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 hardware_uarths.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include "hardware_uarths.h" +#include "sysctl.h" +#include "encoding.h" + +volatile UarthsT *const uarths = (volatile UarthsT *)UARTHS_BASE_ADDR; + +typedef struct _uarths_instance +{ + plic_irq_callback_t callback; + void *ctx; + uarths_interrupt_mode_t uarths_interrupt_mode; +} uarths_instance_t; + +uarths_instance_t g_uarths_instance; + +uarths_interrupt_mode_t uarths_get_interrupt_mode(void) +{ + uint32_t v_rx_interrupt = uarths->ip.rxwm; + uint32_t v_tx_interrupt = uarths->ip.txwm; + return (v_rx_interrupt << 1) | v_tx_interrupt; +} + +int uarths_irq_callback(void *ctx) +{ + uarths_instance_t *uart_context = (uarths_instance_t *)ctx; + + if(uart_context->callback) + uart_context->callback(uart_context->ctx); + return 0; +} + +void uarths_set_interrupt_cnt(uarths_interrupt_mode_t interrupt_mode, uint8_t cnt) +{ + switch(interrupt_mode) + { + case UARTHS_SEND: + uarths->txctrl.txcnt = cnt; + break; + case UARTHS_RECEIVE: + uarths->rxctrl.rxcnt = cnt; + break; + case UARTHS_SEND_RECEIVE: + default: + uarths->txctrl.txcnt = cnt; + uarths->rxctrl.rxcnt = cnt; + break; + } +} + +void uarths_set_irq(uarths_interrupt_mode_t interrupt_mode, plic_irq_callback_t uarths_callback, void *ctx, uint32_t priority) +{ + g_uarths_instance.callback = uarths_callback; + g_uarths_instance.ctx = ctx; + + switch(interrupt_mode) + { + case UARTHS_SEND: + uarths->ie.txwm = 1; + uarths->ie.rxwm = 0; + break; + case UARTHS_RECEIVE: + uarths->ie.txwm = 0; + uarths->ie.rxwm = 1; + break; + default: + uarths->ie.txwm = 1; + uarths->ie.rxwm = 1; + break; + } + g_uarths_instance.uarths_interrupt_mode = interrupt_mode; + + plic_set_priority(IRQN_UARTHS_INTERRUPT, priority); + plic_irq_register(IRQN_UARTHS_INTERRUPT, uarths_irq_callback, &g_uarths_instance); + plic_irq_enable(IRQN_UARTHS_INTERRUPT); +} + +static inline int uarths_putc(char c) +{ + while (uarths->txdata.full) + continue; + uarths->txdata.data = (uint8_t)c; + + return 0; +} + +size_t uarths_receive_data(uint8_t *buf, size_t BufLen) +{ + size_t i; + for(i = 0; i < BufLen; i++) + { + uarths_rxdata_t recv = uarths->rxdata; + if(recv.empty) + break; + else + buf[i] = (recv.data & 0xFF); + } + return i; +} + +size_t uarths_send_data(const uint8_t *buf, size_t BufLen) +{ + size_t write = 0; + while (write < BufLen) + { + uarths_putc(*buf++); + write++; + } + return write; +} + +int uarths_getc(void) +{ + /* while not empty */ + uarths_rxdata_t recv = uarths->rxdata; + + if (recv.empty) + return EOF; + else + return recv.data; +} + +int uarths_putchar(char c) +{ + return uarths_putc(c); +} + +int uarths_puts(const char *s) +{ + while (*s) + if (uarths_putc(*s++) != 0) + return -1; + return 0; +} + +void uarths_init(void) +{ + uint32_t freq = SysctlClockGetFreq(SYSCTL_CLOCK_CPU); + uint16_t div = freq / 115200 - 1; + + /* Set UART registers */ + uarths->div.div = div; + uarths->txctrl.txen = 1; + uarths->rxctrl.rxen = 1; + uarths->txctrl.txcnt = 0; + uarths->rxctrl.rxcnt = 0; + uarths->ip.txwm = 1; + uarths->ip.rxwm = 1; + uarths->ie.txwm = 0; + uarths->ie.rxwm = 1; +} + +void uarths_config(uint32_t BaudRate, uarths_stopbit_t stopbit) +{ + uint32_t freq = SysctlClockGetFreq(SYSCTL_CLOCK_CPU); + uint16_t div = freq / BaudRate - 1; + uarths->div.div = div; + uarths->txctrl.nstop = stopbit; +} diff --git a/board/k210-emulator/third_party_driver/watchdog/Kconfig b/board/k210-emulator/third_party_driver/watchdog/Kconfig new file mode 100644 index 00000000..e801fa0e --- /dev/null +++ b/board/k210-emulator/third_party_driver/watchdog/Kconfig @@ -0,0 +1,34 @@ +menuconfig BSP_USING_WDT0 +bool "Using watchdog 0 " +default n +if BSP_USING_WDT0 +config WDT_BUS_NAME_0 + string "watchdog bus 0 name" + default "wdt0" + +config WDT_DRIVER_NAME_0 + string "watchdog driver 0 name" + default "wdt0_drv" + +config WDT_0_DEVICE_NAME_0 + string "watchdog device 0 name" + default "wdt0_dev0" +endif + +menuconfig BSP_USING_WDT1 +bool "Using watchdog 1 " +default n +if BSP_USING_WDT1 +config WDT_BUS_NAME_1 + string "watchdog bus 1 name" + default "wdt1" + +config WDT_DRIVER_NAME_1 + string "watchdog driver 1 name" + default "wdt1_drv" + +config WDT_1_DEVICE_NAME_1 + string "watchdog device 1 name" + default "wdt1_dev1" +endif + diff --git a/board/k210-emulator/third_party_driver/watchdog/Makefile b/board/k210-emulator/third_party_driver/watchdog/Makefile new file mode 100644 index 00000000..9b82583d --- /dev/null +++ b/board/k210-emulator/third_party_driver/watchdog/Makefile @@ -0,0 +1,4 @@ +SRC_FILES := wdt.c connect_wdt.c + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/board/k210-emulator/third_party_driver/watchdog/connect_wdt.c b/board/k210-emulator/third_party_driver/watchdog/connect_wdt.c new file mode 100644 index 00000000..1ebcd6ba --- /dev/null +++ b/board/k210-emulator/third_party_driver/watchdog/connect_wdt.c @@ -0,0 +1,172 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_wdt.c +* @brief support kd233-board watchdog function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include "wdt.h" +#include "connect_wdt.h" + +static uint32 WdtOpen(void *dev) +{ + NULL_PARAM_CHECK(dev); + + wdt_device_number_t id; + struct WdtHardwareDevice *wdt = (struct WdtHardwareDevice *)dev; + id = *(wdt_device_number_t *)wdt->private_data; + + wdt_init(id, 4095, NONE, NONE); + return EOK; +} + +static uint32 WdtConfigure(void *drv, struct BusConfigureInfo *args) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(args); + + struct WdtDriver *wdt = (struct WdtDriver *)drv; + wdt_device_number_t id = *(wdt_device_number_t *)wdt->private_data; + + switch (args->configure_cmd) + { + case OPER_WDT_SET_TIMEOUT: + if (wdt_init(id, (uint64_t)*(int *)args->private_data, NONE, NONE) == 0) + { + return ERROR; + } + break; + case OPER_WDT_KEEPALIVE: + wdt_feed(id); + break; + default: + return ERROR; + } + return EOK; +} + +static const struct WdtDevDone dev_done = +{ + WdtOpen, + NONE, + NONE, + NONE, +}; + +int HwWdtInit(void) +{ + wdt_device_number_t id; + + x_err_t ret = EOK; + +#ifdef BSP_USING_WDT0 + { + static struct WdtBus wdt0; + + ret = WdtBusInit(&wdt0, WDT_BUS_NAME_0); + if(ret != EOK) + { + KPrintf("Watchdog bus init error %d\n", ret); + return ERROR; + } + + static struct WdtDriver drv0; + drv0.configure = WdtConfigure; + id = WDT_DEVICE_0; + drv0.private_data = &id; + + ret = WdtDriverInit(&drv0, WDT_DRIVER_NAME_0); + if(ret != EOK) + { + KPrintf("Watchdog driver init error %d\n", ret); + return ERROR; + } + ret = WdtDriverAttachToBus(WDT_DRIVER_NAME_0, WDT_BUS_NAME_0); + if(ret != EOK) + { + KPrintf("Watchdog driver attach error %d\n", ret); + return ERROR; + } + + static struct WdtHardwareDevice dev0; + dev0.dev_done = &dev_done; + dev0.private_data = &id; + + ret = WdtDeviceRegister(&dev0, WDT_0_DEVICE_NAME_0); + if(ret != EOK) + { + KPrintf("Watchdog device register error %d\n", ret); + return ERROR; + } + ret = WdtDeviceAttachToBus(WDT_0_DEVICE_NAME_0, WDT_BUS_NAME_0); + if(ret != EOK) + { + KPrintf("Watchdog device register error %d\n", ret); + return ERROR; + } + } +#endif + +#ifdef BSP_USING_WDT1 + { + static struct WdtBus wdt1; + + ret = WdtBusInit(&wdt1, WDT_BUS_NAME_1); + if(ret != EOK) + { + KPrintf("Watchdog bus init error %d\n", ret); + return ERROR; + } + + static struct WdtDriver drv1; + drv1.configure = WdtConfigure; + id = WDT_DEVICE_1; + drv1.private_data = &id; + + ret = WdtDriverInit(&drv1, WDT_DRIVER_NAME_1); + if(ret != EOK) + { + KPrintf("Watchdog driver init error %d\n", ret); + return ERROR; + } + ret = WdtDriverAttachToBus(WDT_DRIVER_NAME_1, WDT_BUS_NAME_1); + if(ret != EOK) + { + KPrintf("Watchdog driver attach error %d\n", ret); + return ERROR; + } + + static struct WdtHardwareDevice dev1; + dev1.dev_done = &dev_done; + dev1.private_data = &id; + + ret = WdtDeviceRegister(&dev1, WDT_1_DEVICE_NAME_1); + if(ret != EOK) + { + KPrintf("Watchdog device register error %d\n", ret); + return ERROR; + } + ret = WdtDeviceAttachToBus(WDT_1_DEVICE_NAME_1, WDT_BUS_NAME_1); + if(ret != EOK) + { + KPrintf("Watchdog device register error %d\n", ret); + return ERROR; + } + } +#endif + + return ret; +} diff --git a/board/k210-emulator/third_party_driver/watchdog/wdt.c b/board/k210-emulator/third_party_driver/watchdog/wdt.c new file mode 100644 index 00000000..b3909354 --- /dev/null +++ b/board/k210-emulator/third_party_driver/watchdog/wdt.c @@ -0,0 +1,125 @@ +/* Copyright 2018 Canaan Inc. + * + * 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 + * + * http://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 wdt.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include "wdt.h" +#include "platform.h" +#include "stddef.h" +#include "utils.h" +#include "sysctl.h" +#include "plic.h" +#include "math.h" + +volatile wdt_t *const wdt[2] = +{ + (volatile wdt_t *)WDT0_BASE_ADDR, + (volatile wdt_t *)WDT1_BASE_ADDR +}; + +static void wdt_enable(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; + wdt[id]->cr |= WDT_CR_ENABLE; +} + +static void wdt_disable(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; + wdt[id]->cr &= (~WDT_CR_ENABLE); +} + +static void wdt_set_timeout(wdt_device_number_t id, uint8_t timeout) +{ + wdt[id]->torr = WDT_TORR_TOP(timeout); +} + +static void wdt_response_mode(wdt_device_number_t id, uint8_t mode) +{ + wdt[id]->cr &= (~WDT_CR_RMOD_MASK); + wdt[id]->cr |= mode; +} + +static uint64_t wdt_get_pclk(wdt_device_number_t id) +{ + return id ? SysctlClockGetFreq(SYSCTL_CLOCK_WDT1) : SysctlClockGetFreq(SYSCTL_CLOCK_WDT0); +} + +static uint8_t wdt_get_top(wdt_device_number_t id, uint64_t timeout_ms) +{ + uint64_t wdt_clk = wdt_get_pclk(id); + uint64_t ret = (timeout_ms * wdt_clk / 1000) >> 16; + if (ret) + ret = (uint32_t)log2(ret); + if (ret > 0xf) + ret = 0xf; + return (uint8_t)ret; +} + +void wdt_feed(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; +} + +void wdt_clear_interrupt(wdt_device_number_t id) +{ + wdt[id]->eoi = wdt[id]->eoi; +} + +void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq) +{ + sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0); + sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0); + sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0); + + plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1); + plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT); + plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, NULL); + + wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT); + uint8_t m_top = wdt_get_top(id, time_out_ms); + wdt_set_timeout(id, m_top); + wdt_enable(id); +} + +uint32_t wdt_init(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq, void *ctx) +{ + sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0); + sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0); + sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0); + + plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1); + plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT); + plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, ctx); + + wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT); + uint8_t m_top = wdt_get_top(id, time_out_ms); + wdt_set_timeout(id, m_top); + wdt_enable(id); + return (1UL << (m_top + 16 + 1)) * 1000UL / wdt_get_pclk(id); +} + +void wdt_stop(wdt_device_number_t id) +{ + wdt_disable(id); +} + diff --git a/kernel/thread/init.c b/kernel/thread/init.c index 6369e352..e8aa8e4b 100644 --- a/kernel/thread/init.c +++ b/kernel/thread/init.c @@ -92,7 +92,6 @@ struct InitSequenceDesc components_init[] = #ifdef FS_CH376 { "ch376", Ch376fsInit }, #endif - { "libc_system", LibcSystemInit }, #ifdef RTC_SYNC_USING_NTP { "rtc_ntp_sync",RtcNtpSyncInit}, #endif diff --git a/path_kernel.mk b/path_kernel.mk index f027663c..14729e69 100644 --- a/path_kernel.mk +++ b/path_kernel.mk @@ -83,6 +83,19 @@ KERNELPATHS :=-I$(BSP_ROOT) \ -I$(KERNEL_ROOT)/include # endif +ifeq ($(BSP_ROOT),$(KERNEL_ROOT)/board/k210-emulator) +KERNELPATHS :=-I$(BSP_ROOT) \ + -I$(BSP_ROOT)/third_party_driver \ + -I$(BSP_ROOT)/include \ + -I$(BSP_ROOT)/third_party_driver/include \ + -I$(BSP_ROOT)/third_party_driver/spi/third_party_spi_lora/inc \ + -I$(BSP_ROOT)/third_party_driver/spi/third_party_spi_lora/src/radio \ + -I$(BSP_ROOT)/third_party_driver/camera \ + -I$(BSP_ROOT)/third_party_driver/drivers \ + -I$(BSP_ROOT)/third_party_driver/lcd \ + -I$(KERNEL_ROOT)/include # +endif + ifeq ($(BSP_ROOT),$(KERNEL_ROOT)/board/aiit-riscv64-board) KERNELPATHS :=-I$(BSP_ROOT) \ -I$(BSP_ROOT)/third_party_driver \